# Customers

> The shop’s customers and what is kept about them.

Source: https://storeware.ai/docs/api-reference/rest/customers

## List customers

`GET /api/v1/stores/{storeId}/customers`

A page of customers, newest first unless `sort` says otherwise, each with what they have bought. Archived customers are left out unless `archived` asks for them. Each narrowing takes some away, and a value that cannot be read is ignored. `meta.breakdown` counts every customer not archived; send `breakdown=0` to leave it out.

Needs `customers:read`.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `storeId` | path | string | The shop. |
| `search` | query | string | Words in the email, first name or last name. |
| `sort` | query | string | One of `created_desc`, `created_asc`, `name_asc`, `name_desc`. |
| `accountType` | query | string | One of `guest`, `registered`, `business`. |
| `acceptsMarketing` | query | string | `1` for those who agreed to be emailed, `0` for those who did not. One of `0`, `1`. |
| `archived` | query | string | `1` lists archived customers among the rest, `only` lists the archive alone. One of `1`, `only`. |
| `tags` | query | string | Comma separated: carrying any of these, up to ten. |
| `orders` | query | string | `none` for those who never ordered, or a number: at least that many orders. |
| `spent` | query | integer | Have spent at least this, in minor units, after refunds. At least 1. |
| `recent` | query | integer | Have ordered within this many days. At least 1. |
| `quiet` | query | integer | Have ordered, and not within this many days. At least 1. |
| `country` | query | string | Two letters: they live there or have had an order sent there. |
| `bought` | query | string (uuid) | Have bought this product. |
| `breakdown` | query | string | `0` leaves `meta.breakdown` out. One of `0`. |
| `limit` | query | integer | How many to return, up to 250. Fifty when not given. From 1 to 250. |
| `offset` | query | integer | How many to skip, for the next page. At least 0. |

**Answers** `200`

