Support
Manage orders and customersManage a customer

How to manage a customer

View as Markdown

Create, read, update customer profiles within a store.

Overview

Customers are profiles associated with one or more orders in a store. The Customer API is a REST API. All operations use standard HTTP methods against store-scoped endpoints under v1. The following article provides examples of how to use the Customer API to manage customers in your store.

Prerequisites

The following prerequisites are required before you can manage customers:

  • a GoDaddy account with an active commerce store
  • a Personal Access Token (PAT) with the scopes for the operations you need (commerce.customer:read for reads; commerce.customer:create or :update for writes)
  • your storeId

    Find your store ID

    Go to Your stores to find your store ID.

List customers

GET /v1/commerce/stores/{storeId}/customers retrieves all customers for a store. Deleted customers are excluded by default.

The following procedure lists customers in your store.

  1. Retrieve a list of customers:

    curl -s "https://api.godaddy.com/v1/commerce/stores/${STORE_ID}/customers" \
      -H "Authorization: Bearer $GODADDY_PAT"
  2. Review the response:

    {
      "customers": [
        {
          "customerId": "<CUSTOMER_UUID>",
          "firstName": "<CUSTOMER_FIRST_NAME>",
          "lastName": "<CUSTOMER_LAST_NAME>",
          "emails": [{ "email": "<CUSTOMER_EMAIL_ADDRESS>", "default": true }],
          "phones": [{ "phone": "<CUSTOMER_PHONE_NUMBER>", "default": true }],
          "createdAt": "<ISO8601_CREATED_TIMESTAMP>",
          "updatedAt": "<ISO8601_UPDATED_TIMESTAMP>"
        }
      ],
      "links": [
        {
          "rel": "self",
          "href": "https://api.godaddy.com/v1/commerce/stores/<STORE_ID>/customers?page=1",
          "method": "GET"
        }
      ]
    }

    Response shape

    Each customer is identified by customerId. Contact details (emails, phones) are arrays, not scalar fields — access them as customer.emails[0].email, not customer.email. The links array contains HATEOAS pagination cursors.

    Pagination

    Pass totalRequired=true to include totalItems and totalPages in the response. The returned links echo the current request (e.g. the self link above reflects the page you fetched). To page forward, prefer the pageToken from the previous response over incrementing the page param.

Create a customer

POST /v1/commerce/stores/{storeId}/customers creates a new customer or de-duplicates an existing one using channel data. If the supplied channel data matches an existing customer, the existing record is updated rather than a new one created.

The request body has two top-level fields: a required source (the application creating the customer, e.g. COMMERCE) and a nested customer object holding the profile. Creation is asynchronous — a successful call returns 202 Accepted with a links array rather than the created record.

Contact details must be arrays

Send emails and phones as the emails and phones arrays, each with an email / phone sub-field. A top-level scalar email or phone is accepted with a 202 but silently discarded — the customer is created with no contact info. Always confirm with a follow-up GET.

The following procedure creates a customer profile.

  1. Create a customer with their contact details:

    curl -s -X POST "https://api.godaddy.com/v1/commerce/stores/${STORE_ID}/customers" \
      -H "Authorization: Bearer $GODADDY_PAT" \
      -H "Content-Type: application/json" \
      -d '{
        "source": "COMMERCE",
        "customer": {
          "firstName": "<CUSTOMER_FIRST_NAME>",
          "lastName": "<CUSTOMER_LAST_NAME>",
          "emails": [{ "email": "<CUSTOMER_EMAIL_ADDRESS>", "default": true }],
          "phones": [{ "phone": "<CUSTOMER_PHONE_NUMBER>", "default": true }]
        }
      }'
  2. The call returns 202 Accepted with a links array — not the customer record. Read the customerId from the href of the link whose rel is "customer":

    {
      "links": [
        {
          "rel": "customer",
          "href": "https://api.godaddy.com/v1/commerce/stores/<STORE_ID>/customers/<CUSTOMER_UUID>",
          "method": "GET"
        },
        {
          "rel": "request",
          "href": "https://api.godaddy.com/v1/commerce/stores/<STORE_ID>/customer-requests/<REQUEST_UUID>",
          "method": "GET"
        }
      ]
    }

    Which link to use

    The customerId is the last path segment of the rel: "customer" href. GET that href to confirm the customer (and its contact details) persisted. The rel: "request" link tracks the async action and may not be accessible to PAT callers.

