How to manage a customer
View as MarkdownCreate, 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:readfor reads;commerce.customer:createor:updatefor writes) - your
storeIdFind 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.
-
Retrieve a list of customers:
curl -s "https://api.godaddy.com/v1/commerce/stores/${STORE_ID}/customers" \ -H "Authorization: Bearer $GODADDY_PAT" -
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 ascustomer.emails[0].email, notcustomer.email. Thelinksarray contains HATEOAS pagination cursors.Pagination
Pass
totalRequired=trueto includetotalItemsandtotalPagesin the response. The returnedlinksecho the current request (e.g. theselflink above reflects the page you fetched). To page forward, prefer thepageTokenfrom the previous response over incrementing thepageparam.
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.
-
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 }] } }' -
The call returns
202 Acceptedwith alinksarray — not the customer record. Read thecustomerIdfrom thehrefof the link whoserelis"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
customerIdis the last path segment of therel: "customer"href. GET that href to confirm the customer (and its contact details) persisted. Therel: "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.
-
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" -
Review the response. The customer is returned wrapped in a
customerobject, alongsidelinks. Use this GET to confirm that theemails/phonesarrays and the latestupdatedAtpersisted 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.
-
GET the customer first (see Get a customer) and note its current
updatedAt. -
Send the update as a nested
customerobject: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
| Status | Most likely cause | Note |
|---|---|---|
400 | Malformed JSON in the request body. | |
401 | PAT is missing or expired. | Go to Authentication to generate a new token. |
403 | Token doesn't include the required scope (commerce.customer:read, :create, or :update). | |
404 | Store ID or customer ID doesn't exist or isn't accessible with the provided token. | |
422 | Body 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. |
429 | Rate 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:
| Field | Type | Required | Description |
|---|---|---|---|
firstName | String | Yes | Buyer first name |
lastName | String | Yes | Buyer last name |
email | String | Yes | Buyer email address |
phone | String | No | Buyer phone number |
companyName | String | No | Company name |
address | Object | No | Billing 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 provide | customerId on order | orderCount increments |
|---|---|---|
customerId only | Set | No |
customerId + billing | Set | Yes |
billing only | Not set | Yes (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.
Recommended flow
The following procedure creates a customer and associates it with a new order.
-
Create the customer via REST (see above) and note the
customerId. -
Create a draft order with both
customerIdandbilling: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>" } } } }' -
Add line items with the
addLineItemBySkuIdmutation, then transition the order withopenOrder. The customer'sorderCountincrements when the order reachesOPEN.
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 DRAFT → OPEN 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>"
}
}
}
}'| Field | Where to find it |
|---|---|
ORDER_ID | From addDraftOrder or orders query (e.g. Order_abc123) |
CUSTOMER_UUID | From the rel: "customer" link in the create response |
CHANNEL_ID | From 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
commerce.customer:read, commerce.customer:create, commerce.customer:updateRelated
API References
Last updated on
How is this guide?