SHOP DESKDevelopers
shopdeskbd.com

Customers

Customer records. Addresses are returned on the detail read only.

Paste a key and every snippet on this page switches from the placeholder to your key — and the Try it panel under each endpoint is ready to send. It is stored in this browser only and goes nowhere except, if you press Send, straight to the API host you pick there.

List customers

GET/ext/v1/customerscustomers:read

Addresses are on the detail read only — a page of 100 customers should not carry every address any of them ever saved. search finds a customer by name, email or phone, the phone in any Bangladeshi form; phone finds only the customer whose phone is exactly that number.

Query parameters

NameTypeDescription
limitnumberdefault 25max 100Page size.
starting_afterstringReturn the page AFTER this object id (the previous page's next_cursor).
ending_beforestringReturn the page BEFORE this object id.
sortstringdefault -created_atNewest first by default. Only created_at is sortable — a cursor over a mutable key (like updated_at) cannot page reliably. Use updated_after to sync changes.created_at-created_at
store_idstringRestrict to one store. Required breadth control for company-scoped keys; on a store-scoped key it must match the key's own store.
searchstringMatch on name, phone or email. A phone matches in any Bangladeshi form: +8801712345678, 8801712345678 and 01712345678 find the same customer, separators ignored — the way phones are stored.
phonestringOnly customers whose phone IS this number — an exact match, not a search: no name or email can match it. Any Bangladeshi mobile spelling (+8801712345678, 8801712345678, 01712345678); anything that is not a valid mobile is a 422.

Request

export SHOPDESK_API_KEY="shopdesk_sk_YOUR_API_KEY"

curl -sS "https://api.shopdeskbd.com/ext/v1/customers?limit=25" \
  -H "Authorization: Bearer $SHOPDESK_API_KEY"
Try itruns from your browser
GEThttps://api.shopdeskbd.com/ext/v1/customers?search=01712345678&phone=01712345678

Stored in this browser only and never sent anywhere except to the API host you picked above — these pages are static files with no server behind them.

Query parameters

Blank fields are left out of the request.

Paste a key above to enable Send.

Responses

  • 200A cursor page of customers.
  • 401Missing/invalid API key, revoked or expired key, plan without API access, or a dead store.
  • 403The key's scopes do not cover this endpoint.
  • 422Validation failed — error.fields maps each offending field to its messages.
  • 429Rate limit exceeded for this key. Honor Retry-After and the X-RateLimit-* headers.

Every failure uses the one error envelope — Errors lists each code and what to do with it.

Example 200 response
{
  "data": [
    {
      "id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
      "store_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
      "full_name": "Rafiqul Islam",
      "email": null,
      "phone": "01712345678",
      "status": "active",
      "type": "manual",
      "gender": null,
      "created_at": "2026-08-11T10:00:00.000Z",
      "updated_at": "2026-08-11T10:00:00.000Z"
    }
  ],
  "meta": {
    "has_more": true,
    "next_cursor": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001"
  }
}

Create a customer

POST/ext/v1/customerscustomers:write

Phones are canonicalized (+880… spellings collapse to 01…) and unique per store, as is email — a duplicate is a 409. API-created customers are always type manual.

Headers

NameTypeDescription
Idempotency-KeystringOptional, but honored: send it to make retries of this request safe.

Body parameters

NameTypeDescription
store_iduuidTarget store. REQUIRED with a company-scoped key; with a store-scoped key it may only repeat the key's own store.
full_namerequiredstring—
phonestringBangladeshi mobile, any accepted spelling — stored canonical (01712345678). Unique per store.
emailstring—
statusstringdefault active—activeinactiveblocked
genderstring—malefemale

Request

export SHOPDESK_API_KEY="shopdesk_sk_YOUR_API_KEY"

curl -sS -X POST "https://api.shopdeskbd.com/ext/v1/customers" \
  -H "Authorization: Bearer $SHOPDESK_API_KEY" \
  -H "Idempotency-Key: 3f2b8c1e-9d4a-4e7b-8a6f-2c5d1e0b9a47" \
  -H "Content-Type: application/json" \
  -d '{
  "full_name": "Rafiqul Islam",
  "phone": "01712345678"
}'
Try itruns from your browser
POSThttps://api.shopdeskbd.com/ext/v1/customers