Get a customer

GET /v1/commerce/stores/{storeId}/customers/{customerId} retrieves a single customer by ID.

The following procedure reads a single customer by ID.

  1. Retrieve a single customer by its customerId:

    CUSTOMER_ID="<CUSTOMER_UUID>"
    
    curl -s "https://api.godaddy.com/v1/commerce/stores/${STORE_ID}/customers/${CUSTOMER_ID}" \
      -H "Authorization: Bearer $GODADDY_PAT"
  2. Review the response. The customer is returned wrapped in a customer object, alongside links. Use this GET to confirm that the emails/phones arrays and the latest updatedAt persisted after a create or update:

    {
      "customer": {
        "customerId": "<CUSTOMER_UUID>",
        "firstName": "<CUSTOMER_FIRST_NAME>",
        "lastName": "<CUSTOMER_LAST_NAME>",
        "emails": [{ "email": "<CUSTOMER_EMAIL_ADDRESS>", "default": true }],
        "phones": [{ "phone": "<CUSTOMER_PHONE_NUMBER>", "default": true }],
        "createdAt": "<ISO8601_CREATED_TIMESTAMP>",
        "updatedAt": "<ISO8601_UPDATED_TIMESTAMP>"
      },
      "links": []
    }

Update a customer

PATCH /v1/commerce/stores/{storeId}/customers/{customerId} updates a customer. The body is a nested customer object containing the fields you want to change plus the current updatedAt value for optimistic concurrency. Like create, the update is asynchronous and returns 202 Accepted.

updatedAt is required and must be current

Include the updatedAt you received from your most recent GET. If it is missing the API returns 422; if it is stale the API returns 202 but silently drops the update. After patching, re-GET the customer to confirm the change landed, and retry with the fresh updatedAt if it did not.

The following procedure updates the email address for a customer.

  1. GET the customer first (see Get a customer) and note its current updatedAt.

  2. Send the update as a nested customer object:

    CUSTOMER_ID="<CUSTOMER_UUID>"
    
    curl -s -X PATCH "https://api.godaddy.com/v1/commerce/stores/${STORE_ID}/customers/${CUSTOMER_ID}" \
      -H "Authorization: Bearer $GODADDY_PAT" \
      -H "Content-Type: application/json" \
      -d '{
        "customer": {
          "emails": [{ "email": "<NEW_EMAIL_ADDRESS>", "default": true }],
          "updatedAt": "<ISO8601_UPDATED_TIMESTAMP_FROM_GET>"
        }
      }'

Common errors

StatusMost likely causeNote
400Malformed JSON in the request body.
401PAT is missing or expired.Go to Authentication to generate a new token.
403Token doesn't include the required scope (commerce.customer:read, :create, or :update).
404Store ID or customer ID doesn't exist or isn't accessible with the provided token.
422Body failed schema validation — e.g. a missing updatedAt on update, or a wrong contact sub-field name.Response is a ValidationError with a fields array pinpointing each bad path.
429Rate limit exceeded.Honor the Retry-After header before retrying.

Associate a customer with an order

There is no dedicated "associate customer" endpoint. You link a customer to an order by setting both customerId and billing on the order via the Order subgraph GraphQL API (addDraftOrder or updateOrder mutations).

What is billing

The billing field is a nested object on the order that holds the buyer's contact information. It is not a separate API — you set it as part of the addDraftOrder or updateOrder mutation input. The fields are:

FieldTypeRequiredDescription
firstNameStringYesBuyer first name
lastNameStringYesBuyer last name
emailStringYesBuyer email address
phoneStringNoBuyer phone number
companyNameStringNoCompany name
addressObjectNoBilling address

