Orders
Orders with their totals, status and payment state. Compact by default; expand items and the customer when you need them.
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 orders
/ext/v1/ordersorders:readCompact by default. Add ?expand=customer,items for the full object. updated_after is the sync filter — it catches orders placed before your last poll but changed since.
Query parameters
| Name | Type | Description |
|---|---|---|
limit | numberdefault 25max 100 | Page size. |
starting_after | string | Return the page AFTER this object id (the previous page's next_cursor). |
ending_before | string | Return the page BEFORE this object id. |
sort | stringdefault -created_at | Newest 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_id | string | Restrict to one store. Required breadth control for company-scoped keys; on a store-scoped key it must match the key's own store. |
status | string | Filter to one of the values below.pendingfollow_upconfirmedprocessingready_to_shipin_transitdeliveredreturnedfailed_deliverycancelledholdspam |
payment_status | string | Filter to one of the values below.unpaidpartially_paidpaidrefunded |
fulfillment_status | string | Filter to one of the values below.unfulfilledpartially_fulfilledfulfilledreturned |
channel | string | Sales channel SLUG (the stable per-store key), not its id. |
created_after | date-time | ISO-8601 timestamp. Inclusive lower bound. |
created_before | date-time | ISO-8601 timestamp. Exclusive upper bound. |
updated_after | date-time | Only orders changed since this instant. THE sync filter: an order placed last month and confirmed this morning is exactly the row a created_after poll would miss. |
follow_up_before | date-time | Only orders with a follow-up (call-back) scheduled BEFORE this instant — pass now for the overdue call list. Orders with no follow-up never match. |
follow_up_after | date-time | Only orders with a follow-up scheduled AFTER this instant. Combine with follow_up_before for a window (today, this week). |
assignee_id | uuid | Only orders assigned to this staff member (the order's assignee.id). |
customer_id | uuid | Only this customer's orders — their order history. |
search | string | Match on order number, customer name or customer phone. A phone matches in any Bangladeshi form: +8801712345678, 8801712345678 and 01712345678 find the same orders, separators ignored. |
expand | string[] | Include related objects. Allowed: customer, items. Comma-separated (customer,items), one level. Omitted by default so a sync walking pages stays cheap. |
Request
export SHOPDESK_API_KEY="shopdesk_sk_YOUR_API_KEY"
curl -sS "https://api.shopdeskbd.com/ext/v1/orders?limit=25&updated_after=2026-08-01T00%3A00%3A00Z&expand=customer%2Citems" \
-H "Authorization: Bearer $SHOPDESK_API_KEY"const url = new URL("https://api.shopdeskbd.com/ext/v1/orders");
Object.entries({
limit: "25",
updated_after: "2026-08-01T00:00:00Z",
expand: "customer,items",
}).forEach(([key, value]) => url.searchParams.set(key, value));
const response = await fetch(url, {
headers: {
Authorization: `Bearer ${process.env.SHOPDESK_API_KEY}`,
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.code}: ${error.message} [${error.request_id}]`);
}
const { data, meta } = await response.json();import os
import requests
response = requests.get(
"https://api.shopdeskbd.com/ext/v1/orders",
params={
"limit": "25",
"updated_after": "2026-08-01T00:00:00Z",
"expand": "customer,items",
},
headers={
"Authorization": f"Bearer {os.environ['SHOPDESK_API_KEY']}",
},
timeout=30,
)
if not response.ok:
error = response.json()["error"]
raise RuntimeError(f"{error['code']}: {error['message']}")
page = response.json()
rows, meta = page["data"], page["meta"]<?php
$key = getenv('SHOPDESK_API_KEY');
$ch = curl_init('https://api.shopdeskbd.com/ext/v1/orders?limit=25&updated_after=2026-08-01T00%3A00%3A00Z&expand=customer%2Citems');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $key],
CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
$response = json_decode($body, true);
if ($status >= 400) {
throw new RuntimeException("{$response['error']['code']}: {$response['error']['message']}");
}
$rows = $response['data'];
$meta = $response['meta'];https://api.shopdeskbd.com/ext/v1/orders?channel=facebookStored 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 orders.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.fieldsmaps each offending field to its messages.429Rate limit exceeded for this key. HonorRetry-Afterand theX-RateLimit-*headers.
Every failure uses the one error envelope — Errors lists each code and what to do with it.
{
"data": [
{
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"store_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"number": "ORD-20260811-1042",
"source": "api",
"channel": {
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"name": "Facebook",
"slug": "facebook",
"type": "facebook"
},
"customer_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"location_id": null,
"status": "pending",
"payment_status": "unpaid",
"fulfillment_status": "unfulfilled",
"subtotal": "1250.00",
"discount_amount": "1250.00",
"shipping_charge": "1250.00",
"tax_amount": "1250.00",
"total_amount": "1250.00",
"paid_amount": "1250.00",
"due_amount": "1250.00",
"refunded_amount": "1250.00",
"shipping_address": null,
"coupon": null,
"custom_fields": null,
"note": null,
"follow_up_at": "2026-08-11T10:00:00.000Z",
"follow_up_note": "Call after salary day.",
"assignee": {
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"name": "Nusrat Jahan"
},
"delivered_at": "2026-08-11T10:00:00.000Z",
"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 an order
/ext/v1/ordersorders:writeRuns the SAME order-creation core as the dashboard and storefront: availability-checked stock reservation, coupon engine, totals math and plan-quota metering are all inherited, never re-implemented. Lines reference variants by id or SKU; the customer is an existing id or a find-or-create by phone. Price overrides are honored — this is a trusted-merchant surface. Company-scoped keys must send store_id.
Headers
| Name | Type | Description |
|---|---|---|
Idempotency-Keyrequired | string | REQUIRED. A unique value per logical request (a UUID is ideal); reuse it verbatim when retrying. A retry replays the original response with Idempotent-Replayed: true instead of running twice. |
Body parameters
| Name | Type | Description |
|---|---|---|
store_id | uuid | Target store. REQUIRED with a company-scoped key; with a store-scoped key it may only repeat the key's own store. |
channel | string | A sales-channel SLUG for attribution. Defaults to the store's manual channel (Decision Q11 — tagging is optional, never forced). |
location_id | uuid | Location (warehouse) to allocate stock from. Defaults to the company's default location — the admin-desk rule. |
customer_id | uuid | An existing customer. Provide this OR customer. |
customer | CreateOrderCustomerDto | Find-or-create by phone. Provide this OR customer_id. |
itemsrequired | CreateOrderLineDto[] | — |
shipping_address | object | Free-form shipping address object, stored verbatim. |
shipping_charge | number | Delivery charge as YOUR system computed it (trusted surface). A free-shipping coupon still zeroes it. Default 0. |
tax_amount | number | — |
coupon_code | string | Priced and redeemed by the same engine as every other surface; an unusable code fails the order rather than mispricing it. |
note | string | — |
payment | CreateOrderPaymentDto | An upfront settled payment (like the admin desk's "paid amount"). Omit for an unpaid order; record later payments via POST /v1/orders/{id}/payments. |
customer fields
| Name | Type | Description |
|---|---|---|
phonerequired | string | Bangladeshi mobile, any accepted spelling — stored canonical. THE find-or-create match key. |
full_name | string | Required when the phone matches no existing customer (a new record needs a name); ignored when one exists — a sale never silently renames a customer. |
email | string | — |
items[] fields
| Name | Type | Description |
|---|---|---|
variant_id | uuid | The variant to sell. Provide this OR sku. |
sku | string | Resolve the variant by SKU instead of id. |
quantityrequired | number | — |
unit_price | number | Override the regular unit price (trusted surface). Omitted = the variant's current catalog price — the admin-desk rule, verbatim. |
discount_price | number | Override the discounted unit price. Only honored when it is a REAL discount (above 0, below the regular price) — same rule as the desk. |
payment fields
| Name | Type | Description |
|---|---|---|
payment_method_id | uuid | One of the store's payment methods (must be active). |
amountrequired | number | — |
transaction_id | string | — |
Request
export SHOPDESK_API_KEY="shopdesk_sk_YOUR_API_KEY"
curl -sS -X POST "https://api.shopdeskbd.com/ext/v1/orders" \
-H "Authorization: Bearer $SHOPDESK_API_KEY" \
-H "Idempotency-Key: 3f2b8c1e-9d4a-4e7b-8a6f-2c5d1e0b9a47" \
-H "Content-Type: application/json" \
-d '{
"channel": "facebook",
"customer": {
"phone": "01712345678",
"full_name": "Rafiqul Islam"
},
"items": [
{
"sku": "TSHIRT-RED-M",
"quantity": 2
}
],
"shipping_charge": 120,
"note": "Deliver after 6pm."
}'const url = new URL("https://api.shopdeskbd.com/ext/v1/orders");
const response = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SHOPDESK_API_KEY}`,
"Idempotency-Key": "3f2b8c1e-9d4a-4e7b-8a6f-2c5d1e0b9a47",
"Content-Type": "application/json",
},
body: JSON.stringify({
"channel": "facebook",
"customer": {
"phone": "01712345678",
"full_name": "Rafiqul Islam"
},
"items": [
{
"sku": "TSHIRT-RED-M",
"quantity": 2
}
],
"shipping_charge": 120,
"note": "Deliver after 6pm."
}),
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.code}: ${error.message} [${error.request_id}]`);
}
const object = await response.json();import os
import requests
payload = {
"channel": "facebook",
"customer": {
"phone": "01712345678",
"full_name": "Rafiqul Islam",
},
"items": [
{
"sku": "TSHIRT-RED-M",
"quantity": 2,
},
],
"shipping_charge": 120,
"note": "Deliver after 6pm.",
}
response = requests.post(
"https://api.shopdeskbd.com/ext/v1/orders",
json=payload,
headers={
"Authorization": f"Bearer {os.environ['SHOPDESK_API_KEY']}",
"Idempotency-Key": "3f2b8c1e-9d4a-4e7b-8a6f-2c5d1e0b9a47",
},
timeout=30,
)
if not response.ok:
error = response.json()["error"]
raise RuntimeError(f"{error['code']}: {error['message']}")
obj = response.json()<?php
$key = getenv('SHOPDESK_API_KEY');
$payload = json_encode([
'channel' => 'facebook',
'customer' => [
'phone' => '01712345678',
'full_name' => 'Rafiqul Islam',
],
'items' => [
[
'sku' => 'TSHIRT-RED-M',
'quantity' => 2,
],
],
'shipping_charge' => 120,
'note' => 'Deliver after 6pm.',
]);
$ch = curl_init('https://api.shopdeskbd.com/ext/v1/orders');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $key, 'Idempotency-Key: 3f2b8c1e-9d4a-4e7b-8a6f-2c5d1e0b9a47', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => $payload,
CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
$response = json_decode($body, true);
if ($status >= 400) {
throw new RuntimeException("{$response['error']['code']}: {$response['error']['message']}");
}https://api.shopdeskbd.com/ext/v1/ordersStored 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.
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 order, in the same shape asGET /v1/orders/{id}with customer and items expanded.400The requiredIdempotency-Keyheader is missing, empty, or longer than 255 characters (VALIDATION_ERROR;error.fieldsnames the header), or a line cannot be reserved from stock (INSUFFICIENT_STOCK;error.fields.itemsnames it).401Missing/invalid API key, revoked or expired key, plan without API access, or a dead store.403Missing scope, or the plan order quota is exhausted (plan_limit_reached).409A request with thisIdempotency-Keyis still in flight (IDEMPOTENCY_IN_FLIGHT) — retry once it has finished.422Validation failed —error.fieldsmaps each offending field to its messages.429Rate limit exceeded for this key. HonorRetry-Afterand theX-RateLimit-*headers.
Every failure uses the one error envelope — Errors lists each code and what to do with it.
{
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"store_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"number": "ORD-20260811-1042",
"source": "api",
"channel": {
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"name": "Facebook",
"slug": "facebook",
"type": "facebook"
},
"customer_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"location_id": null,
"status": "pending",
"payment_status": "unpaid",
"fulfillment_status": "unfulfilled",
"subtotal": "1250.00",
"discount_amount": "1250.00",
"shipping_charge": "1250.00",
"tax_amount": "1250.00",
"total_amount": "1250.00",
"paid_amount": "1250.00",
"due_amount": "1250.00",
"refunded_amount": "1250.00",
"shipping_address": null,
"coupon": null,
"custom_fields": null,
"note": null,
"follow_up_at": "2026-08-11T10:00:00.000Z",
"follow_up_note": "Call after salary day.",
"assignee": {
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"name": "Nusrat Jahan"
},
"delivered_at": "2026-08-11T10:00:00.000Z",
"created_at": "2026-08-11T10:00:00.000Z",
"updated_at": "2026-08-11T10:00:00.000Z",
"items": [
{
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"product_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"variant_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"product_name": "Classic Cotton T-Shirt",
"variant_name": "Red / M",
"sku": "TSHIRT-RED-M",
"quantity": 2,
"unit_price": "1250.00",
"discount_price": "1250.00",
"subtotal": "1250.00"
}
],
"customer": {
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"full_name": "Rafiqul Islam",
"email": null,
"phone": "01712345678",
"type": "manual",
"status": "active"
}
}Get an order by id
/ext/v1/orders/{id}orders:readAdd ?expand=customer,items for the related objects.
Path parameters
| Name | Type | Description |
|---|---|---|
idrequired | uuid | The order id. |
Query parameters
| Name | Type | Description |
|---|---|---|
expand | string[] | Include related objects. Allowed: customer, items. Comma-separated (customer,items), one level. Omitted by default so a sync walking pages stays cheap. |
store_id | string | Restrict the lookup to one store (company-scoped keys). |
Request
export SHOPDESK_API_KEY="shopdesk_sk_YOUR_API_KEY"
curl -sS "https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID?expand=customer%2Citems" \
-H "Authorization: Bearer $SHOPDESK_API_KEY"const url = new URL("https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID");
Object.entries({
expand: "customer,items",
}).forEach(([key, value]) => url.searchParams.set(key, value));
const response = await fetch(url, {
headers: {
Authorization: `Bearer ${process.env.SHOPDESK_API_KEY}`,
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.code}: ${error.message} [${error.request_id}]`);
}
const object = await response.json();import os
import requests
response = requests.get(
"https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID",
params={
"expand": "customer,items",
},
headers={
"Authorization": f"Bearer {os.environ['SHOPDESK_API_KEY']}",
},
timeout=30,
)
if not response.ok:
error = response.json()["error"]
raise RuntimeError(f"{error['code']}: {error['message']}")
obj = response.json()<?php
$key = getenv('SHOPDESK_API_KEY');
$ch = curl_init('https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID?expand=customer%2Citems');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $key],
CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
$response = json_decode($body, true);
if ($status >= 400) {
throw new RuntimeException("{$response['error']['code']}: {$response['error']['message']}");
}https://api.shopdeskbd.com/ext/v1/orders/5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001Stored 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 order.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.404Order not found.422Validation failed —error.fieldsmaps each offending field to its messages.429Rate limit exceeded for this key. HonorRetry-Afterand theX-RateLimit-*headers.
Every failure uses the one error envelope — Errors lists each code and what to do with it.
{
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"store_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"number": "ORD-20260811-1042",
"source": "api",
"channel": {
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"name": "Facebook",
"slug": "facebook",
"type": "facebook"
},
"customer_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"location_id": null,
"status": "pending",
"payment_status": "unpaid",
"fulfillment_status": "unfulfilled",
"subtotal": "1250.00",
"discount_amount": "1250.00",
"shipping_charge": "1250.00",
"tax_amount": "1250.00",
"total_amount": "1250.00",
"paid_amount": "1250.00",
"due_amount": "1250.00",
"refunded_amount": "1250.00",
"shipping_address": null,
"coupon": null,
"custom_fields": null,
"note": null,
"follow_up_at": "2026-08-11T10:00:00.000Z",
"follow_up_note": "Call after salary day.",
"assignee": {
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"name": "Nusrat Jahan"
},
"delivered_at": "2026-08-11T10:00:00.000Z",
"created_at": "2026-08-11T10:00:00.000Z",
"updated_at": "2026-08-11T10:00:00.000Z",
"items": [
{
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"product_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"variant_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"product_name": "Classic Cotton T-Shirt",
"variant_name": "Red / M",
"sku": "TSHIRT-RED-M",
"quantity": 2,
"unit_price": "1250.00",
"discount_price": "1250.00",
"subtotal": "1250.00"
}
],
"customer": {
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"full_name": "Rafiqul Islam",
"email": null,
"phone": "01712345678",
"type": "manual",
"status": "active"
}
}Update an order's note and follow-up
/ext/v1/orders/{id}orders:writeThe call-desk edit: the order note and the follow-up (when to call the customer back, and why). Legal in ANY status, exactly like the dashboard's order-details edit, and it runs the same code: nothing about the money, lines or stock moves. null clears a field; an omitted field is left alone; send at least one. Emits order.updated with data.previous holding the old values when something actually changed.
Path parameters
| Name | Type | Description |
|---|---|---|
idrequired | uuid | The order id. |
Headers
| Name | Type | Description |
|---|---|---|
Idempotency-Key | string | Optional, but honored: send it to make retries of this request safe. |
Body parameters
| Name | Type | Description |
|---|---|---|
store_id | uuid | Target store. REQUIRED with a company-scoped key; with a store-scoped key it may only repeat the key's own store. |
note | string | The order note. null clears it. |
follow_up_at | date-time | When to call the customer back (ISO 8601). null clears the follow-up. |
follow_up_note | string | Why the call-back is needed. null clears it. |
Request
export SHOPDESK_API_KEY="shopdesk_sk_YOUR_API_KEY"
curl -sS -X PATCH "https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID" \
-H "Authorization: Bearer $SHOPDESK_API_KEY" \
-H "Idempotency-Key: 3f2b8c1e-9d4a-4e7b-8a6f-2c5d1e0b9a47" \
-H "Content-Type: application/json" \
-d '{
"follow_up_at": "2026-10-02T10:00:00.000Z",
"follow_up_note": "Call after salary day."
}'const url = new URL("https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID");
const response = await fetch(url, {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.SHOPDESK_API_KEY}`,
"Idempotency-Key": "3f2b8c1e-9d4a-4e7b-8a6f-2c5d1e0b9a47",
"Content-Type": "application/json",
},
body: JSON.stringify({
"follow_up_at": "2026-10-02T10:00:00.000Z",
"follow_up_note": "Call after salary day."
}),
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.code}: ${error.message} [${error.request_id}]`);
}
const object = await response.json();import os
import requests
payload = {
"follow_up_at": "2026-10-02T10:00:00.000Z",
"follow_up_note": "Call after salary day.",
}
response = requests.patch(
"https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID",
json=payload,
headers={
"Authorization": f"Bearer {os.environ['SHOPDESK_API_KEY']}",
"Idempotency-Key": "3f2b8c1e-9d4a-4e7b-8a6f-2c5d1e0b9a47",
},
timeout=30,
)
if not response.ok:
error = response.json()["error"]
raise RuntimeError(f"{error['code']}: {error['message']}")
obj = response.json()<?php
$key = getenv('SHOPDESK_API_KEY');
$payload = json_encode([
'follow_up_at' => '2026-10-02T10:00:00.000Z',
'follow_up_note' => 'Call after salary day.',
]);
$ch = curl_init('https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $key, 'Idempotency-Key: 3f2b8c1e-9d4a-4e7b-8a6f-2c5d1e0b9a47', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => $payload,
CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
$response = json_decode($body, true);
if ($status >= 400) {
throw new RuntimeException("{$response['error']['code']}: {$response['error']['message']}");
}https://api.shopdeskbd.com/ext/v1/orders/5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001Stored 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
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 order (customer and items expanded).400AnIdempotency-Keyheader was sent but is empty or longer than 255 characters (VALIDATION_ERROR;error.fieldsnames 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.404Order not found.409A request with thisIdempotency-Keyis still in flight (IDEMPOTENCY_IN_FLIGHT) — retry once it has finished.422Validation failed —error.fieldsmaps each offending field to its messages.429Rate limit exceeded for this key. HonorRetry-Afterand theX-RateLimit-*headers.
Every failure uses the one error envelope — Errors lists each code and what to do with it.
{
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"store_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"number": "ORD-20260811-1042",
"source": "api",
"channel": {
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"name": "Facebook",
"slug": "facebook",
"type": "facebook"
},
"customer_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"location_id": null,
"status": "pending",
"payment_status": "unpaid",
"fulfillment_status": "unfulfilled",
"subtotal": "1250.00",
"discount_amount": "1250.00",
"shipping_charge": "1250.00",
"tax_amount": "1250.00",
"total_amount": "1250.00",
"paid_amount": "1250.00",
"due_amount": "1250.00",
"refunded_amount": "1250.00",
"shipping_address": null,
"coupon": null,
"custom_fields": null,
"note": null,
"follow_up_at": "2026-08-11T10:00:00.000Z",
"follow_up_note": "Call after salary day.",
"assignee": {
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"name": "Nusrat Jahan"
},
"delivered_at": "2026-08-11T10:00:00.000Z",
"created_at": "2026-08-11T10:00:00.000Z",
"updated_at": "2026-08-11T10:00:00.000Z",
"items": [
{
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"product_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"variant_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"product_name": "Classic Cotton T-Shirt",
"variant_name": "Red / M",
"sku": "TSHIRT-RED-M",
"quantity": 2,
"unit_price": "1250.00",
"discount_price": "1250.00",
"subtotal": "1250.00"
}
],
"customer": {
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"full_name": "Rafiqul Islam",
"email": null,
"phone": "01712345678",
"type": "manual",
"status": "active"
}
}Cancel an order
/ext/v1/orders/{id}/cancelorders:writeSugar for the cancelled transition: same map, same stock unwind (release an open reservation, reverse a committed sale).
Path parameters
| Name | Type | Description |
|---|---|---|
idrequired | uuid | The order id. |
Headers
| Name | Type | Description |
|---|---|---|
Idempotency-Key | string | Optional, but honored: send it to make retries of this request safe. |
Body parameters
| Name | Type | Description |
|---|---|---|
store_id | uuid | Target store. REQUIRED with a company-scoped key; with a store-scoped key it may only repeat the key's own store. |
note | string | Recorded on the order's timeline. |
Request
export SHOPDESK_API_KEY="shopdesk_sk_YOUR_API_KEY"
curl -sS -X POST "https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID/cancel" \
-H "Authorization: Bearer $SHOPDESK_API_KEY" \
-H "Idempotency-Key: 3f2b8c1e-9d4a-4e7b-8a6f-2c5d1e0b9a47" \
-H "Content-Type: application/json" \
-d '{
"note": "Customer changed their mind."
}'const url = new URL("https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID/cancel");
const response = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SHOPDESK_API_KEY}`,
"Idempotency-Key": "3f2b8c1e-9d4a-4e7b-8a6f-2c5d1e0b9a47",
"Content-Type": "application/json",
},
body: JSON.stringify({
"note": "Customer changed their mind."
}),
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.code}: ${error.message} [${error.request_id}]`);
}
const object = await response.json();import os
import requests
payload = {
"note": "Customer changed their mind.",
}
response = requests.post(
"https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID/cancel",
json=payload,
headers={
"Authorization": f"Bearer {os.environ['SHOPDESK_API_KEY']}",
"Idempotency-Key": "3f2b8c1e-9d4a-4e7b-8a6f-2c5d1e0b9a47",
},
timeout=30,
)
if not response.ok:
error = response.json()["error"]
raise RuntimeError(f"{error['code']}: {error['message']}")
obj = response.json()<?php
$key = getenv('SHOPDESK_API_KEY');
$payload = json_encode([
'note' => 'Customer changed their mind.',
]);
$ch = curl_init('https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID/cancel');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $key, 'Idempotency-Key: 3f2b8c1e-9d4a-4e7b-8a6f-2c5d1e0b9a47', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => $payload,
CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
$response = json_decode($body, true);
if ($status >= 400) {
throw new RuntimeException("{$response['error']['code']}: {$response['error']['message']}");
}https://api.shopdeskbd.com/ext/v1/orders/5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001/cancelStored 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
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 cancelled order (customer and items expanded).400AnIdempotency-Keyheader was sent but is empty or longer than 255 characters (VALIDATION_ERROR;error.fieldsnames the header), or the order cannot be cancelled from its current status (INVALID_STATUS_TRANSITION;error.fields.statusnames it).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.404Order not found.409A courier parcel for this order is still live (CONFLICT;error.fields.statusis["live_parcel"]): before the courier picks it up it has to be cancelled from the dashboard first; after, it is asked back with a Return request in the dashboard; or a request with thisIdempotency-Keyis still in flight (IDEMPOTENCY_IN_FLIGHT) — retry once it has finished.422Validation failed —error.fieldsmaps each offending field to its messages.429Rate limit exceeded for this key. HonorRetry-Afterand theX-RateLimit-*headers.
Every failure uses the one error envelope — Errors lists each code and what to do with it.
{
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"store_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"number": "ORD-20260811-1042",
"source": "api",
"channel": {
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"name": "Facebook",
"slug": "facebook",
"type": "facebook"
},
"customer_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"location_id": null,
"status": "pending",
"payment_status": "unpaid",
"fulfillment_status": "unfulfilled",
"subtotal": "1250.00",
"discount_amount": "1250.00",
"shipping_charge": "1250.00",
"tax_amount": "1250.00",
"total_amount": "1250.00",
"paid_amount": "1250.00",
"due_amount": "1250.00",
"refunded_amount": "1250.00",
"shipping_address": null,
"coupon": null,
"custom_fields": null,
"note": null,
"follow_up_at": "2026-08-11T10:00:00.000Z",
"follow_up_note": "Call after salary day.",
"assignee": {
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"name": "Nusrat Jahan"
},
"delivered_at": "2026-08-11T10:00:00.000Z",
"created_at": "2026-08-11T10:00:00.000Z",
"updated_at": "2026-08-11T10:00:00.000Z",
"items": [
{
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"product_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"variant_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"product_name": "Classic Cotton T-Shirt",
"variant_name": "Red / M",
"sku": "TSHIRT-RED-M",
"quantity": 2,
"unit_price": "1250.00",
"discount_price": "1250.00",
"subtotal": "1250.00"
}
],
"customer": {
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"full_name": "Rafiqul Islam",
"email": null,
"phone": "01712345678",
"type": "manual",
"status": "active"
}
}List an order's payments
/ext/v1/orders/{id}/paymentspayments:readEvery settled, pending and refunded row against the order, oldest first. Refunds are negative amounts with status refunded.
Path parameters
| Name | Type | Description |
|---|---|---|
idrequired | uuid | The order id. |
Query parameters
| Name | Type | Description |
|---|---|---|
store_id | uuid | Restrict the lookup to one store. Breadth control for company-scoped keys; on a store-scoped key it must match the key's own store. |
Request
export SHOPDESK_API_KEY="shopdesk_sk_YOUR_API_KEY"
curl -sS "https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID/payments" \
-H "Authorization: Bearer $SHOPDESK_API_KEY"const url = new URL("https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID/payments");
const response = await fetch(url, {
headers: {
Authorization: `Bearer ${process.env.SHOPDESK_API_KEY}`,
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.code}: ${error.message} [${error.request_id}]`);
}
const { data } = await response.json();import os
import requests
response = requests.get(
"https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID/payments",
headers={
"Authorization": f"Bearer {os.environ['SHOPDESK_API_KEY']}",
},
timeout=30,
)
if not response.ok:
error = response.json()["error"]
raise RuntimeError(f"{error['code']}: {error['message']}")
page = response.json()
rows = page["data"]<?php
$key = getenv('SHOPDESK_API_KEY');
$ch = curl_init('https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID/payments');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $key],
CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
$response = json_decode($body, true);
if ($status >= 400) {
throw new RuntimeException("{$response['error']['code']}: {$response['error']['message']}");
}
$rows = $response['data'];https://api.shopdeskbd.com/ext/v1/orders/5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001/paymentsStored 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 order's payment rows.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.404Order not found.422Validation failed —error.fieldsmaps each offending field to its messages.429Rate limit exceeded for this key. HonorRetry-Afterand theX-RateLimit-*headers.
Every failure uses the one error envelope — Errors lists each code and what to do with it.
{
"data": [
{
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"store_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"order_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"amount": "1250.00",
"status": "paid",
"transaction_id": "TRX9F3K2",
"payment_method": {
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"name": "bKash",
"type": "online"
},
"paid_at": "2026-08-11T10:00:00.000Z",
"created_at": "2026-08-11T10:00:00.000Z"
}
]
}Record a payment against an order
/ext/v1/orders/{id}/paymentspayments:writeThe staff path verbatim: the amount is capped at the order's NET due (refunds counted), the paid/due rollup recomputes under a row lock, and the paid-in-full events fire exactly once. A provider transaction id is unique per store — recording the same TrxID twice is a 409 (duplicate_transaction_id, naming the order that has it). A payment method set to require a transaction id refuses a payment without one (transaction_id_required, 400). While a courier parcel with a cash-on-delivery amount is out, a payment is a 409 cod_parcel_active.
Path parameters
| Name | Type | Description |
|---|---|---|
idrequired | uuid | The order id. |
Headers
| Name | Type | Description |
|---|---|---|
Idempotency-Keyrequired | string | REQUIRED. A unique value per logical request (a UUID is ideal); reuse it verbatim when retrying. A retry replays the original response with Idempotent-Replayed: true instead of running twice. |
Body parameters
| Name | Type | Description |
|---|---|---|
store_id | uuid | Target store. REQUIRED with a company-scoped key; with a store-scoped key it may only repeat the key's own store. |
amountrequired | number | — |
payment_method_id | uuid | One of the store's payment methods (must be active). |
transaction_id | string | Provider transaction id. Unique per store — recording the same TrxID twice is a 409. |
Request
export SHOPDESK_API_KEY="shopdesk_sk_YOUR_API_KEY"
curl -sS -X POST "https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID/payments" \
-H "Authorization: Bearer $SHOPDESK_API_KEY" \
-H "Idempotency-Key: 3f2b8c1e-9d4a-4e7b-8a6f-2c5d1e0b9a47" \
-H "Content-Type: application/json" \
-d '{
"amount": 500,
"transaction_id": "TRX9F3K2"
}'const url = new URL("https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID/payments");
const response = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SHOPDESK_API_KEY}`,
"Idempotency-Key": "3f2b8c1e-9d4a-4e7b-8a6f-2c5d1e0b9a47",
"Content-Type": "application/json",
},
body: JSON.stringify({
"amount": 500,
"transaction_id": "TRX9F3K2"
}),
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.code}: ${error.message} [${error.request_id}]`);
}
const object = await response.json();import os
import requests
payload = {
"amount": 500,
"transaction_id": "TRX9F3K2",
}
response = requests.post(
"https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID/payments",
json=payload,
headers={
"Authorization": f"Bearer {os.environ['SHOPDESK_API_KEY']}",
"Idempotency-Key": "3f2b8c1e-9d4a-4e7b-8a6f-2c5d1e0b9a47",
},
timeout=30,
)
if not response.ok:
error = response.json()["error"]
raise RuntimeError(f"{error['code']}: {error['message']}")
obj = response.json()<?php
$key = getenv('SHOPDESK_API_KEY');
$payload = json_encode([
'amount' => 500,
'transaction_id' => 'TRX9F3K2',
]);
$ch = curl_init('https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID/payments');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $key, 'Idempotency-Key: 3f2b8c1e-9d4a-4e7b-8a6f-2c5d1e0b9a47', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => $payload,
CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
$response = json_decode($body, true);
if ($status >= 400) {
throw new RuntimeException("{$response['error']['code']}: {$response['error']['message']}");
}https://api.shopdeskbd.com/ext/v1/orders/5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001/paymentsStored 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
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 updated order (customer and items expanded).400The requiredIdempotency-Keyheader is missing, empty, or longer than 255 characters (VALIDATION_ERROR;error.fieldsnames 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.404Order not found.409This transaction id is already recorded in the store; or a request with thisIdempotency-Keyis still in flight (IDEMPOTENCY_IN_FLIGHT) — retry once it has finished.422Validation failed —error.fieldsmaps each offending field to its messages.429Rate limit exceeded for this key. HonorRetry-Afterand theX-RateLimit-*headers.
Every failure uses the one error envelope — Errors lists each code and what to do with it.
{
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"store_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"number": "ORD-20260811-1042",
"source": "api",
"channel": {
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"name": "Facebook",
"slug": "facebook",
"type": "facebook"
},
"customer_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"location_id": null,
"status": "pending",
"payment_status": "unpaid",
"fulfillment_status": "unfulfilled",
"subtotal": "1250.00",
"discount_amount": "1250.00",
"shipping_charge": "1250.00",
"tax_amount": "1250.00",
"total_amount": "1250.00",
"paid_amount": "1250.00",
"due_amount": "1250.00",
"refunded_amount": "1250.00",
"shipping_address": null,
"coupon": null,
"custom_fields": null,
"note": null,
"follow_up_at": "2026-08-11T10:00:00.000Z",
"follow_up_note": "Call after salary day.",
"assignee": {
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"name": "Nusrat Jahan"
},
"delivered_at": "2026-08-11T10:00:00.000Z",
"created_at": "2026-08-11T10:00:00.000Z",
"updated_at": "2026-08-11T10:00:00.000Z",
"items": [
{
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"product_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"variant_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"product_name": "Classic Cotton T-Shirt",
"variant_name": "Red / M",
"sku": "TSHIRT-RED-M",
"quantity": 2,
"unit_price": "1250.00",
"discount_price": "1250.00",
"subtotal": "1250.00"
}
],
"customer": {
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"full_name": "Rafiqul Islam",
"email": null,
"phone": "01712345678",
"type": "manual",
"status": "active"
}
}Change an order status
/ext/v1/orders/{id}/statusorders:writeValidated against the SAME strict transition map staff use — an illegal move is refused with INVALID_STATUS_TRANSITION. A delivered order cannot be moved to returned: returns of delivered orders are made in the dashboard. Stock side effects are the staff path’s, inherited: commit on delivery, release on cancel. A returned order keeps its stock held (not for sale) until the parcel is received in the dashboard ("RTO received"). On a never-delivered order, returned keeps up to the delivery charge from an advance only when the parcel's pickup is recorded; otherwise everything paid is owed back to the customer and no courier charge is booked. returned is refused (CONFLICT; error.fields.status is ["parcel_not_picked_up"]) while a courier that reports pickups (Pathao, RedX, CarryBee, Bahok) has not reported picking the parcel up.
Path parameters
| Name | Type | Description |
|---|---|---|
idrequired | uuid | The order id. |
Headers
| Name | Type | Description |
|---|---|---|
Idempotency-Key | string | Optional, but honored: send it to make retries of this request safe. |
Body parameters
| Name | Type | Description |
|---|---|---|
store_id | uuid | Target store. REQUIRED with a company-scoped key; with a store-scoped key it may only repeat the key's own store. |
statusrequired | string | —pendingfollow_upconfirmedprocessingready_to_shipin_transitdeliveredreturnedfailed_deliverycancelledholdspam |
note | string | Recorded on the order's timeline. |
Request
export SHOPDESK_API_KEY="shopdesk_sk_YOUR_API_KEY"
curl -sS -X PATCH "https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID/status" \
-H "Authorization: Bearer $SHOPDESK_API_KEY" \
-H "Idempotency-Key: 3f2b8c1e-9d4a-4e7b-8a6f-2c5d1e0b9a47" \
-H "Content-Type: application/json" \
-d '{
"status": "confirmed",
"note": "Confirmed over the phone."
}'const url = new URL("https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID/status");
const response = await fetch(url, {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.SHOPDESK_API_KEY}`,
"Idempotency-Key": "3f2b8c1e-9d4a-4e7b-8a6f-2c5d1e0b9a47",
"Content-Type": "application/json",
},
body: JSON.stringify({
"status": "confirmed",
"note": "Confirmed over the phone."
}),
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.code}: ${error.message} [${error.request_id}]`);
}
const object = await response.json();import os
import requests
payload = {
"status": "confirmed",
"note": "Confirmed over the phone.",
}
response = requests.patch(
"https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID/status",
json=payload,
headers={
"Authorization": f"Bearer {os.environ['SHOPDESK_API_KEY']}",
"Idempotency-Key": "3f2b8c1e-9d4a-4e7b-8a6f-2c5d1e0b9a47",
},
timeout=30,
)
if not response.ok:
error = response.json()["error"]
raise RuntimeError(f"{error['code']}: {error['message']}")
obj = response.json()<?php
$key = getenv('SHOPDESK_API_KEY');
$payload = json_encode([
'status' => 'confirmed',
'note' => 'Confirmed over the phone.',
]);
$ch = curl_init('https://api.shopdeskbd.com/ext/v1/orders/REPLACE_WITH_ID/status');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $key, 'Idempotency-Key: 3f2b8c1e-9d4a-4e7b-8a6f-2c5d1e0b9a47', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => $payload,
CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
$response = json_decode($body, true);
if ($status >= 400) {
throw new RuntimeException("{$response['error']['code']}: {$response['error']['message']}");
}https://api.shopdeskbd.com/ext/v1/orders/5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001/statusStored 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
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 order (customer and items expanded).400AnIdempotency-Keyheader was sent but is empty or longer than 255 characters (VALIDATION_ERROR;error.fieldsnames the header), or the transition map forbids this move (INVALID_STATUS_TRANSITION;error.fields.statusnames it).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.404Order not found.409A courier parcel for this order is still live (CONFLICT;error.fields.statusis["live_parcel"]): before the courier picks it up it has to be cancelled from the dashboard first; after, it is asked back with a Return request in the dashboard; or, forreturned, the courier has not reported picking the parcel up (error.fields.statusis["parcel_not_picked_up"]); or, forin_transit, the order’s parcel was cancelled and has to be booked again (["shipment_cancelled"]); or a request with thisIdempotency-Keyis still in flight (IDEMPOTENCY_IN_FLIGHT) — retry once it has finished.422Validation failed —error.fieldsmaps each offending field to its messages.429Rate limit exceeded for this key. HonorRetry-Afterand theX-RateLimit-*headers.
Every failure uses the one error envelope — Errors lists each code and what to do with it.
{
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"store_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"number": "ORD-20260811-1042",
"source": "api",
"channel": {
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"name": "Facebook",
"slug": "facebook",
"type": "facebook"
},
"customer_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"location_id": null,
"status": "pending",
"payment_status": "unpaid",
"fulfillment_status": "unfulfilled",
"subtotal": "1250.00",
"discount_amount": "1250.00",
"shipping_charge": "1250.00",
"tax_amount": "1250.00",
"total_amount": "1250.00",
"paid_amount": "1250.00",
"due_amount": "1250.00",
"refunded_amount": "1250.00",
"shipping_address": null,
"coupon": null,
"custom_fields": null,
"note": null,
"follow_up_at": "2026-08-11T10:00:00.000Z",
"follow_up_note": "Call after salary day.",
"assignee": {
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"name": "Nusrat Jahan"
},
"delivered_at": "2026-08-11T10:00:00.000Z",
"created_at": "2026-08-11T10:00:00.000Z",
"updated_at": "2026-08-11T10:00:00.000Z",
"items": [
{
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"product_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"variant_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"product_name": "Classic Cotton T-Shirt",
"variant_name": "Red / M",
"sku": "TSHIRT-RED-M",
"quantity": 2,
"unit_price": "1250.00",
"discount_price": "1250.00",
"subtotal": "1250.00"
}
],
"customer": {
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"full_name": "Rafiqul Islam",
"email": null,
"phone": "01712345678",
"type": "manual",
"status": "active"
}
}