Summary and recommendation
The WooCommerce REST API (base: `https://{store_domain}/wp-json/wc/v3`) exposes a `/customers` resource that maps to WordPress users holding the `customer` role.
Authentication is Consumer Key/Secret via HTTP Basic Auth over HTTPS;
OAuth 1.0a is available only for non-HTTPS environments-this is not OAuth 2.0.
Always pin to `wc/v3` in the URL path;
`wc/v2` and `wc/v1` expose different field sets.
There is no native SCIM 2.0 endpoint;
SCIM provisioning requires third-party plugins or middleware.
For teams building against an identity graph, the stable join key is the WordPress user `id` (integer), which is returned on customer creation and used across the `/customers`, `/orders`, and `/wp/v2/users` endpoints.
API quick reference
| Has user API | Yes |
| Auth method | HTTP Basic Auth (Consumer Key as username, Consumer Secret as password) over HTTPS; OAuth 1.0a for non-HTTPS environments |
| Base URL | Official docs |
| SCIM available | No |
| SCIM plan required | N/A |
Authentication
Auth method: HTTP Basic Auth (Consumer Key as username, Consumer Secret as password) over HTTPS; OAuth 1.0a for non-HTTPS environments
Setup steps
- Log in to WordPress admin and navigate to WooCommerce > Settings > Advanced > REST API.
- Click 'Add key', enter a description, select the WordPress user, and choose permission level (Read, Write, or Read/Write).
- Click 'Generate API key' to receive the Consumer Key and Consumer Secret.
- For HTTPS: pass Consumer Key and Consumer Secret via HTTP Basic Auth header (Authorization: Basic base64(ck:cs)).
- For non-HTTPS: use OAuth 1.0a signing with the Consumer Key and Consumer Secret.
Required scopes
| Scope | Description | Required for |
|---|---|---|
| Read | Allows GET requests to all WooCommerce REST API endpoints. | Listing and retrieving customers |
| Write | Allows POST, PUT, PATCH, DELETE requests to all WooCommerce REST API endpoints. | Creating, updating, and deleting customers |
| Read/Write | Full access combining Read and Write permissions. | Full customer lifecycle management |
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| id | integer | Unique customer identifier (WordPress user ID). | read-only | read-only | Auto-assigned by WordPress. |
| string | Customer email address. | required | optional | Must be unique across the site. | |
| first_name | string | Customer first name. | optional | optional | |
| last_name | string | Customer last name. | optional | optional | |
| username | string | WordPress username. | optional | read-only | Auto-generated from email if not provided. Cannot be changed after creation via API. |
| password | string | Customer password. | optional | optional | Write-only; never returned in responses. |
| role | string | WordPress user role (e.g., 'customer', 'subscriber'). | read-only | read-only | Defaults to 'customer'. Not directly settable via WooCommerce REST API. |
| date_created | date-time | ISO 8601 date the customer was created (site timezone). | read-only | read-only | |
| date_created_gmt | date-time | ISO 8601 date the customer was created (UTC). | read-only | read-only | |
| date_modified | date-time | ISO 8601 date the customer was last modified (site timezone). | read-only | read-only | |
| billing | object | Billing address object (first_name, last_name, company, address_1, address_2, city, state, postcode, country, email, phone). | optional | optional | |
| shipping | object | Shipping address object (first_name, last_name, company, address_1, address_2, city, state, postcode, country). | optional | optional | |
| is_paying_customer | boolean | Whether the customer has completed at least one order. | read-only | read-only | |
| avatar_url | string | Gravatar URL for the customer. | read-only | read-only | Derived from email via Gravatar. |
| meta_data | array | Array of custom meta data objects ({id, key, value}). | optional | optional | Allows storing arbitrary key-value pairs on the customer record. |
| orders_count | integer | Number of orders placed by the customer. | read-only | read-only | |
| total_spent | string | Total amount spent by the customer (decimal string). | read-only | read-only |
Core endpoints
List customers
- Method: GET
- URL:
/wp-json/wc/v3/customers - Watch out for: Default role filter is 'customer'. Pass role=all to include all WordPress user roles. Guests (no account) are not returned.
Request example
GET /wp-json/wc/v3/customers?per_page=10&page=1&role=customer
Response example
[{"id":5,"email":"jane@example.com","first_name":"Jane","last_name":"Doe","username":"janedoe","role":"customer","orders_count":3,"total_spent":"150.00"}]
Retrieve a customer
- Method: GET
- URL:
/wp-json/wc/v3/customers/{id} - Watch out for: ID is the WordPress user ID, not an order or WooCommerce-specific ID.
Request example
GET /wp-json/wc/v3/customers/5
Response example
{"id":5,"email":"jane@example.com","first_name":"Jane","last_name":"Doe","billing":{"address_1":"123 Main St","city":"Austin","country":"US"}}
Create a customer
- Method: POST
- URL:
/wp-json/wc/v3/customers - Watch out for: email is required. If username is omitted, WooCommerce auto-generates one from the email. Password is write-only and never returned.
Request example
POST /wp-json/wc/v3/customers
{"email":"new@example.com","first_name":"John","last_name":"Smith","password":"securepass"}
Response example
{"id":12,"email":"new@example.com","first_name":"John","last_name":"Smith","username":"johnsmith","role":"customer"}
Update a customer
- Method: PUT
- URL:
/wp-json/wc/v3/customers/{id} - Watch out for: username cannot be changed after creation. Partial updates are supported (only supplied fields are changed).
Request example
PUT /wp-json/wc/v3/customers/12
{"first_name":"Jonathan","billing":{"phone":"555-1234"}}
Response example
{"id":12,"email":"new@example.com","first_name":"Jonathan","billing":{"phone":"555-1234"}}
Delete a customer
- Method: DELETE
- URL:
/wp-json/wc/v3/customers/{id} - Watch out for: force=true is required; the WooCommerce REST API does not support soft-delete (trash) for customers. This permanently deletes the WordPress user.
Request example
DELETE /wp-json/wc/v3/customers/12?force=true
Response example
{"id":12,"email":"new@example.com","first_name":"Jonathan","last_name":"Smith"}
Batch create/update/delete customers
- Method: POST
- URL:
/wp-json/wc/v3/customers/batch - Watch out for: Batch requests are limited to 100 objects per call per the WooCommerce docs. Exceeding this limit returns a 400 error.
Request example
POST /wp-json/wc/v3/customers/batch
{"create":[{"email":"a@x.com","first_name":"A"}],"update":[{"id":5,"last_name":"Updated"}],"delete":[12]}
Response example
{"create":[{"id":13,"email":"a@x.com"}],"update":[{"id":5,"last_name":"Updated"}],"delete":[{"id":12}]}
List customer downloads
- Method: GET
- URL:
/wp-json/wc/v3/customers/{id}/downloads - Watch out for: Returns downloadable product access records for the customer. Read-only endpoint.
Request example
GET /wp-json/wc/v3/customers/5/downloads
Response example
[{"download_id":"abc123","download_url":"https://...","product_id":42,"product_name":"eBook"}]
Retrieve customer orders (via orders endpoint)
- Method: GET
- URL:
/wp-json/wc/v3/orders - Watch out for: There is no dedicated /customers/{id}/orders sub-resource. Filter the /orders endpoint using the customer query parameter (WordPress user ID).
Request example
GET /wp-json/wc/v3/orders?customer=5
Response example
[{"id":101,"status":"completed","customer_id":5,"total":"49.99"}]
Rate limits, pagination, and events
Rate limits: WooCommerce itself does not impose API-level rate limits. Rate limiting is determined by the underlying WordPress hosting environment (server, PHP-FPM workers, web server config). No official rate-limit documentation exists from WooCommerce.
Rate-limit headers: No
Retry-After header: No
Rate-limit notes: Rate limits are host-dependent. Managed WordPress hosts (e.g., WP Engine, Kinsta) may enforce their own request throttling. WooCommerce docs do not specify rate-limit headers or Retry-After behavior.
Pagination method: offset
Default page size: 10
Max page size: 100
Pagination pointer: page / per_page
Webhooks available: Yes
Webhook notes: WooCommerce supports webhooks configurable via WooCommerce > Settings > Advanced > Webhooks or via the REST API (/wp-json/wc/v3/webhooks). Webhooks fire HTTP POST payloads to a configured URL on specified events.
Alternative event strategy: WordPress action hooks (e.g., woocommerce_new_customer, woocommerce_update_customer) can be used server-side for custom integrations.
Webhook events: customer.created, customer.updated, customer.deleted
SCIM API status
- SCIM available: No
- SCIM version: Not documented
- Plan required: N/A
- Endpoint: Not documented
Limitations:
- WooCommerce has no native SCIM 2.0 support.
- SCIM provisioning requires third-party plugins or middleware (e.g., IdP-specific connectors).
- No official WooCommerce SCIM endpoint exists.
Common scenarios
Three integration patterns cover the majority of customer lifecycle use cases:
Provisioning: POST to /wp-json/wc/v3/customers with at minimum {email, password}.
Capture the returned id immediately-it is the WordPress user ID and the durable identity graph anchor.
If the email already exists, the API returns a 400;
pre-check with GET /wp-json/wc/v3/customers?email={email} before writing.
Profile sync: Use PUT to /wp-json/wc/v3/customers/{id} for individual updates;
partial updates are supported.
For bulk operations, POST to /wp-json/wc/v3/customers/batch with an update array capped at 100 objects per call-larger sets must be split.
Critical caveat: username and role cannot be changed via the WooCommerce REST API.
Role changes require a separate call to the WordPress REST API (PUT /wp/v2/users/{id}) using admin-level application password credentials.
Event-driven triggers: Register a webhook via POST /wp-json/wc/v3/webhooks with topic: 'customer.created'.
Validate payloads using the X-WC-Webhook-Signature header (HMAC-SHA256).
Note that guest checkouts (customer_id=0) do not trigger customer.created and are not accessible via /customers at all.
Provision a new customer account
- Generate a Read/Write API key in WooCommerce > Settings > Advanced > REST API.
- POST to /wp-json/wc/v3/customers with at minimum {email, password}.
- Capture the returned id (WordPress user ID) for future reference.
- Optionally update billing/shipping address with a PUT to /wp-json/wc/v3/customers/{id}.
Watch out for: If the email already exists as a WordPress user, the API returns a 400 error ('Sorry, that email address is already used!'). Check for existing users first with GET /wp-json/wc/v3/customers?email={email}.
Sync customer profile updates from an external system
- Query the external system for changed user records.
- For each changed record, PUT to /wp-json/wc/v3/customers/{id} with only the changed fields.
- For bulk updates, use POST /wp-json/wc/v3/customers/batch with an 'update' array (max 100 per call).
- Handle 404 responses by creating the customer instead (POST /wp-json/wc/v3/customers).
Watch out for: username and role cannot be updated via the WooCommerce REST API. Role changes require the WordPress REST API (/wp/v2/users/{id}) with an admin-level application password.
Receive real-time notification on new customer registration
- Navigate to WooCommerce > Settings > Advanced > Webhooks and click 'Add webhook'.
- Set Topic to 'Customer created', enter the delivery URL, and set Status to 'Active'.
- Alternatively, create the webhook via API: POST /wp-json/wc/v3/webhooks with {name, topic:'customer.created', delivery_url, status:'active'}.
- Validate the incoming webhook payload using the X-WC-Webhook-Signature header (HMAC-SHA256 of the payload using the webhook secret).
Watch out for: Webhooks fire for registered customers only. Guest checkouts do not trigger customer.created. Webhook delivery failures are retried up to 5 times with exponential backoff; after 5 failures the webhook is disabled automatically.
Why building this yourself is a trap
Several behaviors in the WooCommerce API are non-obvious and will cause integration failures if not handled explicitly:
- Hard delete only:
DELETE /wp-json/wc/v3/customers/{id}requiresforce=trueand permanently destroys the underlying WordPress user. There is no soft-delete or trash state. Any identity graph reference to thatidbecomes a dangling pointer. - Rate limits are invisible: WooCommerce publishes no rate-limit headers and no
Retry-Afterbehavior. Throttling is entirely host-dependent (e.g., WP Engine, Kinsta enforce their own limits). Build retry logic with exponential backoff defensively, not reactively. - Pagination defaults are low: The default page size is 10; max is 100 via
per_page. The/customersendpoint defaults torole=customer-passrole=allto surface Shop Managers and Administrators, or they will be silently omitted from list results. - Webhook reliability: Failed webhook deliveries retry up to 5 times with exponential backoff; after 5 failures the webhook is automatically disabled. Monitor webhook status actively if your pipeline depends on real-time customer events.
Automate WooCommerce workflows without one-off scripts
Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.