> This page is for Developer.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.bigcommerce.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.bigcommerce.com/_mcp/server.

# GraphQL Storefront API: Customers

BigCommerce's GraphQL Storefront API Customers powers access to customer objects such as the ability to update a customer, get a customer address book, reset a password, and more. Developers can use GraphQL Storefront API to create an end-to-end shopper experience and manage some customer account use cases.

Customer mutations and queries can do the following:

* Register a customer
* Update a customer
* Add a customer address
* Update a customer address
* Delete a customer address
* Change a customer password
* Request a password reset
* Reset a password
* Get a customer address book
* Get a customer's stored payment instruments
* Update a customer's stored payment instrument
* Delete a customer's stored payment instrument

When you register, change, or reset a password, you can validate it using the password complexity requirements under the [CustomersSettings node](/developer/api-reference/graphql/storefront/types/objects/customers-settings) before submitting the desired password to the BigCommerce platform.

## Tokens

To make requests, create a [store-level](/developer/docs/overview/api-fundamentals/api-accounts#store-level-api-accounts) or [app-level](/developer/docs/overview/api-fundamentals/api-accounts#app-level-api-accounts) API account with one or more of the following token creation OAuth scopes:

| UI Name                                      | Permission | Parameter                                     | Description                                                                   |
| :------------------------------------------- | :--------- | :-------------------------------------------- | :---------------------------------------------------------------------------- |
| Storefront API tokens                        | modify     | `store_storefront-api`                        | Create payment access tokens, process payments                                |
| Storefront API customer impersonation tokens | modify     | `store_storefront_api_customer_impersonation` | Create GraphQL Storefront API bearer tokens that allow customer impersonation |

No additional scopes are required to use the GraphQL Storefront API. For more information, see [token creation OAuth scopes](/developer/docs/overview/api-fundamentals/api-accounts#token-creation-scopes).

To authenticate calls to the GraphQL Storefront API, your application can generate a bearer token. This can be done by using either the [Create a storefront token](/developer/api-reference/rest/admin/authentication-apis/storefront-api-tokens/create-token) or the [Create a customer impersonation token](/developer/api-reference/rest/admin/authentication-apis/storefront-api-tokens/customer-impersonation-token/create-token-with-customer-impersonation) REST endpoint. On a Stencil storefront, you can also access a token directly from the page context. Learn more about [Using auto-generated tokens in Stencil themes](/developer/docs/storefront/guides/graphql-storefront-api#using-auto-generated-tokens-in-stencil-themes).

For more information, see [Creating a token](/developer/docs/storefront/guides/graphql-storefront-api#creating-a-token) in the GraphQL Storefront API Overview and [Dynamic tokens](/developer/docs/overview/api-fundamentals/api-accounts#bigcommerce-generated-jwts) in the Authentication and Example Requests article.

## reCAPTCHA

Captcha is not required when the reCAPTCHA is disabled in the control panel. Be sure to use a valid user verification response reCAPTCHA token if reCAPTCHA is enabled.

Customer impersonation tokens do not require the use of reCAPTCHA even when the reCAPTCHA setting is enabled. You can bypass the reCAPTCHA and it will still function. Note, if reCAPTCHA is provided it must be valid, otherwise it will be rejected.

## Example queries and mutations

### Register a customer

Register a customer using the form field configuration set up in the control panel for both the account signup and address fields.

#### Request

**`Example mutation: Register a customer`**

```graphql title="Example mutation: Register a customer"
mutation {
  customer {
    registerCustomer(
      reCaptchaV2: { token: "" }
      input: {
        firstName: "John"
        lastName: "Smith"
        email: "jon@example.com"
        password: "Password123!"
        phone: "123-456-7890"
        company: "BC"
        address: {
          firstName: "John"
          lastName: "Smith"
          address1: "123 Main Street"
          address2: "Suite 200"
          city: "Austin"
          company: "Acme Corporation"
          countryCode: "US"
          stateOrProvince: "TX"
          phone: "555-123-4567"
          postalCode: "78701"
        }
        formFields: {
          checkboxes: [{ fieldEntityId: 1, fieldValueEntityIds: [1, 2, 3] }]
          multipleChoices: [{ fieldEntityId: 1, fieldValueEntityId: 2 }]
          numbers: [{ fieldEntityId: 1, number: 1.0 }]
          texts: [{ fieldEntityId: 1, text: "Customer notes" }]
          passwords: [{ fieldEntityId: 1, password: "SecurePassword123!" }]
        }
      }
    ) {
      customer {
        firstName
        lastName
      }
      errors {
        __typename
        ... on ValidationError {
          message
        }
        ... on CustomerRegistrationError {
          message
        }
        ... on EmailAlreadyInUseError {
          message
        }
        ... on AccountCreationDisabledError {
          message
        }
      }
    }
  }
}
```

#### Response

**`Example mutation: Register a customer`**

```json title="Example mutation: Register a customer"
# Success

{
  "data": {
    "customer": {
      "registerCustomer": {
        "customer": {
          "firstName": "John",
          "lastName": "Smith"
        },
        "errors": []
      }
    }
  }
}


# Error - Email already in use

{
  "data": {
    "customer": {
      "registerCustomer": {
        "customer": null,
        "errors": [
          {
            "__typename": "EmailAlreadyInUseError",
            "message": "The email address is already in use."
          }
        ]
      }
    }
  }
}
```

### Update a customer

Update customer information, except for password and address. Use either `resetPassword`, or `changePassword` to reset or update the user password.

#### Request

**`Example mutation: Customer update`**

```graphql title="Example mutation: Customer update"
mutation {
  customer {
    updateCustomer(
      reCaptchaV2: { token: "" }
      input: {
        firstName: "John"
        lastName: "Smith"
        email: "john@test.com"
        phone: "123-456-7890"
        company: "BC"
        formFields: {
          # optional
          checkboxes: [{ fieldEntityId: 1, fieldValueEntityIds: [1, 2, 3] }]
          multipleChoices: [{ fieldEntityId: 1, fieldValueEntityId: 2 }]
          numbers: [{ fieldEntityId: 1, number: 1.0 }]
          texts: [{ fieldEntityId: 1, text: "Customer notes" }]
          passwords: [{ fieldEntityId: 1, password: "SecurePassword123!" }]
        }
      }
    ) {
      customer {
        firstName
        lastName
      }
      errors {
        __typename
        ... on ValidationError {
          message
        }
        ... on CustomerDoesNotExistError {
          message
        }
        ... on EmailAlreadyInUseError {
          message
        }
      }
    }
  }
}
```

#### Response

**`Example mutation: Customer update`**

```json title="Example mutation: Customer update" "
{
  "data": {
    "customer": {
      "updateCustomer": {
        "customer": {
          "firstName": "Jonathan",
          "lastName": "Smith"
        },
        "errors": []
      }
    }
  }
}
```

### Add a customer address

The BigCommerce platform can support and store plenty of addresses per customer. Use the `addCustomerAddress` to include multiple addresses to the customer account.  Similar to `registerCustomer`, add `CustomerAddress` using the form field configuration set up in the control panel for address fields.

#### Request

**`Example mutation: Add a customer address`**

```graphql title="Example mutation: Add a customer address"
mutation {
  customer {
    addCustomerAddress(
      reCaptchaV2: { token: "" }
      input: {
        firstName: "John"
        lastName: "Smith"
        address1: "1234 Fake Street"
        address2: ""
        city: "Austin"
        company: "BC"
        countryCode: "US"
        stateOrProvince: "TX"
        phone: "123-456-7890"
        postalCode: "78610"
        formFields: {
          checkboxes: [{ fieldEntityId: 1, fieldValueEntityIds: [1, 2, 3] }]
          multipleChoices: [{ fieldEntityId: 1, fieldValueEntityId: 2 }]
          numbers: [{ fieldEntityId: 1, number: 1.0 }]
          texts: [{ fieldEntityId: 1, text: "Customer notes" }]
          passwords: [{ fieldEntityId: 1, password: "SecurePassword123!" }]
        }
      }
    ) {
      errors {
        __typename
        ... on ValidationError {
          message
        }
        ... on CustomerNotLoggedInError {
          message
        }
        ... on CustomerAddressCreationError {
          message
        }
      }
    }
  }
}
```

#### Response

**`Example mutation: Add a customer address`**

```json title="Example mutation: Add a customer address"
{
  "data": {
    "customer": {
      "addCustomerAddress": {
        "errors": []
      }
    }
  }
}
```

### Update a customer address

Use this `updateCustomerAddress` mutation when a customer needs to make changes to an address associated with their account.

#### Request

**`Example mutation: Update a customer address`**

```graphql title="Example mutation: Update a customer address"
mutation {
  customer {
    updateCustomerAddress(
    reCaptchaV2: { token: "" },
    input: {
        addressEntityId: 1,
        data: {
        firstName: "John",
        lastName: "Smith",
        address1: "123 Main Street",
        address2: "Suite 200",
        city: "Austin",
        company: "Acme Corporation",
        countryCode: "US",
        stateOrProvince: "TX",
        phone: "555-123-4567",
        postalCode: "78701",
        formFields: {
            checkboxes: [
            {
                fieldEntityId: 1,
                fieldValueEntityIds: [1,2,3]
            }
            ],
            multipleChoices: [
            {
                fieldEntityId: 1,
                fieldValueEntityId: 2
            }
            ],
            numbers: [
            {
                fieldEntityId: 1,
                number: 1.0
            }
            ],
            texts: [
            {
                fieldEntityId: 1,
                text: "Customer notes"
            }
            ],
            passwords: [
            {
                fieldEntityId: 1,
                password: "SecurePassword123!"
            }
            ],
        }
        }
    }
    ) {
    errors {
        __typename
        ... on ValidationError {
        message
        }
        ... on CustomerNotLoggedInError {
        message
        }
        ... on AddressDoesNotExistError {
        message
        }
        ... on CustomerAddressUpdateError {
        message
        }
      }
    }
  }
}
```

#### Response

**`Example mutation: Update a customer address`**

```json title="Example mutation: Update a customer address"
# Success

{
  "data": {
    "customer": {
      "updateCustomerAddress": {
        "errors": []
      }
    }
  }
}

# Error
# Address Does Not Exist

{
"data": {
  "customer": {
    "updateCustomerAddress": {
      "errors": [
        {
          "__typename": "AddressDoesNotExistError",
          "message": "An address with the supplied ID does not exist."
        }
      ]
    }
  }
}
}
```

### Delete a customer address

Use this `delete` mutation when a customer needs to delete an address associated with their account.

#### Request

**`Example mutation: Delete a customer address`**

```graphql title="Example mutation: Delete a customer address"
mutation {
  customer {
    deleteCustomerAddress(
      reCaptchaV2: { token: "" }
      input: { addressEntityId: 1 }
    ) {
      errors {
        __typename
        ... on CustomerNotLoggedInError {
          message
        }
        ... on CustomerAddressDeletionError {
          message
        }
      }
    }
  }
}
```

#### Response

**`Example mutation: Delete a customer address`**

```json title="Example mutation: Delete a customer address"
{
  "data": {
    "customer": {
      "deleteCustomerAddress": {
        "errors": []
      }
    }
  }
}
```

### Change a customer password

Use the `changePassword` mutation in cases where the customer needs to update their password. The user must know their current password in order to complete the change.

#### Request

**`Example mutation: Change a user password`**

```graphql title="Example mutation: Change a user password"
mutation {
  customer {
    changePassword(
      input: { currentPassword: "Password1!", newPassword: "Password2!" }
    ) {
      errors {
        ... on ValidationError {
          path
          message
        }
        ... on CustomerPasswordError {
          message
        }
        ... on CustomerDoesNotExistError {
          message
        }
        ... on CustomerNotLoggedInError {
          message
        }
      }
    }
  }
}
```

### Request a password reset

A customer can request a password reset using the `requestResetPassword` mutation example as seen below.

#### Request

**`Example mutation: Request a password reset`**

```graphql title="Example mutation: Request a password reset"
mutation {
  customer {
    requestResetPassword(
      reCaptchaV2: { token: "" }
      input: { email: "john@test.com" }
    ) {
      errors {
        ... on ValidationError {
          message
        }
      }
    }
  }
}
```

#### Response

**`Example mutation: Request a password reset`**

```json title="Example mutation: Request a password reset"
{
  "data": {
    "customer": {
      "requestResetPassword": {
        "errors": []
      }
    }
  }
}
```

### Reset a password

When a customer needs a password reset, use the `resetPassword` example mutation to complete the reset.

#### Request

**`Example mutation: Reset a password`**

```graphql title="Example mutation: Reset a password"
mutation {
  customer {
    resetPassword(
      input: {
        customerEntityId: 1 # Provided in the link contained in the reset password email
        token: "" # Provided in the link contained in the reset password email
        newPassword: "NewPassword1234"
      }
    ) {
      errors {
        ... on ValidationError {
          message
        }
        ... on ChangePasswordError {
          message
        }
      }
    }
  }
}
```

### Get a customer address book

Use this query to view all the addresses a customer has added to their account.

#### Request

**`Example query: Get a customer address book`**

```graphql title="Example query: Get a customer address book"
query {
    customer {
      firstName
      lastName
      formFields {
          entityId
          name
      }
      addresses {
          collectionInfo {
              totalItems
          }
          edges {
              node {
                  entityId
                  firstName
                  lastName
                  address1
                  city
                  stateOrProvince
                  postalCode
                  formFields {
                      entityId
                      name
                  }
              }
          }
      }
    }
}
```

### Get a customer's stored payment instruments

Use the `storedPaymentInstruments` field on the `Customer` type to list the payment instruments a customer has saved, such as cards, PayPal accounts, and bank accounts.

> **Warning**
>
> This field requires a valid customer JWT. Use a [customer impersonation token](/developer/api-reference/rest/admin/authentication-apis/storefront-api-tokens/customer-impersonation-token/create-token-with-customer-impersonation), or a token retrieved while a customer is logged in to the storefront. For unauthenticated requests, the parent `customer` query resolves to `null`, so no instruments are returned.

The connection returns one `StoredPaymentInstrument` per edge. Each instrument's `details` field is a `StoredPaymentInstrumentDetails` union — use inline fragments (`... on StoredCard`, `... on StoredPaypalAccount`, `... on StoredBankAccount`) to select the type-specific fields. The connection also exposes `defaultStoredPaymentInstrumentToken`, the token of the customer's default instrument when one is set.

The connection follows the [Relay cursor connection spec](https://relay.dev/graphql/connections.htm). Page through results with the `first`/`after` (forward) or `last`/`before` (backward) arguments, and read `pageInfo` to determine whether more pages are available and which cursors to request next. Each edge's `cursor` is the value to pass to `after` (or `before`) to continue paging from that instrument.

To narrow the result set to specific payment methods, pass the `filters` argument with one or more `paymentMethodIds` (for example, `["braintree.credit_card", "braintree.paypal"]`). An empty or omitted list returns all instruments.

The example below requests the first 10 instruments after a given cursor, filtered to cards and PayPal accounts, and selects the full set of fields available on each instrument type.

#### Request

**`Example query: Get a customer's stored payment instruments`**

```graphql title="Example query: Get a customer's stored payment instruments"
query {
  customer {
    storedPaymentInstruments(
      first: 10
      after: "eyJ0b2tlbiI6ImExYjJjM2Q0ZTUifQ=="
      filters: { paymentMethodIds: ["braintree.credit_card", "braintree.paypal"] }
    ) {
      defaultStoredPaymentInstrumentToken
      pageInfo {
        hasNextPage
        hasPreviousPage
        startCursor
        endCursor
      }
      edges {
        cursor
        node {
          token
          paymentMethodId
          details {
            __typename
            ... on StoredCard {
              brand
              last4
              issuerIdentificationNumber
              expires {
                month
                year
              }
              billingAddress {
                firstName
                lastName
                email
                company
                address1
                address2
                city
                stateOrProvince
                stateOrProvinceCode
                postalCode
                countryCode
                phone
              }
            }
            ... on StoredPaypalAccount {
              email
            }
            ... on StoredBankAccount {
              maskedAccountNumber
              issuer
            }
          }
        }
      }
    }
  }
}
```

#### Response

**`Example query: Get a customer's stored payment instruments`**

```json title="Example query: Get a customer's stored payment instruments"
{
  "data": {
    "customer": {
      "storedPaymentInstruments": {
        "defaultStoredPaymentInstrumentToken": "a1b2c3d4e5",
        "pageInfo": {
          "hasNextPage": false,
          "hasPreviousPage": false,
          "startCursor": "eyJ0b2tlbiI6ImExYjJjM2Q0ZTUifQ==",
          "endCursor": "eyJ0b2tlbiI6ImJjZGVmZyJ9"
        },
        "edges": [
          {
            "cursor": "eyJ0b2tlbiI6ImExYjJjM2Q0ZTUifQ==",
            "node": {
              "token": "a1b2c3d4e5",
              "paymentMethodId": "braintree.credit_card",
              "details": {
                "__typename": "StoredCard",
                "brand": "VISA",
                "last4": "1111",
                "issuerIdentificationNumber": "411111",
                "expires": {
                  "month": 12,
                  "year": 2027
                },
                "billingAddress": {
                  "firstName": "John",
                  "lastName": "Smith",
                  "email": "john@example.com",
                  "company": "Acme Inc.",
                  "address1": "123 Main Street",
                  "address2": "Suite 200",
                  "city": "Austin",
                  "stateOrProvince": "Texas",
                  "stateOrProvinceCode": "TX",
                  "postalCode": "78701",
                  "countryCode": "US",
                  "phone": "512-555-0142"
                }
              }
            }
          },
          {
            "cursor": "eyJ0b2tlbiI6ImZnaGlqayJ9",
            "node": {
              "token": "fghijk67890",
              "paymentMethodId": "braintree.paypal",
              "details": {
                "__typename": "StoredPaypalAccount",
                "email": "john@example.com"
              }
            }
          },
          {
            "cursor": "eyJ0b2tlbiI6ImJjZGVmZyJ9",
            "node": {
              "token": "bcdefg12345",
              "paymentMethodId": "stripe.bank_account",
              "details": {
                "__typename": "StoredBankAccount",
                "maskedAccountNumber": "****6789",
                "issuer": "Example Bank"
              }
            }
          }
        ]
      }
    }
  }
}
```

### Update a customer's stored payment instrument

Use the `updateStoredPaymentInstrument` mutation on the `customer` mutation type to update the billing address and/or promote a stored payment instrument to be the customer's default. Instrument data itself, such as the card number, expiry, or brand, is immutable and cannot be changed through this mutation.

> **Warning**
>
> This field requires a valid customer JWT, the same as `storedPaymentInstruments`. Use a [customer impersonation token](/developer/api-reference/rest/admin/authentication-apis/storefront-api-tokens/customer-impersonation-token/create-token-with-customer-impersonation), or a token retrieved while a customer is logged in to the storefront.

Both this mutation and `deleteStoredPaymentInstrument` act on an existing instrument's `token`. Get an instrument's token from the [`storedPaymentInstruments`](#get-a-customers-stored-payment-instruments) query before calling either mutation.

`setAsDefault` is promote-only: pass `true` to make this instrument the customer's default. Omitting the field or passing `false` leaves the current default unchanged — there is no way to unset a default without promoting a different instrument in its place.

Billing address updates are supported only for card instruments whose payment method allows editing. Passing billingAddress for any other instrument returns an error.

On `billingAddress`, `firstName`, `address1`, `city`, and `countryCode` are required. `lastName`, `email`, `company`, `address2`, `stateOrProvince`, `stateOrProvinceCode`, `postalCode`, and `phone` are optional.

The result's `defaultStoredPaymentInstrumentToken` is populated only when the request sets `setAsDefault: true`, in which case it echoes the token of the instrument just promoted. Billing-only updates, and requests where `setAsDefault` is omitted or `false`, return `null` for this field — even if the customer already has a different default instrument set.

#### Request

**`Example mutation: Update a customer's stored payment instrument`**

```graphql title="Example mutation: Update a customer's stored payment instrument"
mutation {
  customer {
    updateStoredPaymentInstrument(
      input: {
        token: "a1b2c3d4e5"
        setAsDefault: true
        billingAddress: {
          firstName: "John"
          lastName: "Smith"
          address1: "123 Main Street"
          city: "Austin"
          countryCode: "US"
        }
      }
    ) {
      storedPaymentInstrument {
        token
        paymentMethodId
        details {
          __typename
          ... on StoredCard {
            brand
            last4
            billingAddress {
              firstName
              lastName
              email
              company
              address1
              address2
              city
              stateOrProvince
              stateOrProvinceCode
              postalCode
              countryCode
              phone
            }
          }
        }
      }
      defaultStoredPaymentInstrumentToken
      errors {
        __typename
        message
      }
    }
  }
}
```

#### Response

**`Example mutation: Update a customer's stored payment instrument`**

```json title="Example mutation: Update a customer's stored payment instrument"
# Success

{
  "data": {
    "customer": {
      "updateStoredPaymentInstrument": {
        "storedPaymentInstrument": {
          "token": "a1b2c3d4e5",
          "paymentMethodId": "braintree.credit_card",
          "details": {
            "__typename": "StoredCard",
            "brand": "VISA",
            "last4": "1111",
            "billingAddress": {
              "firstName": "John",
              "lastName": "Smith",
              "email": null,
              "company": null,
              "address1": "123 Main Street",
              "address2": null,
              "city": "Austin",
              "stateOrProvince": null,
              "stateOrProvinceCode": null,
              "postalCode": null,
              "countryCode": "US",
              "phone": null
            }
          }
        },
        "defaultStoredPaymentInstrumentToken": "a1b2c3d4e5",
        "errors": []
      }
    }
  }
}


# Success - billing-only update (setAsDefault omitted)

{
  "data": {
    "customer": {
      "updateStoredPaymentInstrument": {
        "storedPaymentInstrument": {
          "token": "a1b2c3d4e5",
          "paymentMethodId": "braintree.credit_card",
          "details": {
            "__typename": "StoredCard",
            "brand": "VISA",
            "last4": "1111",
            "billingAddress": {
              "firstName": "John",
              "lastName": "Smith",
              "email": null,
              "company": null,
              "address1": "123 Main Street",
              "address2": null,
              "city": "Austin",
              "stateOrProvince": null,
              "stateOrProvinceCode": null,
              "postalCode": null,
              "countryCode": "US",
              "phone": null
            }
          }
        },
        "defaultStoredPaymentInstrumentToken": null,
        "errors": []
      }
    }
  }
}


# Error - Instrument not found or not owned by this customer

{
  "data": {
    "customer": {
      "updateStoredPaymentInstrument": {
        "storedPaymentInstrument": null,
        "defaultStoredPaymentInstrumentToken": null,
        "errors": [
          {
            "__typename": "UpdateStoredPaymentInstrumentError",
            "message": "Unable to update the stored payment instrument."
          }
        ]
      }
    }
  }
}


# Error - Invalid billing address

{
  "data": {
    "customer": {
      "updateStoredPaymentInstrument": {
        "storedPaymentInstrument": null,
        "defaultStoredPaymentInstrumentToken": null,
        "errors": [
          {
            "__typename": "UpdateStoredPaymentInstrumentError",
            "message": "The provided billing address is invalid."
          }
        ]
      }
    }
  }
}
```

### Delete a customer's stored payment instrument

Use the `deleteStoredPaymentInstrument` mutation on the `customer` mutation type to delete a stored payment instrument. Deleting an instrument removes it from BigCommerce and unvaults the associated token at the payment provider.

> **Warning**
>
> This field requires a valid customer JWT, the same as `storedPaymentInstruments`. Use a [customer impersonation token](/developer/api-reference/rest/admin/authentication-apis/storefront-api-tokens/customer-impersonation-token/create-token-with-customer-impersonation), or a token retrieved while a customer is logged in to the storefront.

Get the instrument's `token` from the [`storedPaymentInstruments`](#get-a-customers-stored-payment-instruments) query before calling this mutation.

The mutation result contains only an `errors` list — there is no data payload on success. An empty `errors` array indicates the instrument was deleted.

Deleting the customer's current default instrument automatically promotes another remaining instrument to be the new default.

#### Request

**`Example mutation: Delete a customer's stored payment instrument`**

```graphql title="Example mutation: Delete a customer's stored payment instrument"
mutation {
  customer {
    deleteStoredPaymentInstrument(input: { token: "a1b2c3d4e5" }) {
      errors {
        __typename
        message
      }
    }
  }
}
```

#### Response

**`Example mutation: Delete a customer's stored payment instrument`**

```json title="Example mutation: Delete a customer's stored payment instrument"
# Success

{
  "data": {
    "customer": {
      "deleteStoredPaymentInstrument": {
        "errors": []
      }
    }
  }
}


# Error - Instrument not found or not owned by this customer

{
  "data": {
    "customer": {
      "deleteStoredPaymentInstrument": {
        "errors": [
          {
            "__typename": "DeleteStoredPaymentInstrumentError",
            "message": "Unable to delete the stored payment instrument."
          }
        ]
      }
    }
  }
}
```

### Error handling

`updateStoredPaymentInstrument` and `deleteStoredPaymentInstrument` can fail in two different ways. Expected, request-specific failures — an unsupported payment method or a token that doesn't belong to the customer — are returned in the mutation's own `errors` array, as shown in the examples above. Authentication failures and unmapped or transient upstream errors are returned as top-level GraphQL errors instead, with `data.customer` set to `null`. Check both places when handling responses.

A missing or expired customer JWT returns a top-level error:

**`Example: top-level GraphQL error (missing customer token)`**

```json title="Example: top-level GraphQL error (missing customer token)"
{
  "data": {
    "customer": null
  },
  "errors": [
    {
      "message": "A customer access token is required for this operation, but it was not provided.",
      "path": ["customer"],
      "locations": [{ "line": 1, "column": 9 }],
      "extensions": {
        "code": "MISSING_CUSTOMER_ACCESS_TOKEN"
      }
    }
  ]
}
```

Transient or unmapped upstream failures also surface as a top-level error, but without an `extensions.code`:

**`Example: top-level GraphQL error (unmapped or transient failure)`**

```json title="Example: top-level GraphQL error (unmapped or transient failure)"
{
  "data": {
    "customer": null
  },
  "errors": [
    {
      "message": "Internal server error"
    }
  ]
}
```

Join our [Developer community](https://support.bigcommerce.com/s/community) to share your feedback with us in the BigCommerceDevs Slack.

## Resources

### Documentation

* [GraphQL Storefront API overview](/developer/docs/storefront/guides/graphql-storefront-api)
* [Guide to API Accounts: Store-level API accounts](/developer/docs/overview/api-fundamentals/api-accounts#store-level-api-accounts)
* [Guide to API accounts: OAuth token creation scopes](/developer/docs/overview/api-fundamentals/api-accounts#token-creation-scopes)
* [Authentication and example requests: BigCommerce-generated JWTs](/developer/docs/overview/api-fundamentals/api-accounts#bigcommerce-generated-jwts)

### API reference

#### Storefront tokens

* [Create a storefront token](/developer/api-reference/rest/admin/authentication-apis/storefront-api-tokens/create-token)
* [Create a customer impersonation token](/developer/api-reference/rest/admin/authentication-apis/storefront-api-tokens/customer-impersonation-token/create-token-with-customer-impersonation)

#### REST management API: customers

* [Customers V3](/developer/api-reference/rest/admin/management/customers/v3)

### Community

* [Developer community](https://support.bigcommerce.com/s/community)