The Storefront API lets you create and manage customer accounts programmatically without needing to log in to Storefront Manager. This is useful if you have your own platform or control panel and want to automate customer provisioning when users sign up, sync customer records, or build tooling for your support team.
Note: DNS management via the API only works for domains using Storefront's default Shopco nameservers (a.ns.shopco.com, b.ns.shopco.com, c.ns.shopco.com). Domains using custom nameservers manage their own DNS outside of Storefront.
Before you begin
Requirements
- An active OpenSRS Storefront with API access enabled
- API credentials (Client ID and Client Secret) generated in Storefront Manager
- Your OpenSRS account balance above $10 to keep your Storefront active
Customer endpoints
Create a customer
Creates a new customer account under your reseller.
POST /v1/customer
Request fields
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
| first_name | string | Yes | Max 50 chars | Customer's first name |
| last_name | string | Yes | Max 50 chars | Customer's last name |
| string | Yes | Valid email format | Customer's email address | |
| username | string | Yes | 3–20 chars, [a-zA-Z0-9_-] only, unique per reseller | Login username |
| address1 | string | Yes | Max 255 chars | Street address |
| city | string | Yes | Max 100 chars | City |
| state | string | Yes | Full name, max 50 chars (e.g. Ontario) | State or province |
| postal_code | string | Yes | Validated against country | Postal or ZIP code |
| country | string | Yes | 2-letter ISO 3166-1 alpha-2 code (e.g. CA, US) | Country (e.g. CA) |
| phone | string | Yes | E.164 format, validated against country | Phone number — stored in normalized format (e.g. +1.4165550101) |
| send_email | boolean | No | Default: false | Send a welcome email to the customer |
| currency_code | string | No | Must be a supported currency code | Customer's billing currency (e.g. USD, CAD) — returns 400 if not recognized |
| external_user_id | string | No | Max 255 chars, no control characters | Your internal reference ID for this customer |
Notes:
- postal_code is validated against country at the database level.
- phone validation is country-aware.
Example request
{
"first_name": "Jane",
"last_name": "Doe",
"email": "jane.doe@example.com",
"username": "janedoe01",
"address1": "123 Main St",
"city": "Toronto",
"state": "Ontario",
"postal_code": "M5V 2T6",
"country": "CA",
"phone": "+1 416 555 0101",
"send_email": false,
"currency_code": "CAD",
"external_user_id": "cust-12345"
}Example cURL
curl -X POST "https://api.shopco.com/v1/customer" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"first_name": "Jane",
"last_name": "Doe",
"email": "jane.doe@example.com",
"username": "janedoe01",
"address1": "123 Main St",
"city": "Toronto",
"state": "Ontario",
"postal_code": "M5V 2T6",
"country": "CA",
"phone": "+1 416 555 0101",
"send_email": false,
"currency_code": "CAD",
"external_user_id": "cust-12345"
}'Success response
200 OK — the new customer's UUID, returned as a JSON string.
"8d9f0ef8-6045-4bb2-b473-f7f5c2dcf0a8"
Get a customer
Returns a single customer by ID.
GET /v1/customer/{customer_id}
Path parameters
| Parameter | Type | Description |
|---|---|---|
| customer_id | UUID | The customer's ID (returned by create) |
Example cURL
curl -X GET "https://api.shopco.com/v1/customer/8d9f0ef8-6045-4bb2-b473-f7f5c2dcf0a8" \ -H "Authorization: Bearer <access_token>"
Success response
200 OK — a customer object.
| Field | Type | Description |
|---|---|---|
| id | UUID | Customer's unique ID |
| first_name | string or null | First name |
| last_name | string or null | Last name |
| string | Email address | |
| username | string | Login username |
| status | string | Account status (active, suspended, etc.) |
| created_date | datetime or null | ISO 8601 timestamp of account creation |
| last_login_date | datetime or null | ISO 8601 timestamp of last login |
| phone | string or null | Phone number in normalized format |
| address1 | string or null | Street address |
| address2 | string or null | Address line 2 |
| address3 | string or null | Address line 3 |
| city | string or null | City |
| state | string or null | State or province |
| postal_code | string or null | Postal or ZIP code |
| country | string or null | 2-letter ISO country code |
| currency | object or null | { "code": "USD", "symbol": "$", "descr": "US Dollar" } |
| totp_enabled | boolean | Whether 2FA is enabled on the account |
| external_user_id | string or null | Your internal reference ID |
| stripe_customer_id | string or null | Stripe customer ID if a payment method is on file |
Example response
{
"id": "8d9f0ef8-6045-4bb2-b473-f7f5c2dcf0a8",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane.doe@example.com",
"username": "janedoe01",
"status": "active",
"created_date": "2026-04-01T10:00:00.000000Z",
"last_login_date": null,
"phone": "+1.4165550101",
"address1": "123 Main St",
"address2": null,
"address3": null,
"city": "Toronto",
"state": "Ontario",
"postal_code": "M5V 2T6",
"country": "CA",
"currency": {
"code": "CAD",
"symbol": "$",
"descr": "Canadian Dollar"
},
"totp_enabled": false,
"external_user_id": "cust-12345",
"stripe_customer_id": null
}Update a customer
Partially updates a customer. Only include the fields you want to change — omitted fields are left unchanged.
PATCH /v1/customer/{customer_id}
Path parameters
| Parameter | Type | Description |
|---|---|---|
| customer_id | UUID | The customer's ID |
Request fields
All fields are optional. At least one must be provided.
| Field | Type | Constraints | Description |
|---|---|---|---|
| first_name | string | Max 50 chars | First name |
| last_name | string | Max 50 chars | Last name |
| string | Valid email format | Email address | |
| address1 | string | Max 255 chars | Street address |
| city | string | Max 100 chars | City |
| state | string or null | Full name, max 50 chars (e.g. Ontario) | State or province |
| postal_code | string or null | Validated against country | Postal or ZIP code |
| country | string | 2-letter ISO code | Country |
| phone | string | E.164 format, validated against country | Phone number — if updating, include country in the same request or the existing country on the account is used. Returns 400 if neither is present. |
| currency_code | string | Must be a supported currency code | Billing currency |
| external_user_id | string | Max 255 chars, no control characters | Your internal reference ID |
Example request
{
"city": "Vancouver",
"state": "British Columbia",
"external_user_id": "cust-12345-updated"
}Example cURL
curl -X PATCH "https://api.shopco.com/v1/customer/8d9f0ef8-6045-4bb2-b473-f7f5c2dcf0a8" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"city": "Vancouver",
"state": "British Columbia",
"external_user_id": "cust-12345-updated"
}'Success response
200 OK — empty body.
Error responses
All error responses follow this structure:
{ "detail": "<message>" }
For field validation errors (Pydantic):
{
"detail": [
{
"type": "missing",
"loc": ["body", "first_name"],
"msg": "Field required",
"input": {}
}
]
}HTTP status codes
| Status | Meaning |
|---|---|
| 400 Bad Request | Invalid payload or constraint violation |
| 401 Unauthorized | Missing or invalid token |
| 404 Not Found | Customer not found |
| 409 Conflict | Username already exists for this reseller |
| 422 Unprocessable Entity | Field validation failed |
| 429 Too Many Requests | Rate limit exceeded — check Retry-After header |
| 500 Internal Server Error | Unexpected failure — contact support if this persists |
Related articles
- API DNS Management Guide — Manage DNS records for your customers' domains
Questions or issues with the API? Contact OpenSRS Support.
Was this article helpful? If not please submit a request here
How helpful was this article?
Thanks for your feedback!