Stored in this browser only and never sent anywhere except to the API host you picked above — these pages are static files with no server behind them.

Valid JSON
Idempotency-Keyoptional
generating…

A new value is generated whenever you edit this request, and kept while you do not — so sending twice without changing anything is a real retry and comes back Idempotent-Replayed: true instead of writing again.

Paste a key above to enable Send.

Responses

  • 201The created customer, addresses included.
  • 400An Idempotency-Key header was sent but is empty or longer than 255 characters (VALIDATION_ERROR; error.fields names the header).
  • 401Missing/invalid API key, revoked or expired key, plan without API access, or a dead store.
  • 403The key's scopes do not cover this endpoint.
  • 409A customer with this phone or email already exists; or a request with this Idempotency-Key is still in flight (IDEMPOTENCY_IN_FLIGHT) — retry once it has finished.
  • 422Validation failed — error.fields maps each offending field to its messages.
  • 429Rate limit exceeded for this key. Honor Retry-After and the X-RateLimit-* headers.

Every failure uses the one error envelope — Errors lists each code and what to do with it.

Example 200 response
{
  "id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
  "store_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
  "full_name": "Rafiqul Islam",
  "email": null,
  "phone": "01712345678",
  "status": "active",
  "type": "manual",
  "gender": null,
  "created_at": "2026-08-11T10:00:00.000Z",
  "updated_at": "2026-08-11T10:00:00.000Z",
  "addresses": [
    {
      "id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
      "label": "Home",
      "recipient_name": "Rafiqul Islam",
      "recipient_phone": "01712345678",
      "address_line": "House 12, Road 5",
      "city": "Dhaka",
      "area": "Dhanmondi",
      "postal_code": "1209",
      "is_default": true,
      "created_at": "2026-08-11T10:00:00.000Z",
      "updated_at": "2026-08-11T10:00:00.000Z"
    }
  ],
  "stats": {
    "orders_count": 4,
    "total_spent": "1250.00",
    "last_order_at": "2026-08-11T10:00:00.000Z",
    "returned_count": 1
  }
}

Get a customer by id, with their addresses

GET/ext/v1/customers/{id}customers:read

The customer plus every saved address, default address first. Add ?expand=stats for their order history (order count, total spent, last order, returns) — that needs the orders:read scope as well, and stats is simply omitted for a key without it.

Path parameters

NameTypeDescription
idrequireduuidThe customer id.

Query parameters

NameTypeDescription
store_iduuidRestrict the lookup to one store. Breadth control for company-scoped keys; on a store-scoped key it must match the key's own store.
expandstring[]Include stats (order count, total spent, last order, returns). Needs the orders:read scope too; omitted from the response when the key lacks it.

Request

export SHOPDESK_API_KEY="shopdesk_sk_YOUR_API_KEY"

curl -sS "https://api.shopdeskbd.com/ext/v1/customers/REPLACE_WITH_ID?expand=stats" \
  -H "Authorization: Bearer $SHOPDESK_API_KEY"
Try itruns from your browser
GEThttps://api.shopdeskbd.com/ext/v1/customers/5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001

Stored in this browser only and never sent anywhere except to the API host you picked above — these pages are static files with no server behind them.

Path parameters

Query parameters

Blank fields are left out of the request.

Paste a key above to enable Send.

Responses

  • 200The customer.
  • 401Missing/invalid API key, revoked or expired key, plan without API access, or a dead store.
  • 403The key's scopes do not cover this endpoint.
  • 404Customer not found.
  • 422Validation failed — error.fields maps each offending field to its messages.
  • 429Rate limit exceeded for this key. Honor Retry-After and the X-RateLimit-* headers.

Every failure uses the one error envelope — Errors lists each code and what to do with it.