| Field | Type | Description |
| --- | --- | --- |
| `data` | array of [CustomerSummary](https://storeware.ai/docs/api-reference/rest/objects#customersummary) |  |
| `meta` | object |  |
| `meta.total` | integer | How many match, across every page. |
| `meta.breakdown` | object | Every customer not archived, whatever the page asks. Left out with `breakdown=0`. |
| `meta.breakdown.total` | integer |  |
| `meta.breakdown.registered` | integer |  |
| `meta.breakdown.withOrders` | integer | Have at least one order not cancelled. |
| `meta.breakdown.acceptsMarketing` | integer |  |

```bash
curl "https://api.storeware.ai/api/v1/stores/$STORE_ID/customers" \
  -H "Authorization: Bearer $TOKEN"
```

## Create a customer

`POST /api/v1/stores/{storeId}/customers`

Adds somebody who has not been through the checkout, as a guest. Marketing consent cannot be set here: a customer added this way starts without it. An email another customer of the shop holds, an archived one included, is a 409. Send an `Idempotency-Key` header to make a retry safe.

Needs `customers:write`.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `storeId` | path | string | The shop. |

**Body**

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `email` | string (email) | Yes | Up to 254 characters. |
| `firstName` | string or null | No | Up to 120 characters. |
| `lastName` | string or null | No | Up to 120 characters. |
| `phone` | string or null | No | Up to 40 characters. |
| `defaultAddress` | object or null | No |  |
| `defaultAddress.name` | string or null | No | Up to 200 characters. |
| `defaultAddress.line_one` | string | Yes | 1 to 200 characters. |
| `defaultAddress.line_two` | string or null | No | Up to 200 characters. |
| `defaultAddress.city` | string | Yes | 1 to 120 characters. |
| `defaultAddress.state` | string or null | No | Up to 120 characters. |
| `defaultAddress.country` | string | Yes | Matches `^[A-Z]{2}$`. |
| `defaultAddress.postal_code` | string | Yes | 1 to 32 characters. |
| `tags` | array of string | No | Up to 100 items. |
| `taxExempt` | boolean | No |  |
| `taxExemptionReference` | string or null | No | Up to 200 characters. |
| `acceptsMarketing` | any | No |  |

**Answers** `201`

| Field | Type | Description |
| --- | --- | --- |
| `data` | [Customer](https://storeware.ai/docs/api-reference/rest/objects#customer) |  |

```bash
curl -X POST "https://api.storeware.ai/api/v1/stores/$STORE_ID/customers" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d @body.json
```

## List the tags and countries customers have

`GET /api/v1/stores/{storeId}/customers/facets`

The tags the shop’s customers carry and the countries they live in or have had orders sent to, the commonest first, counted over customers not archived. For offering the values `tags` and `country` can narrow `listCustomers` by.

Needs `customers:read`.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `storeId` | path | string | The shop. |

**Answers** `200`

| Field | Type | Description |
| --- | --- | --- |
| `data` | object |  |
| `data.tags` | array of string | Up to 100. |
| `data.countries` | array of string | Two letter codes, up to 250. |

```bash
curl "https://api.storeware.ai/api/v1/stores/$STORE_ID/customers/facets" \
  -H "Authorization: Bearer $TOKEN"
```

## Get a customer

`GET /api/v1/stores/{storeId}/customers/{customerId}`

The customer, with their 100 most recent orders in `meta.orders`.

Needs `customers:read`.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `storeId` | path | string | The shop. |
| `customerId` | path | string | The customer. |

**Answers** `200`

| Field | Type | Description |
| --- | --- | --- |
| `data` | [CustomerSummary](https://storeware.ai/docs/api-reference/rest/objects#customersummary) |  |
| `meta` | object |  |
| `meta.orders` | array of object | Newest first, up to 100. |
| `meta.orders[].id` | string (uuid) |  |
| `meta.orders[].storeId` | string (uuid) |  |
| `meta.orders[].sessionId` | string (uuid) or null |  |
| `meta.orders[].customerId` | string (uuid) or null |  |
| `meta.orders[].buyerProven` | boolean |  |
| `meta.orders[].orderNumber` | string |  |
| `meta.orders[].customerNote` | string or null |  |
| `meta.orders[].status` | string | One of `created`, `confirmed`, `manual_review`, `processing`, `shipped`, `delivered`, `canceled`. |
| `meta.orders[].currency` | string |  |
| `meta.orders[].locale` | string or null |  |
| `meta.orders[].buyerEmail` | string |  |
| `meta.orders[].buyerFirstName` | string or null |  |
| `meta.orders[].buyerLastName` | string or null |  |
| `meta.orders[].buyerPhone` | string or null |  |
| `meta.orders[].shippingAddress` | any or null |  |
| `meta.orders[].billingAddress` | any or null |  |
| `meta.orders[].fulfillmentOption` | any or null |  |
| `meta.orders[].subtotalAmount` | number |  |
| `meta.orders[].discountAmount` | number |  |
| `meta.orders[].fulfillmentAmount` | number |  |
| `meta.orders[].taxAmount` | number |  |
| `meta.orders[].fulfillmentTaxAmount` | number |  |
| `meta.orders[].fulfillmentDiscountAmount` | number |  |
| `meta.orders[].companyId` | string (uuid) or null |  |
| `meta.orders[].priceListId` | string (uuid) or null |  |
| `meta.orders[].paymentTermsNetDays` | number or null |  |
| `meta.orders[].dueAt` | string (date-time) or null |  |
| `meta.orders[].purchaseOrderNumber` | string or null |  |
| `meta.orders[].totalAmount` | number |  |
| `meta.orders[].refundedAmount` | number |  |
| `meta.orders[].changeAmount` | number |  |
| `meta.orders[].creditAppliedAmount` | number |  |
| `meta.orders[].taxCalculationId` | string or null |  |
| `meta.orders[].taxTransactionId` | string or null |  |
| `meta.orders[].discountId` | string (uuid) or null |  |
| `meta.orders[].discountCode` | string or null |  |
| `meta.orders[].tags` | array of string |  |
| `meta.orders[].heldAt` | string (date-time) or null |  |
| `meta.orders[].heldBy` | string or null |  |
| `meta.orders[].holdReason` | string or null |  |
| `meta.orders[].origin` | string | One of `storefront`, `agent`, `admin`, `plugin`, `imported`, `subscription`. |
| `meta.orders[].agentId` | string or null |  |
| `meta.orders[].conversationId` | string (uuid) or null |  |
| `meta.orders[].referralId` | string (uuid) or null |  |
| `meta.orders[].adLinkId` | string (uuid) or null |  |
| `meta.orders[].placedAt` | string (date-time) |  |
| `meta.orders[].canceledAt` | string (date-time) or null |  |
| `meta.orders[].subscriptionId` | string (uuid) or null |  |
| `meta.orders[].createdAt` | string (date-time) |  |
| `meta.orders[].updatedAt` | string (date-time) |  |

```bash
curl "https://api.storeware.ai/api/v1/stores/$STORE_ID/customers/$CUSTOMER_ID" \
  -H "Authorization: Bearer $TOKEN"
```

## Update a customer

`PATCH /api/v1/stores/{storeId}/customers/{customerId}`

Changes only the fields sent; a null empties one, and an address is replaced whole. Marketing consent cannot be set here. Changing the email to one another customer holds is a 409, and any new email counts as unverified until the customer signs in with it. `note` is the merchant’s own and is never shown to the customer. Send an `Idempotency-Key` header to make a retry safe.

Needs `customers:write`.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `storeId` | path | string | The shop. |
| `customerId` | path | string | The customer. |

**Body**

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `email` | string (email) | No | Up to 254 characters. |
| `firstName` | string or null | No | Up to 120 characters. |
| `lastName` | string or null | No | Up to 120 characters. |
| `phone` | string or null | No | Up to 40 characters. |
| `defaultAddress` | object or null | No |  |
| `defaultAddress.name` | string or null | No | Up to 200 characters. |
| `defaultAddress.line_one` | string | Yes | 1 to 200 characters. |
| `defaultAddress.line_two` | string or null | No | Up to 200 characters. |
| `defaultAddress.city` | string | Yes | 1 to 120 characters. |
| `defaultAddress.state` | string or null | No | Up to 120 characters. |
| `defaultAddress.country` | string | Yes | Matches `^[A-Z]{2}$`. |
| `defaultAddress.postal_code` | string | Yes | 1 to 32 characters. |
| `tags` | array of string | No | Up to 100 items. |
| `taxExempt` | boolean | No |  |
| `taxExemptionReference` | string or null | No | Up to 200 characters. |
| `acceptsMarketing` | any | No |  |
| `note` | string or null | No | Up to 5,000 characters. |

**Answers** `200`

| Field | Type | Description |
| --- | --- | --- |
| `data` | [Customer](https://storeware.ai/docs/api-reference/rest/objects#customer) |  |

```bash
curl -X PATCH "https://api.storeware.ai/api/v1/stores/$STORE_ID/customers/$CUSTOMER_ID" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d @body.json
```

## List a customer’s saved addresses

`GET /api/v1/stores/{storeId}/customers/{customerId}/addresses`

The addresses a customer has besides their default, oldest first, up to 50. The default is `defaultAddress` on the customer and is not repeated here.

Needs `customers:read`.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `storeId` | path | string | The shop. |
| `customerId` | path | string | The customer. |

**Answers** `200`

| Field | Type | Description |
| --- | --- | --- |
| `data` | array of [CustomerSavedAddress](https://storeware.ai/docs/api-reference/rest/objects#customersavedaddress) |  |
| `meta` | object |  |
| `meta.total` | integer | How many match, across every page. |

```bash
curl "https://api.storeware.ai/api/v1/stores/$STORE_ID/customers/$CUSTOMER_ID/addresses" \
  -H "Authorization: Bearer $TOKEN"
```

## Save an address for a customer

`POST /api/v1/stores/{storeId}/customers/{customerId}/addresses`

Saves another address, whole. One the customer already has, their default included, is a 409, and so is one past the 50 a customer can keep. Send an `Idempotency-Key` header to make a retry safe.

Needs `customers:write`.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `storeId` | path | string | The shop. |
| `customerId` | path | string | The customer. |

**Body**

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `address` | object | Yes |  |
| `address.name` | string or null | No | Up to 200 characters. |
| `address.line_one` | string | Yes | 1 to 200 characters. |
| `address.line_two` | string or null | No | Up to 200 characters. |
| `address.city` | string | Yes | 1 to 120 characters. |
| `address.state` | string or null | No | Up to 120 characters. |
| `address.country` | string | Yes | Matches `^[A-Z]{2}$`. |
| `address.postal_code` | string | Yes | 1 to 32 characters. |

**Answers** `201`

| Field | Type | Description |
| --- | --- | --- |
| `data` | [CustomerSavedAddress](https://storeware.ai/docs/api-reference/rest/objects#customersavedaddress) |  |

```bash
curl -X POST "https://api.storeware.ai/api/v1/stores/$STORE_ID/customers/$CUSTOMER_ID/addresses" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d @body.json
```

## Correct a customer’s saved address

`PATCH /api/v1/stores/{storeId}/customers/{customerId}/addresses/{addressId}`

Replaces the address whole. Sending what is already there changes nothing. Lines that match another address the customer has are a 409. Send an `Idempotency-Key` header to make a retry safe.

Needs `customers:write`.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `storeId` | path | string | The shop. |
| `customerId` | path | string | The customer. |
| `addressId` | path | string | The address. |

**Body**

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `address` | object | Yes |  |
| `address.name` | string or null | No | Up to 200 characters. |
| `address.line_one` | string | Yes | 1 to 200 characters. |
| `address.line_two` | string or null | No | Up to 200 characters. |
| `address.city` | string | Yes | 1 to 120 characters. |
| `address.state` | string or null | No | Up to 120 characters. |
| `address.country` | string | Yes | Matches `^[A-Z]{2}$`. |
| `address.postal_code` | string | Yes | 1 to 32 characters. |

**Answers** `200`

| Field | Type | Description |
| --- | --- | --- |
| `data` | [CustomerSavedAddress](https://storeware.ai/docs/api-reference/rest/objects#customersavedaddress) |  |

```bash
curl -X PATCH "https://api.storeware.ai/api/v1/stores/$STORE_ID/customers/$CUSTOMER_ID/addresses/$ADDRESS_ID" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d @body.json
```

## Remove a customer’s saved address

`DELETE /api/v1/stores/{storeId}/customers/{customerId}/addresses/{addressId}`

Removes one saved address. The default is not one and stays. Send an `Idempotency-Key` header to make a retry safe.

Needs `customers:write`.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `storeId` | path | string | The shop. |
| `customerId` | path | string | The customer. |
| `addressId` | path | string | The address. |

**Answers** `200`

| Field | Type | Description |
| --- | --- | --- |
| `data` | object |  |
| `data.removed` | `true` |  |

```bash
curl -X DELETE "https://api.storeware.ai/api/v1/stores/$STORE_ID/customers/$CUSTOMER_ID/addresses/$ADDRESS_ID" \
  -H "Authorization: Bearer $TOKEN"
```

## Make a saved address the default

`POST /api/v1/stores/{storeId}/customers/{customerId}/addresses/{addressId}/default`

Puts this address on the customer as `defaultAddress`, and saves the old default in its place, so no address is lost. Send an `Idempotency-Key` header to make a retry safe.

Needs `customers:write`.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `storeId` | path | string | The shop. |
| `customerId` | path | string | The customer. |
| `addressId` | path | string | The address. |

**Answers** `200`

| Field | Type | Description |
| --- | --- | --- |
| `data` | object |  |
| `data.madeDefault` | `true` |  |

```bash
curl -X POST "https://api.storeware.ai/api/v1/stores/$STORE_ID/customers/$CUSTOMER_ID/addresses/$ADDRESS_ID/default" \
  -H "Authorization: Bearer $TOKEN"
```

## Archive a customer

`POST /api/v1/stores/{storeId}/customers/{customerId}/archive`

Puts the customer away without deleting anything: their orders, credit and email stay theirs. They leave the lists and totals, and are signed out of their account on the shop until unarchived. Archiving one already archived changes nothing.

Needs `customers:write`.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `storeId` | path | string | The shop. |
| `customerId` | path | string | The customer. |

**Answers** `200`

| Field | Type | Description |
| --- | --- | --- |
| `data` | [Customer](https://storeware.ai/docs/api-reference/rest/objects#customer) |  |

```bash
curl -X POST "https://api.storeware.ai/api/v1/stores/$STORE_ID/customers/$CUSTOMER_ID/archive" \
  -H "Authorization: Bearer $TOKEN"
```

## Unarchive a customer

`POST /api/v1/stores/{storeId}/customers/{customerId}/unarchive`

Brings the customer back as they were. One not archived is answered as it is.

Needs `customers:write`.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `storeId` | path | string | The shop. |
| `customerId` | path | string | The customer. |

**Answers** `200`

| Field | Type | Description |
| --- | --- | --- |
| `data` | [Customer](https://storeware.ai/docs/api-reference/rest/objects#customer) |  |

```bash
curl -X POST "https://api.storeware.ai/api/v1/stores/$STORE_ID/customers/$CUSTOMER_ID/unarchive" \
  -H "Authorization: Bearer $TOKEN"
```

## Withdraw a customer’s marketing consent

`DELETE /api/v1/stores/{storeId}/customers/{customerId}/marketing-consent`

Records that the customer asked not to be emailed, and sends `customer.consent_withdrawn.v1` with their email. Consent can only be withdrawn here, never given. A customer already off the list is answered as they are.

Needs `customers:write`.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `storeId` | path | string | The shop. |
| `customerId` | path | string | The customer. |

**Answers** `200`

| Field | Type | Description |
| --- | --- | --- |
| `data` | [Customer](https://storeware.ai/docs/api-reference/rest/objects#customer) |  |

```bash
curl -X DELETE "https://api.storeware.ai/api/v1/stores/$STORE_ID/customers/$CUSTOMER_ID/marketing-consent" \
  -H "Authorization: Bearer $TOKEN"
```

## List a customer’s metafields

`GET /api/v1/stores/{storeId}/customers/{customerId}/metafields`

Every metafield value set on a customer, each with its definition.

Needs `customers:read`.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `storeId` | path | string | The shop. |
| `customerId` | path | string | The customer. |

**Answers** `200`

| Field | Type | Description |
| --- | --- | --- |
| `data` | array of object |  |
| `data[].definitionId` | string (uuid) |  |
| `data[].namespace` | string |  |
| `data[].key` | string |  |
| `data[].label` | string | The merchant’s name for the field. |
| `data[].type` | string | single_line_text, multi_line_text, integer, decimal, boolean, date, url and the other definition types. |
| `data[].isList` | boolean |  |
| `data[].storefrontVisible` | boolean |  |
| `data[].searchFacet` | boolean |  |
| `data[].position` | integer |  |
| `data[].value` | any | The value, or a list of values when `isList`. |
| `data[].displayValue` | string | The value as one line of text, lists joined. |
| `data[].source` | string | Who set it: the merchant, an import, or an app’s slug. |

```bash
curl "https://api.storeware.ai/api/v1/stores/$STORE_ID/customers/$CUSTOMER_ID/metafields" \
  -H "Authorization: Bearer $TOKEN"
```

## Set a customer’s metafields

`PUT /api/v1/stores/{storeId}/customers/{customerId}/metafields`

Sets up to 25 values in one call. A null value clears its field; keys not named are left alone. An app may set only the fields its manifest declares.

Needs `customers:write`.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `storeId` | path | string | The shop. |
| `customerId` | path | string | The customer. |

**Body**

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `metafields` | array of object | Yes | Up to 25 items. At least 1 item. |
| `metafields[].namespace` | string | No | Default `custom`. |
| `metafields[].key` | string | Yes |  |
| `metafields[].value` | any | No |  |

**Answers** `200`

| Field | Type | Description |
| --- | --- | --- |
| `data` | array of object |  |
| `data[].definitionId` | string (uuid) |  |
| `data[].namespace` | string |  |
| `data[].key` | string |  |
| `data[].label` | string | The merchant’s name for the field. |
| `data[].type` | string | single_line_text, multi_line_text, integer, decimal, boolean, date, url and the other definition types. |
| `data[].isList` | boolean |  |
| `data[].storefrontVisible` | boolean |  |
| `data[].searchFacet` | boolean |  |
| `data[].position` | integer |  |
| `data[].value` | any | The value, or a list of values when `isList`. |
| `data[].displayValue` | string | The value as one line of text, lists joined. |
| `data[].source` | string | Who set it: the merchant, an import, or an app’s slug. |

```bash
curl -X PUT "https://api.storeware.ai/api/v1/stores/$STORE_ID/customers/$CUSTOMER_ID/metafields" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d @body.json
```

## List the trade accounts a customer buys for

`GET /api/v1/stores/{storeId}/customers/{customerId}/companies`

The companies the customer buys on behalf of, by name. At most one today.

Needs `companies:read`.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `storeId` | path | string | The shop. |
| `customerId` | path | string | The customer. |

**Answers** `200`

| Field | Type | Description |
| --- | --- | --- |
| `data` | array of object |  |
| `data[].id` | string (uuid) |  |
| `data[].storeId` | string (uuid) |  |
| `data[].name` | string |  |
| `data[].slug` | string |  |
| `data[].status` | string | Only an `active` account gets its agreed prices. One of `pending`, `active`, `archived`. |
| `data[].taxExempt` | boolean |  |
| `data[].taxExemptionReference` | string or null |  |
| `data[].paymentTermsNetDays` | number or null | Days it has to pay an invoice. Null pays at the till; 0 is due on receipt. |
| `data[].creditLimitAmount` | number or null | The most it may owe at once, in minor units of `creditCurrency`. Null is no limit. |
| `data[].creditCurrency` | string or null |  |
| `data[].priceListId` | string (uuid) or null |  |
| `data[].note` | string or null | The merchant’s own note. Never shown to the buyer. |
| `data[].createdAt` | string (date-time) |  |
| `data[].updatedAt` | string (date-time) |  |

```bash
curl "https://api.storeware.ai/api/v1/stores/$STORE_ID/customers/$CUSTOMER_ID/companies" \
  -H "Authorization: Bearer $TOKEN"
```

## Get a customer’s store credit

`GET /api/v1/stores/{storeId}/customers/{customerId}/store-credit`

What the customer holds in each currency, and the entries behind it, newest first. `orders:read` will do in place of `customers:read`.

Needs `customers:read`.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `storeId` | path | string | The shop. |
| `customerId` | path | string | The customer. |
| `limit` | query | integer | How many entries to return, up to 200. Fifty when not given. From 1 to 200. |

**Answers** `200`

| Field | Type | Description |
| --- | --- | --- |
| `data` | object |  |
| `data.balances` | array of object | One for each currency they hold credit in. |
| `data.balances[].accountId` | string (uuid) |  |
| `data.balances[].customerId` | string (uuid) |  |
| `data.balances[].currency` | string |  |
| `data.balances[].balanceAmount` | integer | In minor units. |
| `data.entries` | array of object | Across every currency, newest first. |
| `data.entries[].id` | string (uuid) |  |
| `data.entries[].storeId` | string (uuid) |  |
| `data.entries[].accountId` | string (uuid) |  |
| `data.entries[].delta` | number | In minor units. Positive puts credit on, negative spends it. |
| `data.entries[].currency` | string | Credit is held per currency. |
| `data.entries[].balanceAfter` | number | The balance after this entry, in minor units. |
| `data.entries[].reason` | string | One of `return_refund`, `goodwill`, `order_payment`, `order_canceled`, `manual_adjustment`, `exchange_difference`, `gift_card`. |
| `data.entries[].note` | string or null |  |
| `data.entries[].orderId` | string (uuid) or null |  |
| `data.entries[].returnId` | string (uuid) or null |  |
| `data.entries[].adjustmentId` | string (uuid) or null |  |
| `data.entries[].giftCardId` | string (uuid) or null |  |
| `data.entries[].sessionId` | string (uuid) or null |  |
| `data.entries[].idempotencyKey` | string or null |  |
| `data.entries[].actorType` | string or null |  |
| `data.entries[].actorId` | string or null |  |
| `data.entries[].createdAt` | string (date-time) |  |

```bash
curl "https://api.storeware.ai/api/v1/stores/$STORE_ID/customers/$CUSTOMER_ID/store-credit" \
  -H "Authorization: Bearer $TOKEN"
```

## Give a customer store credit

`POST /api/v1/stores/{storeId}/customers/{customerId}/store-credit`

Puts credit on the customer’s account in one currency, for them to spend at checkout. `amount` is in minor units. It needs `orders:write`, as a refund does. An `idempotencyKey` already used is refused, so a retry cannot credit twice.

Needs `orders:write`.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `storeId` | path | string | The shop. |
| `customerId` | path | string | The customer. |

**Body**

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `amount` | integer | Yes |  |
| `currency` | string | Yes | 3 to 3 characters. |
| `reason` | string | No | One of `return_refund`, `goodwill`, `order_payment`, `order_canceled`, `manual_adjustment`, `exchange_difference`, `gift_card`. Default `goodwill`. |
| `note` | string | No | Up to 500 characters. |
| `orderId` | string (uuid) | No |  |
| `idempotencyKey` | string | No | Up to 200 characters. |

**Answers** `201`

| Field | Type | Description |
| --- | --- | --- |
| `data` | object |  |
| `data.id` | string (uuid) |  |
| `data.storeId` | string (uuid) |  |
| `data.accountId` | string (uuid) |  |
| `data.delta` | number | In minor units. Positive puts credit on, negative spends it. |
| `data.currency` | string | Credit is held per currency. |
| `data.balanceAfter` | number | The balance after this entry, in minor units. |
| `data.reason` | string | One of `return_refund`, `goodwill`, `order_payment`, `order_canceled`, `manual_adjustment`, `exchange_difference`, `gift_card`. |
| `data.note` | string or null |  |
| `data.orderId` | string (uuid) or null |  |
| `data.returnId` | string (uuid) or null |  |
| `data.adjustmentId` | string (uuid) or null |  |
| `data.giftCardId` | string (uuid) or null |  |
| `data.sessionId` | string (uuid) or null |  |
| `data.idempotencyKey` | string or null |  |
| `data.actorType` | string or null |  |
| `data.actorId` | string or null |  |
| `data.createdAt` | string (date-time) |  |

```bash
curl -X POST "https://api.storeware.ai/api/v1/stores/$STORE_ID/customers/$CUSTOMER_ID/store-credit" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d @body.json
```

## Get what the shop remembers about a customer

`GET /api/v1/stores/{storeId}/customers/{customerId}/memory`

What the customer told the shop they want while shopping signed in (a budget, requirements, context), which the shop keeps to narrow and rank what it shows them.

Needs `customers:read`.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `storeId` | path | string | The shop. |
| `customerId` | path | string | The customer. |

**Answers** `200`

| Field | Type | Description |
| --- | --- | --- |
| `data` | object or null | Null when the shop keeps nothing about them. |
| `data.profile` | object |  |
| `data.profile.maxPrice` | number or null | The most they said they would pay, in whole units of the currency, not minor units. |
| `data.profile.minPrice` | number or null | The least, in the same units. |
| `data.profile.requiredAttributes` | array of object | What they said it must be, such as a colour or a size. |
| `data.profile.requiredAttributes[].key` | string |  |
| `data.profile.requiredAttributes[].value` | string |  |
| `data.profile.context` | array of string | Who it is for, the occasion, the conditions. It ranks what they see and never hides anything. |
| `data.confirmedAt` | string (date-time) | When they last said any of it. |

```bash
curl "https://api.storeware.ai/api/v1/stores/$STORE_ID/customers/$CUSTOMER_ID/memory" \
  -H "Authorization: Bearer $TOKEN"
```

## Make the shop forget what a customer told it

`POST /api/v1/stores/{storeId}/customers/{customerId}/memory`

Removes all of it, or one part. There is no default: a body that names nothing is a 400. Answers with what remains.

Needs `customers:write`.

**Parameters**

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `storeId` | path | string | The shop. |
| `customerId` | path | string | The customer. |

**Body**

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `forget` | string | Yes | What to forget. `attribute` forgets one requirement, named by `key`. One of `all`, `budget`, `context`, `attribute`. |
| `key` | string | No | With `attribute`: the requirement’s key. |

**Answers** `200`

| Field | Type | Description |
| --- | --- | --- |
| `data` | object or null | Null when the shop keeps nothing about them. |
| `data.profile` | object |  |
| `data.profile.maxPrice` | number or null | The most they said they would pay, in whole units of the currency, not minor units. |
| `data.profile.minPrice` | number or null | The least, in the same units. |
| `data.profile.requiredAttributes` | array of object | What they said it must be, such as a colour or a size. |
| `data.profile.requiredAttributes[].key` | string |  |
| `data.profile.requiredAttributes[].value` | string |  |
| `data.profile.context` | array of string | Who it is for, the occasion, the conditions. It ranks what they see and never hides anything. |
| `data.confirmedAt` | string (date-time) | When they last said any of it. |

```bash
curl -X POST "https://api.storeware.ai/api/v1/stores/$STORE_ID/customers/$CUSTOMER_ID/memory" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d @body.json
```