The billing object drives the customer-service integration. When an order with billing transitions to OPEN, the system uses that data to increment the customer's orderCount and establish the order–customer relationship internally.

Always include billing

Setting only customerId creates a reference on the order but does not trigger the customer-service integration. The billing object (with at least firstName, lastName, and email) is what drives orderCount updates. Always provide both fields together.

Behavior by combination

What you providecustomerId on orderorderCount increments
customerId onlySetNo
customerId + billingSetYes
billing onlyNot setYes (customer auto-created)

When you provide only customerId, the order stores the reference but the customer service does not learn about the order. The customer's orderCount stays at 0.

When you provide both customerId and billing, the customer's orderCount increments when the order transitions to OPEN.

When you provide only billing, the system auto-creates a customer record from the billing info with orderCount set to 1. However, the order's customerId field is not backfilled — the auto-created customer's orderCount reflects the relationship, but querying the order returns customerId: null. There is no way to discover the link from the order side.

The following procedure creates a customer and associates it with a new order.

  1. Create the customer via REST (see above) and note the customerId.

  2. Create a draft order with both customerId and billing:

    curl -s "https://api.godaddy.com/v1/commerce/order-subgraph" \
      -H "Authorization: Bearer $GODADDY_PAT" \
      -H "x-store-id: $STORE_ID" \
      -H "Content-Type: application/json" \
      -d '{
        "query": "mutation($input: AddDraftOrderInput!) { addDraftOrder(input: $input) { id customerId billing { firstName lastName email } } }",
        "variables": {
          "input": {
            "context": {
              "storeId": "<STORE_ID>",
              "channelId": "<CHANNEL_ID>"
            },
            "customerId": "<CUSTOMER_UUID>",
            "billing": {
              "firstName": "<FIRST_NAME>",
              "lastName": "<LAST_NAME>",
              "email": "<EMAIL>",
              "phone": "<PHONE>"
            }
          }
        }
      }'
  3. Add line items with the addLineItemBySkuId mutation, then transition the order with openOrder. The customer's orderCount increments when the order reaches OPEN.

To attach a customer to an existing order that has not yet been opened, use updateOrder with the same two fields while the order is still in DRAFT. The orderCount increment only fires during the DRAFTOPEN transition — adding billing to an already-open order does not retroactively trigger it.

curl -s "https://api.godaddy.com/v1/commerce/order-subgraph" \
  -H "Authorization: Bearer $GODADDY_PAT" \
  -H "x-store-id: $STORE_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation($input: UpdateOrderInput!) { updateOrder(input: $input) { id customerId billing { firstName lastName email } } }",
    "variables": {
      "input": {
        "id": "<ORDER_ID>",
        "customerId": "<CUSTOMER_UUID>",
        "billing": {
          "firstName": "<FIRST_NAME>",
          "lastName": "<LAST_NAME>",
          "email": "<EMAIL>",
          "phone": "<PHONE>"
        },
        "context": {
          "storeId": "<STORE_ID>",
          "channelId": "<CHANNEL_ID>"
        }
      }
    }
  }'
FieldWhere to find it
ORDER_IDFrom addDraftOrder or orders query (e.g. Order_abc123)
CUSTOMER_UUIDFrom the rel: "customer" link in the create response
CHANNEL_IDFrom order.context.channelId on any existing order

context is required

The context object with both storeId and channelId is mandatory for addDraftOrder and updateOrder. Retrieve the channelId from the Store REST endpoint:

curl -s "https://api.godaddy.com/v1/commerce/stores/${STORE_ID}" \
  -H "Authorization: Bearer $GODADDY_PAT" | jq '.defaultChannelId'

The defaultChannelId field is available on every store, including new stores with no orders. The value is stable — use it for all orders in the store.

Agent & Automation Notes

Scopescommerce.customer:read, commerce.customer:create, commerce.customer:update
IdempotentNo
DestructiveNo
On failureGET operations are safe to retry. For POST and PATCH, verify the current customer state before retrying to avoid duplicate creates or conflicting updates.

Last updated on

How is this guide?

On this page