Example 200 response
{
  "id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
  "store_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
  "full_name": "Rafiqul Islam",
  "email": null,
  "phone": "01712345678",
  "status": "active",
  "type": "manual",
  "gender": null,
  "created_at": "2026-08-11T10:00:00.000Z",
  "updated_at": "2026-08-11T10:00:00.000Z",
  "addresses": [
    {
      "id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
      "label": "Home",
      "recipient_name": "Rafiqul Islam",
      "recipient_phone": "01712345678",
      "address_line": "House 12, Road 5",
      "city": "Dhaka",
      "area": "Dhanmondi",
      "postal_code": "1209",
      "is_default": true,
      "created_at": "2026-08-11T10:00:00.000Z",
      "updated_at": "2026-08-11T10:00:00.000Z"
    }
  ],
  "stats": {
    "orders_count": 4,
    "total_spent": "1250.00",
    "last_order_at": "2026-08-11T10:00:00.000Z",
    "returned_count": 1
  }
}

Update a customer

PATCH/ext/v1/customers/{id}customers:write

Same rules as creation (canonical phone, per-store uniqueness). The seeded walk-in system record cannot be edited through any surface, this one included.

Path parameters

NameTypeDescription
idrequireduuidThe customer id.

Headers

NameTypeDescription
Idempotency-KeystringOptional, but honored: send it to make retries of this request safe.

Body parameters

NameTypeDescription
store_iduuidTarget store. REQUIRED with a company-scoped key; with a store-scoped key it may only repeat the key's own store.
full_namestring—
phonestring—
emailstring—
statusstring—activeinactiveblocked
genderstring—malefemale

Request

export SHOPDESK_API_KEY="shopdesk_sk_YOUR_API_KEY"

curl -sS -X PATCH "https://api.shopdeskbd.com/ext/v1/customers/REPLACE_WITH_ID" \
  -H "Authorization: Bearer $SHOPDESK_API_KEY" \
  -H "Idempotency-Key: 3f2b8c1e-9d4a-4e7b-8a6f-2c5d1e0b9a47" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "rafiq@example.com"
}'
Try itruns from your browser
PATCHhttps://api.shopdeskbd.com/ext/v1/customers/5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001

Stored in this browser only and never sent anywhere except to the API host you picked above — these pages are static files with no server behind them.

Path parameters

Valid JSON
Idempotency-Keyoptional
generating…

A new value is generated whenever you edit this request, and kept while you do not — so sending twice without changing anything is a real retry and comes back Idempotent-Replayed: true instead of writing again.

Paste a key above to enable Send.

Responses

  • 200The updated customer, addresses included.
  • 400An Idempotency-Key header was sent but is empty or longer than 255 characters (VALIDATION_ERROR; error.fields names the header).
  • 401Missing/invalid API key, revoked or expired key, plan without API access, or a dead store.
  • 403The key's scopes do not cover this endpoint.
  • 404Customer not found.
  • 409A customer with this phone or email already exists; or a request with this Idempotency-Key is still in flight (IDEMPOTENCY_IN_FLIGHT) — retry once it has finished.
  • 422Validation failed — error.fields maps each offending field to its messages.
  • 429Rate limit exceeded for this key. Honor Retry-After and the X-RateLimit-* headers.

Every failure uses the one error envelope — Errors lists each code and what to do with it.

Example 200 response
{
  "id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
  "store_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
  "full_name": "Rafiqul Islam",
  "email": null,
  "phone": "01712345678",
  "status": "active",
  "type": "manual",
  "gender": null,
  "created_at": "2026-08-11T10:00:00.000Z",
  "updated_at": "2026-08-11T10:00:00.000Z",
  "addresses": [
    {
      "id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
      "label": "Home",
      "recipient_name": "Rafiqul Islam",
      "recipient_phone": "01712345678",
      "address_line": "House 12, Road 5",
      "city": "Dhaka",
      "area": "Dhanmondi",
      "postal_code": "1209",
      "is_default": true,
      "created_at": "2026-08-11T10:00:00.000Z",
      "updated_at": "2026-08-11T10:00:00.000Z"
    }
  ],
  "stats": {
    "orders_count": 4,
    "total_spent": "1250.00",
    "last_order_at": "2026-08-11T10:00:00.000Z",
    "returned_count": 1
  }
}