{"openapi":"3.1.0","info":{"title":"Shofni API","version":"1.0.0","description":"REST API for a Shofni store: orders, customers, catalogue, stock and webhooks.\n\n* **Auth**: `Authorization: Bearer shf_...`, a token minted in the dashboard under Settings > API tokens. The token alone decides the store.\n* **Rate limit**: 120 requests per trailing minute per token. Every response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`; over the limit, HTTP 429 `{ \"error\": \"rate_limited\", \"retryAfter\": <seconds> }` with `Retry-After`. Request bodies are capped at 4 MB (HTTP 413).\n* **Errors**: `{ \"error\": { \"code\", \"message\", \"details\"? } }`.\n* **Lists**: `?page=1&limit=25` (limit max 100), answered as `{ data: [...], pagination }`, newest first.\n* **Webhooks**: signed POSTs to your server, see the `webhooks` section."},"servers":[{"url":"https://shofniplus.com/api/v1","description":"Production (also reachable on the store's own domain under /api/v1)"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Orders"},{"name":"Customers"},{"name":"Products"},{"name":"Inventory"},{"name":"Categories"},{"name":"Brands"},{"name":"Store"},{"name":"Webhooks"}],"paths":{"/orders":{"get":{"operationId":"listOrders","summary":"List orders","description":"Newest first. Held table baskets are excluded.","tags":["Orders"],"x-scope":"orders:read","parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"status","in":"query","description":"Comma-separated status codes of this store. Unknown codes: 422 with `details.allowed`.","schema":{"type":"string"}},{"name":"payment_status","in":"query","description":"Comma-separated: paid, unpaid, failed, authorized, refunded_partial, refunded_full, refund_failed.","schema":{"type":"string"}},{"name":"created_after","in":"query","description":"ISO 8601, inclusive.","schema":{"type":"string","format":"date-time"}},{"name":"created_before","in":"query","description":"ISO 8601, exclusive. A date without a time covers that whole UTC day.","schema":{"type":"string","format":"date-time"}},{"name":"updated_after","in":"query","description":"ISO 8601, inclusive. Any change to the order moves `updatedAt`.","schema":{"type":"string","format":"date-time"}},{"name":"q","in":"query","description":"Order number, customer name, phone or email, tracking number, product/variant SKU.","schema":{"type":"string"}},{"name":"channel","in":"query","description":"Comma-separated: store, pos, app, whatsapp, phone, manual, external.","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of orders.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OrderSummary"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"example":{"data":[{"id":"483920","number":"483920","status":{"code":"PENDING","group":"NEW","name":{"ar":"جديد","en":"New"},"customerName":{"ar":"تم استلام طلبك","en":"Order received"}},"paymentStatus":"paid","paymentMethod":{"code":"card","group":"card"},"currency":"SAR","total":27,"amountPaid":27,"channel":"external","source":"api","serviceType":"delivery","itemCount":2,"customer":{"id":"clx1cust","name":"سارة أحمد","phone":"966551112233","email":"sara@example.com"},"trackingNumber":"AWB123","createdAt":"2026-10-19T08:00:00.000Z","updatedAt":"2026-10-19T08:05:00.000Z"}],"pagination":{"page":1,"limit":25,"total":1,"totalPages":1}}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unauthorized","message":"Missing or invalid API token."}}}}},"403":{"description":"Token lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"forbidden","message":"This token lacks the \"orders:read\" scope.","details":{"requiredScope":"orders:read"}}}}}},"422":{"description":"Bad filter.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"validation_failed","message":"Unknown status code(s): NOPE.","details":{"field":"status","allowed":["PENDING","PROCESSING"]}}}}}},"429":{"description":"Rate limited (120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"rate_limited","message":"Too many requests."}}}}}}},"post":{"operationId":"createOrder","summary":"Create an order","description":"Creates a PENDING order priced by the store (catalogue, variant surcharges, add-ons, membership prices, tax), the same path as the register. Tracked stock is deducted with stock movements and returned if the order is later cancelled; the store owner gets the usual new-order alert; restaurants get a kitchen ticket. Cash on delivery is refused (403) for customers the store blocked from COD.\n\n`Idempotency-Key`: optional. The same key within 24 hours returns the first order with 200 and `Idempotent-Replayed: true` instead of creating another.","tags":["Orders"],"x-scope":"orders:write","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderCreateRequest"}}}},"responses":{"200":{"description":"Idempotent replay of an earlier request with the same key.","headers":{"Idempotent-Replayed":{"schema":{"type":"string","const":"true"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Order"}}}}}},"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Order"}}},"example":{"data":{"id":"483920","number":"483920","status":{"code":"PENDING","group":"NEW","name":{"ar":"جديد","en":"New"},"customerName":{"ar":"تم استلام طلبك","en":"Order received"}},"paymentStatus":"paid","paymentMethod":{"code":"card","group":"card"},"currency":"SAR","channel":"external","source":"api","serviceType":"delivery","totals":{"subtotal":27,"listSubtotal":27,"discountTotal":0,"couponDiscount":0,"offerDiscount":0,"discounts":[],"shipping":0,"codFee":0,"fees":[],"tax":0,"taxInclusive":false,"total":27,"amountPaid":27,"amountRefunded":0,"amountDue":0},"lineItems":[{"productId":"clx1burger","variantId":null,"sku":"BRG-01","name":"برجر","nameEn":"Burger","options":[],"variantLabel":null,"addons":[],"note":"بدون بصل","quantity":2,"unitPrice":10,"listUnitPrice":10,"discount":0,"tax":0,"lineTotal":20}],"customer":{"id":"clx1cust","name":"سارة أحمد","phone":"+966 55 111 2233","email":"sara@example.com"},"shippingAddress":{"name":"سارة أحمد","phone":"966551112233","country":null,"region":null,"city":"الرياض","district":"العليا","street":"شارع التحلية","building":"12","unit":null,"postalCode":null,"shortAddress":"RRRD2929","additionalNumber":null,"coordinates":{"lat":24.7,"lng":46.68}},"shipping":{"method":"HOME_DELIVERY","carrierCode":"aramex","carrierName":"Aramex","trackingNumber":"AWB123","trackingUrl":"https://www.aramex.com/track/results?ShipmentNumber=AWB123","labelStatus":"ISSUED","shipmentStatus":null},"notes":{"customer":"اتصل قبل الوصول","staff":[{"id":"clx1note","body":"VIP","authorName":"API: ERP","createdAt":"2026-10-19T08:00:00.000Z"}]},"tags":[],"createdAt":"2026-10-19T08:00:00.000Z","updatedAt":"2026-10-19T08:05:00.000Z"}}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unauthorized","message":"Missing or invalid API token."}}}}},"403":{"description":"COD blocked for this customer, or missing scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"forbidden","message":"Cash on delivery is not available for this customer.","details":{"field":"paymentMethod"}}}}}},"409":{"description":"Could not allocate an order number; retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"conflict","message":"Could not allocate an order number; retry the request."}}}}},"422":{"description":"Invalid input, unknown product, not enough stock, or a unit price was sent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"validation_failed","message":"\"برجر\": 3 in stock, 99 requested.","details":{"field":"items"}}}}}},"429":{"description":"Rate limited (120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"rate_limited","message":"Too many requests."}}}}}}}},"/orders/{id}":{"get":{"operationId":"getOrder","summary":"Get one order","tags":["Orders"],"x-scope":"orders:read","parameters":[{"name":"id","in":"path","required":true,"description":"Order id or its visible number. `123456`, `#A1B2C3` (URL-encode `#` as `%23`) and the legacy six-character suffix are accepted.","schema":{"type":"string"}}],"responses":{"200":{"description":"The order.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Order"}}},"example":{"data":{"id":"483920","number":"483920","status":{"code":"PENDING","group":"NEW","name":{"ar":"جديد","en":"New"},"customerName":{"ar":"تم استلام طلبك","en":"Order received"}},"paymentStatus":"paid","paymentMethod":{"code":"card","group":"card"},"currency":"SAR","channel":"external","source":"api","serviceType":"delivery","totals":{"subtotal":27,"listSubtotal":27,"discountTotal":0,"couponDiscount":0,"offerDiscount":0,"discounts":[],"shipping":0,"codFee":0,"fees":[],"tax":0,"taxInclusive":false,"total":27,"amountPaid":27,"amountRefunded":0,"amountDue":0},"lineItems":[{"productId":"clx1burger","variantId":null,"sku":"BRG-01","name":"برجر","nameEn":"Burger","options":[],"variantLabel":null,"addons":[],"note":"بدون بصل","quantity":2,"unitPrice":10,"listUnitPrice":10,"discount":0,"tax":0,"lineTotal":20}],"customer":{"id":"clx1cust","name":"سارة أحمد","phone":"+966 55 111 2233","email":"sara@example.com"},"shippingAddress":{"name":"سارة أحمد","phone":"966551112233","country":null,"region":null,"city":"الرياض","district":"العليا","street":"شارع التحلية","building":"12","unit":null,"postalCode":null,"shortAddress":"RRRD2929","additionalNumber":null,"coordinates":{"lat":24.7,"lng":46.68}},"shipping":{"method":"HOME_DELIVERY","carrierCode":"aramex","carrierName":"Aramex","trackingNumber":"AWB123","trackingUrl":"https://www.aramex.com/track/results?ShipmentNumber=AWB123","labelStatus":"ISSUED","shipmentStatus":null},"notes":{"customer":"اتصل قبل الوصول","staff":[{"id":"clx1note","body":"VIP","authorName":"API: ERP","createdAt":"2026-10-19T08:00:00.000Z"}]},"tags":[],"createdAt":"2026-10-19T08:00:00.000Z","updatedAt":"2026-10-19T08:05:00.000Z"}}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unauthorized","message":"Missing or invalid API token."}}}}},"403":{"description":"Token lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"forbidden","message":"This token lacks the \"orders:read\" scope.","details":{"requiredScope":"orders:read"}}}}}},"404":{"description":"No such order in this store (ids of other stores read as not found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"Order not found."}}}}},"429":{"description":"Rate limited (120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"rate_limited","message":"Too many requests."}}}}}}}},"/orders/{id}/status":{"patch":{"operationId":"changeOrderStatus","summary":"Move an order to another status","description":"Runs the store's own status engine, exactly as the dashboard does: allowed transitions, required reasons, kitchen ticket, stock return on cancellation, coupon/offer release, return paperwork, customer notification templates, audit trail (actor = the token). Refunds are not performed.","tags":["Orders"],"x-scope":"orders:write","parameters":[{"name":"id","in":"path","required":true,"description":"Order id or its visible number. `123456`, `#A1B2C3` (URL-encode `#` as `%23`) and the legacy six-character suffix are accepted.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderStatusChangeRequest"}}}},"responses":{"200":{"description":"The updated order.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Order"}}}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unauthorized","message":"Missing or invalid API token."}}}}},"403":{"description":"Token lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"forbidden","message":"This token lacks the \"orders:read\" scope.","details":{"requiredScope":"orders:read"}}}}}},"404":{"description":"No such order in this store (ids of other stores read as not found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"Order not found."}}}}},"409":{"description":"The order changed concurrently.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"conflict","message":"The order changed while it was being updated; retry."}}}}},"422":{"description":"Unknown status, transition not allowed, reason required, or notify=false.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"validation_failed","message":"A reason is required for this change.","details":{"field":"status","reasonCode":"REASON_REQUIRED","from":"PENDING","allowedTransitions":["PROCESSING","CANCELLED"]}}}}}},"429":{"description":"Rate limited (120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"rate_limited","message":"Too many requests."}}}}}}}},"/orders/{id}/notes":{"post":{"operationId":"addOrderNote","summary":"Add an internal staff note","tags":["Orders"],"x-scope":"orders:write","parameters":[{"name":"id","in":"path","required":true,"description":"Order id or its visible number. `123456`, `#A1B2C3` (URL-encode `#` as `%23`) and the legacy six-character suffix are accepted.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderNoteRequest"}}}},"responses":{"201":{"description":"Note added.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrderNote"}}},"example":{"data":{"id":"clx1note","orderId":"483920","body":"تم التحقق من العنوان","authorName":"API: ERP","createdAt":"2026-10-19T08:10:00.000Z","unresolvedMentions":[]}}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unauthorized","message":"Missing or invalid API token."}}}}},"403":{"description":"Token lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"forbidden","message":"This token lacks the \"orders:read\" scope.","details":{"requiredScope":"orders:read"}}}}}},"404":{"description":"No such order in this store (ids of other stores read as not found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"Order not found."}}}}},"422":{"description":"Empty note.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"validation_failed","message":"\"body\" is required.","details":{"field":"body"}}}}}},"429":{"description":"Rate limited (120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"rate_limited","message":"Too many requests."}}}}}}}},"/orders/{id}/shipping":{"patch":{"operationId":"setOrderShipping","summary":"Record the carrier and tracking number","description":"Records a waybill that already exists at the carrier (manual ISSUED label, or confirms a label REQUESTED from the same carrier). Writes the shipment and order event and runs the store's LABEL_ISSUED automation. `trackingUrl` is derived from the carrier and cannot be set (422 if sent). An order that already has a live waybill returns 409: reissuing is done from the dashboard.","tags":["Orders"],"x-scope":"orders:write","parameters":[{"name":"id","in":"path","required":true,"description":"Order id or its visible number. `123456`, `#A1B2C3` (URL-encode `#` as `%23`) and the legacy six-character suffix are accepted.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderShippingRequest"}}}},"responses":{"200":{"description":"The updated order.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Order"}}}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unauthorized","message":"Missing or invalid API token."}}}}},"403":{"description":"Token lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"forbidden","message":"This token lacks the \"orders:read\" scope.","details":{"requiredScope":"orders:read"}}}}}},"404":{"description":"No such order in this store (ids of other stores read as not found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"Order not found."}}}}},"409":{"description":"A live waybill already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"conflict","message":"This order already has a live waybill. Reissue it from the dashboard.","details":{"trackingNumber":"AWB123","labelStatus":"ISSUED"}}}}}},"422":{"description":"Unknown carrier or carrier switched off.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"validation_failed","message":"Unknown carrier \"fedx\".","details":{"field":"carrier"}}}}}},"429":{"description":"Rate limited (120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"rate_limited","message":"Too many requests."}}}}}}}},"/customers":{"get":{"operationId":"listCustomers","summary":"List customers","description":"Newest registration first. Customers merged into another record are excluded. `addresses` is not included in list rows.","tags":["Customers"],"x-scope":"customers:read","parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"q","in":"query","description":"Name, email or phone (local `05...` and international forms both match).","schema":{"type":"string"}},{"name":"created_after","in":"query","description":"ISO 8601; compared with the registration date.","schema":{"type":"string","format":"date-time"}},{"name":"updated_after","in":"query","description":"Not supported for customers (no modification timestamp is kept): 422.","schema":{"type":"string"},"deprecated":true}],"responses":{"200":{"description":"A page of customers.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Customer"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"example":{"data":[{"id":"clx1cust","number":42,"name":"خالد سعيد","phone":"966559998877","email":"khaled@example.com","emailVerified":false,"marketingOptIn":false,"language":"ar","country":null,"status":"ACTIVE","source":"API","tags":["wholesale"],"loyaltyPoints":120,"walletBalance":15.5,"orderCount":3,"totalSpent":{"SAR":840},"lastOrderAt":"2026-10-18T19:22:00.000Z","registeredAt":"2026-09-01T10:00:00.000Z"}],"pagination":{"page":1,"limit":25,"total":1,"totalPages":1}}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unauthorized","message":"Missing or invalid API token."}}}}},"403":{"description":"Token lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"forbidden","message":"This token lacks the \"customers:read\" scope.","details":{"requiredScope":"customers:read"}}}}}},"422":{"description":"Bad filter (including updated_after).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"validation_failed","message":"updated_after is not supported for customers (no modification timestamp is kept).","details":{"field":"updated_after"}}}}}},"429":{"description":"Rate limited (120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"rate_limited","message":"Too many requests."}}}}}}},"post":{"operationId":"createCustomer","summary":"Create a customer","description":"Idempotency-Key is not used here: the phone number is unique per store, so a retried create answers 409 with `details.customerId`.","tags":["Customers"],"x-scope":"customers:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerCreateRequest"}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Customer"}}},"example":{"data":{"id":"clx1cust","number":42,"name":"خالد سعيد","phone":"966559998877","email":"khaled@example.com","emailVerified":false,"marketingOptIn":false,"language":"ar","country":null,"status":"ACTIVE","source":"API","tags":["wholesale"],"loyaltyPoints":120,"walletBalance":15.5,"orderCount":3,"totalSpent":{"SAR":840},"lastOrderAt":"2026-10-18T19:22:00.000Z","registeredAt":"2026-09-01T10:00:00.000Z","addresses":[{"id":"clx1addr","label":"المنزل","name":null,"phone":null,"country":null,"region":null,"city":"جدة","district":null,"street":"شارع فلسطين","building":null,"unit":null,"postalCode":null,"shortAddress":"JEDA1234","coordinates":null,"isDefaultShipping":true,"isDefaultBilling":true}]}}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unauthorized","message":"Missing or invalid API token."}}}}},"403":{"description":"Token lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"forbidden","message":"This token lacks the \"customers:read\" scope.","details":{"requiredScope":"customers:read"}}}}}},"409":{"description":"This store already has the phone (any spelling) or the email.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"conflict","message":"A customer with this phone number already exists.","details":{"field":"phone","customerId":"clx1cust"}}}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"validation_failed","message":"\"phone\" must be an E.164 phone number, e.g. +966551234567.","details":{"field":"phone"}}}}}},"429":{"description":"Rate limited (120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"rate_limited","message":"Too many requests."}}}}}}}},"/customers/{id}":{"get":{"operationId":"getCustomer","summary":"Get one customer","tags":["Customers"],"x-scope":"customers:read","parameters":[{"name":"id","in":"path","required":true,"description":"Customer id.","schema":{"type":"string"}}],"responses":{"200":{"description":"The customer, with addresses.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Customer"}}},"example":{"data":{"id":"clx1cust","number":42,"name":"خالد سعيد","phone":"966559998877","email":"khaled@example.com","emailVerified":false,"marketingOptIn":false,"language":"ar","country":null,"status":"ACTIVE","source":"API","tags":["wholesale"],"loyaltyPoints":120,"walletBalance":15.5,"orderCount":3,"totalSpent":{"SAR":840},"lastOrderAt":"2026-10-18T19:22:00.000Z","registeredAt":"2026-09-01T10:00:00.000Z","addresses":[{"id":"clx1addr","label":"المنزل","name":null,"phone":null,"country":null,"region":null,"city":"جدة","district":null,"street":"شارع فلسطين","building":null,"unit":null,"postalCode":null,"shortAddress":"JEDA1234","coordinates":null,"isDefaultShipping":true,"isDefaultBilling":true}]}}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unauthorized","message":"Missing or invalid API token."}}}}},"403":{"description":"Token lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"forbidden","message":"This token lacks the \"customers:read\" scope.","details":{"requiredScope":"customers:read"}}}}}},"404":{"description":"No such customer in this store.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"Customer not found."}}}}},"429":{"description":"Rate limited (120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"rate_limited","message":"Too many requests."}}}}}}},"patch":{"operationId":"updateCustomer","summary":"Update a customer","tags":["Customers"],"x-scope":"customers:write","parameters":[{"name":"id","in":"path","required":true,"description":"Customer id.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerUpdateRequest"}}}},"responses":{"200":{"description":"The updated customer.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Customer"}}},"example":{"data":{"id":"clx1cust","number":42,"name":"خالد سعيد","phone":"966559998877","email":"khaled@example.com","emailVerified":false,"marketingOptIn":false,"language":"ar","country":null,"status":"ACTIVE","source":"API","tags":["wholesale"],"loyaltyPoints":120,"walletBalance":15.5,"orderCount":3,"totalSpent":{"SAR":840},"lastOrderAt":"2026-10-18T19:22:00.000Z","registeredAt":"2026-09-01T10:00:00.000Z","addresses":[{"id":"clx1addr","label":"المنزل","name":null,"phone":null,"country":null,"region":null,"city":"جدة","district":null,"street":"شارع فلسطين","building":null,"unit":null,"postalCode":null,"shortAddress":"JEDA1234","coordinates":null,"isDefaultShipping":true,"isDefaultBilling":true}]}}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unauthorized","message":"Missing or invalid API token."}}}}},"403":{"description":"Token lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"forbidden","message":"This token lacks the \"customers:read\" scope.","details":{"requiredScope":"customers:read"}}}}}},"404":{"description":"No such customer in this store.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"Customer not found."}}}}},"409":{"description":"Phone/email belongs to another customer, or the record was merged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"conflict","message":"Another customer already has this phone number.","details":{"field":"phone","customerId":"clx1other"}}}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"validation_failed","message":"\"tags\" must be an array of strings.","details":{"field":"tags"}}}}}},"429":{"description":"Rate limited (120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"rate_limited","message":"Too many requests."}}}}}}}},"/customers/{id}/orders":{"get":{"operationId":"listCustomerOrders","summary":"List a customer's orders","description":"Newest first, open table baskets excluded. Requires customers:read.","tags":["Customers"],"x-scope":"customers:read","parameters":[{"name":"id","in":"path","required":true,"description":"Customer id.","schema":{"type":"string"}},{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"A page of orders.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OrderSummary"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unauthorized","message":"Missing or invalid API token."}}}}},"403":{"description":"Token lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"forbidden","message":"This token lacks the \"customers:read\" scope.","details":{"requiredScope":"customers:read"}}}}}},"404":{"description":"No such customer in this store.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"Customer not found."}}}}},"429":{"description":"Rate limited (120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"rate_limited","message":"Too many requests."}}}}}}}},"/products":{"get":{"tags":["Products"],"security":[{"bearerAuth":[]}],"x-required-scope":"catalog:read","operationId":"listProducts","summary":"List products","description":"Newest first. Archived products are excluded unless `status=archived`. Each product includes its option groups and variants.","parameters":[{"name":"q","in":"query","required":false,"description":"Search names, descriptions, SKUs, barcodes and tags (Arabic or English).","schema":{"type":"string"}},{"name":"category_id","in":"query","required":false,"description":"Products whose primary category is this id.","schema":{"type":"string"}},{"name":"brand_id","in":"query","required":false,"description":"Products of this brand.","schema":{"type":"string"}},{"name":"sku","in":"query","required":false,"description":"Exact SKU (case-insensitive) on the product or any of its variants.","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"Lifecycle state.","schema":{"type":"string","enum":["active","scheduled","draft","archived"]}},{"name":"in_stock","in":"query","required":false,"description":"true: tracked with stock > 0, or untracked. false: tracked and at or below 0.","schema":{"type":"boolean"}},{"name":"updated_after","in":"query","required":false,"description":"ISO 8601; products changed at or after this instant (use for incremental sync).","schema":{"type":"string","format":"date-time"}},{"name":"created_after","in":"query","required":false,"description":"ISO 8601.","schema":{"type":"string","format":"date-time"}},{"name":"created_before","in":"query","required":false,"description":"ISO 8601.","schema":{"type":"string","format":"date-time"}},{"name":"page","in":"query","required":false,"description":"Page number, from 1.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","required":false,"description":"Page size (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Product"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"401":{"description":"Missing or invalid API token (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The token lacks the required scope (`forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Bad filter value.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`rate_limited`, 120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Products"],"security":[{"bearerAuth":[]}],"x-required-scope":"catalog:write","operationId":"createProduct","summary":"Create a product","description":"Slugs are generated from the names unless given. Idempotency-Key is not supported for products; a repeated create with the same `sku` is refused with 409.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductCreate"},"example":{"name":"تيشيرت قطن","nameEn":"Cotton T-shirt","price":89,"compareAtPrice":120,"sku":"TSH-001","status":"active","categoryIds":["clc1cat0001"],"images":["https://cdn.example.com/tshirt-front.jpg"],"trackStock":true,"stock":25}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Product"}}},"example":{"data":{"id":"clx8p2k0f0001","name":"تيشيرت قطن","nameEn":"Cotton T-shirt","slug":"تيشيرت-قطن","slugEn":"cotton-t-shirt","url":"https://mystore.shofniplus.com/products/%D8%AA%D9%8A%D8%B4%D9%8A%D8%B1%D8%AA-%D9%82%D8%B7%D9%86","description":"قطن مصري 100%","descriptionEn":"100% Egyptian cotton","longDescription":null,"longDescriptionEn":null,"status":"active","isActive":true,"isHidden":false,"isFeatured":false,"sku":"TSH-001","barcode":null,"price":89,"compareAtPrice":120,"effectivePrice":79,"onSale":true,"cost":35,"currency":"SAR","trackStock":true,"stock":14,"images":["https://mystore.shofniplus.com/uploads/clt0abc/1729250000000-a1b2-front.webp"],"categoryId":"clc1cat0001","categoryIds":["clc1cat0001","clc1cat0007"],"brand":{"id":"clb1brand01","name":"نسيج","nameEn":"Naseej"},"tags":["صيفي"],"options":[{"id":"clv1opt0001","name":"المقاس","nameEn":"Size","required":true,"values":[{"code":"m","label":"M","labelEn":null,"priceDelta":0},{"code":"l","label":"L","labelEn":null,"priceDelta":5}]}],"variants":[{"id":"cmb_01hx9k2v7","productId":"clx8p2k0f0001","sku":"TSH-RED-M","barcode":"6281234567897","optionValues":[{"group":"اللون","groupEn":"Colour","value":"أحمر","valueEn":"Red"},{"group":"المقاس","groupEn":"Size","value":"M","valueEn":null}],"price":89,"priceInherited":true,"compareAtPrice":null,"currency":"SAR","stock":14,"trackStock":true,"isEnabled":true,"image":null,"weight":null,"weightUnit":null,"createdAt":"2026-10-01T09:12:00.000Z","updatedAt":"2026-10-18T14:03:11.000Z"}],"weight":{"net":0.25,"gross":0.3,"unit":"KG"},"createdAt":"2026-10-01T09:12:00.000Z","updatedAt":"2026-10-18T14:03:11.000Z"}}}}},"401":{"description":"Missing or invalid API token (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The token lacks the required scope (`forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Duplicate SKU, barcode or slug.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid field (details.field), foreign category/brand id, or an image URL that could not be imported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`rate_limited`, 120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/products/{id}":{"parameters":[{"name":"id","in":"path","required":true,"description":"Product id, Arabic or English slug, or SKU (product or variant).","schema":{"type":"string"}}],"get":{"tags":["Products"],"security":[{"bearerAuth":[]}],"x-required-scope":"catalog:read","operationId":"getProduct","summary":"Get a product","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Product"}}},"example":{"data":{"id":"clx8p2k0f0001","name":"تيشيرت قطن","nameEn":"Cotton T-shirt","slug":"تيشيرت-قطن","slugEn":"cotton-t-shirt","url":"https://mystore.shofniplus.com/products/%D8%AA%D9%8A%D8%B4%D9%8A%D8%B1%D8%AA-%D9%82%D8%B7%D9%86","description":"قطن مصري 100%","descriptionEn":"100% Egyptian cotton","longDescription":null,"longDescriptionEn":null,"status":"active","isActive":true,"isHidden":false,"isFeatured":false,"sku":"TSH-001","barcode":null,"price":89,"compareAtPrice":120,"effectivePrice":79,"onSale":true,"cost":35,"currency":"SAR","trackStock":true,"stock":14,"images":["https://mystore.shofniplus.com/uploads/clt0abc/1729250000000-a1b2-front.webp"],"categoryId":"clc1cat0001","categoryIds":["clc1cat0001","clc1cat0007"],"brand":{"id":"clb1brand01","name":"نسيج","nameEn":"Naseej"},"tags":["صيفي"],"options":[{"id":"clv1opt0001","name":"المقاس","nameEn":"Size","required":true,"values":[{"code":"m","label":"M","labelEn":null,"priceDelta":0},{"code":"l","label":"L","labelEn":null,"priceDelta":5}]}],"variants":[{"id":"cmb_01hx9k2v7","productId":"clx8p2k0f0001","sku":"TSH-RED-M","barcode":"6281234567897","optionValues":[{"group":"اللون","groupEn":"Colour","value":"أحمر","valueEn":"Red"},{"group":"المقاس","groupEn":"Size","value":"M","valueEn":null}],"price":89,"priceInherited":true,"compareAtPrice":null,"currency":"SAR","stock":14,"trackStock":true,"isEnabled":true,"image":null,"weight":null,"weightUnit":null,"createdAt":"2026-10-01T09:12:00.000Z","updatedAt":"2026-10-18T14:03:11.000Z"}],"weight":{"net":0.25,"gross":0.3,"unit":"KG"},"createdAt":"2026-10-01T09:12:00.000Z","updatedAt":"2026-10-18T14:03:11.000Z"}}}}},"401":{"description":"Missing or invalid API token (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The token lacks the required scope (`forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such product in this store.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`rate_limited`, 120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Products"],"security":[{"bearerAuth":[]}],"x-required-scope":"catalog:write","operationId":"updateProduct","summary":"Update a product","description":"Only the fields sent are written; null clears an optional field. Renaming keeps the URL. Price changes go to the price-change ledger and every save is a restorable revision. Stock is not set here: use PATCH /api/v1/inventory or PATCH /api/v1/variants/{id}.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductUpdate"},"example":{"price":79,"compareAtPrice":99,"priceChangeReason":"ERP price sync"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Product"}}}}}},"401":{"description":"Missing or invalid API token (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The token lacks the required scope (`forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such product.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Duplicate SKU, barcode or slug.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`rate_limited`, 120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Products"],"security":[{"bearerAuth":[]}],"x-required-scope":"catalog:write","operationId":"archiveProduct","summary":"Archive a product","description":"Never deletes. Sets status `archived` and switches the product off; orders and reports keep it. PATCH `status: active` restores it.","responses":{"200":{"description":"Archived","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ArchiveResult"}}},"example":{"data":{"id":"clx8p2k0f0001","status":"archived","archived":true,"deleted":false,"alreadyArchived":false}}}}},"401":{"description":"Missing or invalid API token (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The token lacks the required scope (`forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such product.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`rate_limited`, 120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/products/{id}/variants":{"parameters":[{"name":"id","in":"path","required":true,"description":"Product id, slug or SKU.","schema":{"type":"string"}}],"get":{"tags":["Products"],"security":[{"bearerAuth":[]}],"x-required-scope":"catalog:read","operationId":"listProductVariants","summary":"List a product's variants","description":"All variants (max 500) in one page.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Variant"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"401":{"description":"Missing or invalid API token (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The token lacks the required scope (`forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such product.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`rate_limited`, 120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/variants/{id}":{"parameters":[{"name":"id","in":"path","required":true,"description":"Variant id.","schema":{"type":"string"}}],"patch":{"tags":["Products"],"security":[{"bearerAuth":[]}],"x-required-scope":"catalog:write","operationId":"updateVariant","summary":"Update a variant","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VariantUpdate"},"example":{"price":95,"sku":"TSH-RED-M","stock":12}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"allOf":[{"$ref":"#/components/schemas/Variant"},{"type":"object","properties":{"stockChange":{"type":"object","properties":{"before":{"type":"integer"},"after":{"type":"integer"}}}}}]}}},"example":{"data":{"id":"cmb_01hx9k2v7","productId":"clx8p2k0f0001","sku":"TSH-RED-M","barcode":"6281234567897","optionValues":[{"group":"اللون","groupEn":"Colour","value":"أحمر","valueEn":"Red"},{"group":"المقاس","groupEn":"Size","value":"M","valueEn":null}],"price":89,"priceInherited":true,"compareAtPrice":null,"currency":"SAR","stock":14,"trackStock":true,"isEnabled":true,"image":null,"weight":null,"weightUnit":null,"createdAt":"2026-10-01T09:12:00.000Z","updatedAt":"2026-10-18T14:03:11.000Z"}}}}},"401":{"description":"Missing or invalid API token (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The token lacks the required scope (`forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such variant.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Duplicate SKU/barcode, or stock refused (`details.reason`: stock_not_tracked); other fields in the request were saved when `details.otherFieldsSaved` is true.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`rate_limited`, 120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/inventory":{"get":{"tags":["Inventory"],"security":[{"bearerAuth":[]}],"x-required-scope":"catalog:read","operationId":"getInventory","summary":"Stock levels","description":"With `sku`: the lines for those SKUs (unpaged) plus `notFound`. Without: every non-archived product, paged by product, one line per variant (or one per product without variants).","parameters":[{"name":"sku","in":"query","required":false,"description":"Comma-separated SKUs, max 200.","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"Page number, from 1.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","required":false,"description":"Page size (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"oneOf":[{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/InventoryLine"}},"notFound":{"type":"array","items":{"type":"string"}}}}}},{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/InventoryLine"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}]},"example":{"data":{"items":[{"productId":"clx8p2k0f0001","variantId":"cmb_01hx9k2v7","sku":"TSH-RED-M","barcode":null,"name":"تيشيرت قطن","nameEn":"Cotton T-shirt","optionValues":[{"group":"المقاس","value":"M"}],"trackStock":true,"stock":14,"branches":[{"branchId":"clbr01","branchName":"الرياض","branchCode":"RUH","onHand":10,"reserved":1,"available":9}]}],"notFound":["UNKNOWN-1"]}}}}},"401":{"description":"Missing or invalid API token (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The token lacks the required scope (`forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Bad `sku` list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`rate_limited`, 120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Inventory"],"security":[{"bearerAuth":[]}],"x-required-scope":"catalog:write","operationId":"updateInventory","summary":"Bulk set / adjust stock","description":"1 to 200 items, each applied independently through the stock ledger (a StockMovement row per change, actor = the token). The response is 200 with a per-item result; check `ok` on each. Stock never goes below zero.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","minItems":1,"maxItems":200,"items":{"$ref":"#/components/schemas/InventoryUpdateItem"}}}},"example":{"items":[{"sku":"TSH-RED-M","quantity":40,"mode":"set","reason":"STOCKTAKE"},{"sku":"TSH-RED-L","quantity":-2,"mode":"adjust","reason":"DAMAGE","note":"ERP doc 8812"},{"variantId":"cmb_01hx9k2v8","quantity":5,"mode":"set","branchId":"clbr01"}]}}}},"responses":{"200":{"description":"Per-item results","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/InventoryUpdateResult"}}},"example":{"data":{"results":[{"index":0,"ok":true,"sku":"TSH-RED-M","productId":"clx8p2k0f0001","variantId":"cmb_01hx9k2v7","branchId":null,"before":14,"after":40,"changed":true},{"index":1,"ok":false,"error":{"code":"not_found","message":"No product or variant has SKU \"TSH-RED-L\"."}}],"summary":{"total":2,"succeeded":1,"failed":1}}}}}},"401":{"description":"Missing or invalid API token (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The token lacks the required scope (`forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`items` missing, empty or over 200.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`rate_limited`, 120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/categories":{"get":{"tags":["Categories"],"security":[{"bearerAuth":[]}],"x-required-scope":"catalog:read","operationId":"listCategories","summary":"List categories","description":"In the merchant's order. Rows carry `parentId`; a full listing rebuilds the tree.","parameters":[{"name":"parent_id","in":"query","required":false,"description":"Children of this category; `root` for top-level categories.","schema":{"type":"string"}},{"name":"include_archived","in":"query","required":false,"description":"Include archived categories.","schema":{"type":"boolean"}},{"name":"with_counts","in":"query","required":false,"description":"Add productCount (whole subtree).","schema":{"type":"boolean"}},{"name":"page","in":"query","required":false,"description":"Page number, from 1.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","required":false,"description":"Page size (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":100}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Category"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"401":{"description":"Missing or invalid API token (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The token lacks the required scope (`forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`rate_limited`, 120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Categories"],"security":[{"bearerAuth":[]}],"x-required-scope":"catalog:write","operationId":"createCategory","summary":"Create a category","requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/CategoryInput"},{"required":["name"]}]},"example":{"name":"أحذية","nameEn":"Shoes","parentId":"clc1cat0001"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Category"}}},"example":{"data":{"id":"clc1cat0001","name":"ملابس رجالية","nameEn":"Men's clothing","slug":"ملابس-رجالية","slugEn":"mens-clothing","parentId":null,"sortOrder":0,"isHidden":false,"isArchived":false,"description":null,"descriptionEn":null,"fullDescription":null,"fullDescriptionEn":null,"image":null,"createdAt":"2026-09-01T10:00:00.000Z"}}}}},"401":{"description":"Missing or invalid API token (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The token lacks the required scope (`forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid field, unknown parent, cycle or too deep (details.reason).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`rate_limited`, 120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/categories/{id}":{"parameters":[{"name":"id","in":"path","required":true,"description":"Category id.","schema":{"type":"string"}}],"get":{"tags":["Categories"],"security":[{"bearerAuth":[]}],"x-required-scope":"catalog:read","operationId":"getCategory","summary":"Get a category","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Category"}}},"example":{"data":{"id":"clc1cat0001","name":"ملابس رجالية","nameEn":"Men's clothing","slug":"ملابس-رجالية","slugEn":"mens-clothing","parentId":null,"sortOrder":0,"isHidden":false,"isArchived":false,"description":null,"descriptionEn":null,"fullDescription":null,"fullDescriptionEn":null,"image":null,"createdAt":"2026-09-01T10:00:00.000Z"}}}}},"401":{"description":"Missing or invalid API token (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The token lacks the required scope (`forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such category.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`rate_limited`, 120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Categories"],"security":[{"bearerAuth":[]}],"x-required-scope":"catalog:write","operationId":"updateCategory","summary":"Update a category","description":"Only the fields sent are written. Renaming keeps the URL. Moving (parentId) moves the whole subtree.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryInput"},"example":{"nameEn":"Footwear","isHidden":false}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Category"}}}}}},"401":{"description":"Missing or invalid API token (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The token lacks the required scope (`forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such category.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`rate_limited`, 120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/brands":{"get":{"tags":["Brands"],"security":[{"bearerAuth":[]}],"x-required-scope":"catalog:read","operationId":"listBrands","summary":"List brands","parameters":[{"name":"q","in":"query","required":false,"description":"Name search (Arabic or English).","schema":{"type":"string"}},{"name":"include_archived","in":"query","required":false,"description":"Include archived brands.","schema":{"type":"boolean"}},{"name":"page","in":"query","required":false,"description":"Page number, from 1.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","required":false,"description":"Page size (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":100}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Brand"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"401":{"description":"Missing or invalid API token (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The token lacks the required scope (`forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`rate_limited`, 120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/brands/{id}":{"parameters":[{"name":"id","in":"path","required":true,"description":"Brand id or slug.","schema":{"type":"string"}}],"get":{"tags":["Brands"],"security":[{"bearerAuth":[]}],"x-required-scope":"catalog:read","operationId":"getBrand","summary":"Get a brand","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Brand"}}}}}},"401":{"description":"Missing or invalid API token (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The token lacks the required scope (`forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such brand.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`rate_limited`, 120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/store":{"get":{"tags":["Store"],"security":[{"bearerAuth":[]}],"x-required-scope":"catalog:read","operationId":"getStore","summary":"Store information","description":"Name, currency, country, timezone, languages, domains and public contact details of the token's store.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Store"}}}}}},"401":{"description":"Missing or invalid API token (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The token lacks the required scope (`forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`rate_limited`, 120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/order-statuses":{"get":{"tags":["Orders"],"security":[{"bearerAuth":[]}],"x-required-scope":"orders:read","operationId":"listOrderStatuses","summary":"Order status catalogue","description":"Every status code orders can carry, with its group and Arabic/English names. Stores that never customised statuses get the built-in set.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OrderStatusCatalog"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"401":{"description":"Missing or invalid API token (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The token lacks the required scope (`forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`rate_limited`, 120 requests per minute per token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks":{"get":{"tags":["Webhooks"],"operationId":"listWebhooks","x-required-scope":"orders:read","summary":"List webhook endpoints","description":"Requires `orders:read`. Secrets are never listed.","responses":{"200":{"description":"All endpoints of the store.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEndpoint"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"tags":["Webhooks"],"operationId":"createWebhook","summary":"Create a webhook endpoint","description":"Requires `orders:write`, plus the read scope of every subscribed event: `order.created` (orders:read), `order.updated` (orders:read), `order.status_changed` (orders:read), `order.paid` (orders:read), `order.cancelled` (orders:read), `customer.created` (customers:read), `customer.updated` (customers:read), `product.updated` (catalog:read), `inventory.updated` (catalog:read). At most 10 endpoints per store. The URL is checked at save time and before every delivery: https only, default port, and every address the host resolves to must be public.","x-required-scope":"orders:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointCreate"},"example":{"url":"https://example.com/webhooks/shofni","events":["order.created","order.status_changed"]}}}},"responses":{"201":{"description":"Created. `secret` is shown only now.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/WebhookEndpointWithSecret"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/webhooks/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"example":"wh_3f9a1c2b7d4e5f60a1"}],"get":{"tags":["Webhooks"],"operationId":"getWebhook","x-required-scope":"orders:read","summary":"Get a webhook endpoint with its recent deliveries","description":"Requires `orders:read`. `recentDeliveries` holds the last 50 attempts, newest first.","responses":{"200":{"description":"The endpoint.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"allOf":[{"$ref":"#/components/schemas/WebhookEndpoint"},{"type":"object","properties":{"recentDeliveries":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDelivery"}}}}]}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"patch":{"tags":["Webhooks"],"operationId":"updateWebhook","summary":"Update a webhook endpoint or rotate its secret","description":"Requires `orders:write` (and the read scope of any newly subscribed event).","x-required-scope":"orders:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointUpdate"},"example":{"active":false}}}},"responses":{"200":{"description":"Updated. Includes `secret` only when `rotateSecret` was true.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/WebhookEndpointWithSecret"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"}}},"delete":{"tags":["Webhooks"],"operationId":"deleteWebhook","x-required-scope":"orders:write","summary":"Delete a webhook endpoint","description":"Requires `orders:write`. Queued retries for it are dropped.","responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"deleted":{"type":"boolean","const":true}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/webhooks/{id}/test":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"example":"wh_3f9a1c2b7d4e5f60a1"}],"post":{"tags":["Webhooks"],"operationId":"testWebhook","x-required-scope":"orders:write","summary":"Send a test `ping` event","description":"Requires `orders:write`. Sends a signed `ping` now and reports the result. Logged, never retried.","responses":{"200":{"description":"Attempt result (delivered or not).","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"delivered":{"type":"boolean"},"status":{"type":["integer","null"]},"error":{"type":["string","null"]},"durationMs":{"type":"integer"},"deliveryId":{"type":"string"},"eventId":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}}},"webhooks":{"order.created":{"post":{"summary":"order.created","description":"A new order was placed: storefront checkout, POS, table/pre-order, MCP or API. Needs `orders:read` on the subscribing token.","parameters":[{"name":"X-Shofni-Event","in":"header","required":true,"schema":{"type":"string","const":"order.created"}},{"name":"X-Shofni-Delivery","in":"header","required":true,"schema":{"type":"string"}},{"name":"X-Shofni-Attempt","in":"header","required":true,"schema":{"type":"integer"}},{"name":"X-Shofni-Signature","in":"header","required":true,"schema":{"type":"string"},"example":"t=1760870400,v1=5d41402abc4b2a76b9719d911017c592..."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"order.created"},"data":{"$ref":"#/components/schemas/Order"}}}]}}}},"responses":{"2XX":{"description":"Any 2xx acknowledges the delivery. Anything else, or no answer within 5 s, is retried."}}}},"order.updated":{"post":{"summary":"order.updated","description":"An order was edited (lines, prices, customer/address details) or a POS round was added to a table order. Needs `orders:read` on the subscribing token.","parameters":[{"name":"X-Shofni-Event","in":"header","required":true,"schema":{"type":"string","const":"order.updated"}},{"name":"X-Shofni-Delivery","in":"header","required":true,"schema":{"type":"string"}},{"name":"X-Shofni-Attempt","in":"header","required":true,"schema":{"type":"integer"}},{"name":"X-Shofni-Signature","in":"header","required":true,"schema":{"type":"string"},"example":"t=1760870400,v1=5d41402abc4b2a76b9719d911017c592..."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"order.updated"},"data":{"$ref":"#/components/schemas/Order"}}}]}}}},"responses":{"2XX":{"description":"Any 2xx acknowledges the delivery. Anything else, or no answer within 5 s, is retried."}}}},"order.status_changed":{"post":{"summary":"order.status_changed","description":"The order's status moved. `data.previousStatus` holds the status it left. Needs `orders:read` on the subscribing token.","parameters":[{"name":"X-Shofni-Event","in":"header","required":true,"schema":{"type":"string","const":"order.status_changed"}},{"name":"X-Shofni-Delivery","in":"header","required":true,"schema":{"type":"string"}},{"name":"X-Shofni-Attempt","in":"header","required":true,"schema":{"type":"integer"}},{"name":"X-Shofni-Signature","in":"header","required":true,"schema":{"type":"string"},"example":"t=1760870400,v1=5d41402abc4b2a76b9719d911017c592..."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"order.status_changed"},"data":{"$ref":"#/components/schemas/Order"}}}]}}}},"responses":{"2XX":{"description":"Any 2xx acknowledges the delivery. Anything else, or no answer within 5 s, is retried."}}}},"order.paid":{"post":{"summary":"order.paid","description":"A successful capture was recorded in the payment ledger and the order is paid (gateway settle, POS tender, manual payment). Orders marked paid by a status change alone fire `order.status_changed`. Needs `orders:read` on the subscribing token.","parameters":[{"name":"X-Shofni-Event","in":"header","required":true,"schema":{"type":"string","const":"order.paid"}},{"name":"X-Shofni-Delivery","in":"header","required":true,"schema":{"type":"string"}},{"name":"X-Shofni-Attempt","in":"header","required":true,"schema":{"type":"integer"}},{"name":"X-Shofni-Signature","in":"header","required":true,"schema":{"type":"string"},"example":"t=1760870400,v1=5d41402abc4b2a76b9719d911017c592..."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"order.paid"},"data":{"$ref":"#/components/schemas/Order"}}}]}}}},"responses":{"2XX":{"description":"Any 2xx acknowledges the delivery. Anything else, or no answer within 5 s, is retried."}}}},"order.cancelled":{"post":{"summary":"order.cancelled","description":"The order entered a cancelled status (stock was returned). Needs `orders:read` on the subscribing token.","parameters":[{"name":"X-Shofni-Event","in":"header","required":true,"schema":{"type":"string","const":"order.cancelled"}},{"name":"X-Shofni-Delivery","in":"header","required":true,"schema":{"type":"string"}},{"name":"X-Shofni-Attempt","in":"header","required":true,"schema":{"type":"integer"}},{"name":"X-Shofni-Signature","in":"header","required":true,"schema":{"type":"string"},"example":"t=1760870400,v1=5d41402abc4b2a76b9719d911017c592..."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"order.cancelled"},"data":{"$ref":"#/components/schemas/Order"}}}]}}}},"responses":{"2XX":{"description":"Any 2xx acknowledges the delivery. Anything else, or no answer within 5 s, is retried."}}}},"customer.created":{"post":{"summary":"customer.created","description":"A customer record was created (dashboard, import, API, checkout, POS, storefront sign-up). Needs `customers:read` on the subscribing token.","parameters":[{"name":"X-Shofni-Event","in":"header","required":true,"schema":{"type":"string","const":"customer.created"}},{"name":"X-Shofni-Delivery","in":"header","required":true,"schema":{"type":"string"}},{"name":"X-Shofni-Attempt","in":"header","required":true,"schema":{"type":"integer"}},{"name":"X-Shofni-Signature","in":"header","required":true,"schema":{"type":"string"},"example":"t=1760870400,v1=5d41402abc4b2a76b9719d911017c592..."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"customer.created"},"data":{"$ref":"#/components/schemas/Customer"}}}]}}}},"responses":{"2XX":{"description":"Any 2xx acknowledges the delivery. Anything else, or no answer within 5 s, is retried."}}}},"customer.updated":{"post":{"summary":"customer.updated","description":"A customer's profile was edited. Needs `customers:read` on the subscribing token.","parameters":[{"name":"X-Shofni-Event","in":"header","required":true,"schema":{"type":"string","const":"customer.updated"}},{"name":"X-Shofni-Delivery","in":"header","required":true,"schema":{"type":"string"}},{"name":"X-Shofni-Attempt","in":"header","required":true,"schema":{"type":"integer"}},{"name":"X-Shofni-Signature","in":"header","required":true,"schema":{"type":"string"},"example":"t=1760870400,v1=5d41402abc4b2a76b9719d911017c592..."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"customer.updated"},"data":{"$ref":"#/components/schemas/Customer"}}}]}}}},"responses":{"2XX":{"description":"Any 2xx acknowledges the delivery. Anything else, or no answer within 5 s, is retried."}}}},"product.updated":{"post":{"summary":"product.updated","description":"A product was created or a versioned field changed (dashboard, bulk edit, import, API). Stock-only changes fire `inventory.updated` instead. Needs `catalog:read` on the subscribing token.","parameters":[{"name":"X-Shofni-Event","in":"header","required":true,"schema":{"type":"string","const":"product.updated"}},{"name":"X-Shofni-Delivery","in":"header","required":true,"schema":{"type":"string"}},{"name":"X-Shofni-Attempt","in":"header","required":true,"schema":{"type":"integer"}},{"name":"X-Shofni-Signature","in":"header","required":true,"schema":{"type":"string"},"example":"t=1760870400,v1=5d41402abc4b2a76b9719d911017c592..."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"product.updated"},"data":{"$ref":"#/components/schemas/Product"}}}]}}}},"responses":{"2XX":{"description":"Any 2xx acknowledges the delivery. Anything else, or no answer within 5 s, is retried."}}}},"inventory.updated":{"post":{"summary":"inventory.updated","description":"Stock moved through the stock ledger: manual adjustments, counts, receiving, cancellations/returns, API. Storefront checkout sales are reflected by `order.created`. Needs `catalog:read` on the subscribing token.","parameters":[{"name":"X-Shofni-Event","in":"header","required":true,"schema":{"type":"string","const":"inventory.updated"}},{"name":"X-Shofni-Delivery","in":"header","required":true,"schema":{"type":"string"}},{"name":"X-Shofni-Attempt","in":"header","required":true,"schema":{"type":"integer"}},{"name":"X-Shofni-Signature","in":"header","required":true,"schema":{"type":"string"},"example":"t=1760870400,v1=5d41402abc4b2a76b9719d911017c592..."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"inventory.updated"},"data":{"$ref":"#/components/schemas/InventoryUpdatedData"}}}]}}}},"responses":{"2XX":{"description":"Any 2xx acknowledges the delivery. Anything else, or no answer within 5 s, is retried."}}}},"ping":{"post":{"summary":"ping","description":"Sent by POST /webhooks/{id}/test.","parameters":[{"name":"X-Shofni-Event","in":"header","required":true,"schema":{"type":"string","const":"ping"}},{"name":"X-Shofni-Delivery","in":"header","required":true,"schema":{"type":"string"}},{"name":"X-Shofni-Attempt","in":"header","required":true,"schema":{"type":"integer"}},{"name":"X-Shofni-Signature","in":"header","required":true,"schema":{"type":"string"},"example":"t=1760870400,v1=5d41402abc4b2a76b9719d911017c592..."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"ping"},"data":{"type":"object"}}}]}}}},"responses":{"2XX":{"description":"Any 2xx acknowledges the delivery. Anything else, or no answer within 5 s, is retried."}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"shf_<token>","description":"Settings > API tokens in the Shofni dashboard."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["unauthorized","forbidden","not_found","validation_failed","conflict","rate_limited","internal_error"]},"message":{"type":"string","description":"English, for humans. Switch on `code`, not on this."},"details":{"description":"Optional. `details.field` names the offending field on validation_failed."}}}}},"Pagination":{"type":"object","required":["page","limit","total","totalPages"],"properties":{"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0},"totalPages":{"type":"integer","minimum":1}}},"LocalizedText":{"type":"object","properties":{"ar":{"type":"string"},"en":{"type":"string"}}},"OrderStatus":{"type":"object","description":"A status code as THIS store defines it (stores can customise statuses).","properties":{"code":{"type":"string"},"group":{"type":["string","null"],"enum":["NEW","IN_PROGRESS","SHIPPED","DELIVERED","CANCELLED","RETURNED",null]},"name":{"$ref":"#/components/schemas/LocalizedText"},"customerName":{"$ref":"#/components/schemas/LocalizedText","description":"Wording shown to the customer."}}},"PaymentStatus":{"type":"string","enum":["paid","unpaid","failed","authorized","refunded_partial","refunded_full","refund_failed"]},"OrderPaymentMethod":{"type":"object","properties":{"code":{"type":"string","description":"As stored (e.g. cod, cash, card, bank_transfer, mada, fatoorah)."},"group":{"type":"string","enum":["cash","card","transfer","cod","online","wallet","dine_in","other"]}}},"OrderCustomerRef":{"type":"object","properties":{"id":{"type":["string","null"]},"name":{"type":["string","null"]},"phone":{"type":["string","null"]},"email":{"type":["string","null"]}}},"OrderSummary":{"type":"object","properties":{"id":{"type":"string"},"number":{"type":"string","description":"Visible order number (no `#`)."},"status":{"$ref":"#/components/schemas/OrderStatus"},"paymentStatus":{"$ref":"#/components/schemas/PaymentStatus"},"paymentMethod":{"$ref":"#/components/schemas/OrderPaymentMethod"},"currency":{"type":["string","null"]},"total":{"type":"number","description":"In the order's `currency`."},"amountPaid":{"type":"number","description":"In the order's `currency`."},"channel":{"type":"string","description":"store | pos | app | whatsapp | phone | manual | external ..."},"source":{"type":["string","null"],"description":"\"api\" for orders created through this API."},"serviceType":{"type":["string","null"]},"itemCount":{"type":"integer"},"customer":{"$ref":"#/components/schemas/OrderCustomerRef"},"trackingNumber":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"example":{"id":"483920","number":"483920","status":{"code":"PENDING","group":"NEW","name":{"ar":"جديد","en":"New"},"customerName":{"ar":"تم استلام طلبك","en":"Order received"}},"paymentStatus":"paid","paymentMethod":{"code":"card","group":"card"},"currency":"SAR","total":27,"amountPaid":27,"channel":"external","source":"api","serviceType":"delivery","itemCount":2,"customer":{"id":"clx1cust","name":"سارة أحمد","phone":"966551112233","email":"sara@example.com"},"trackingNumber":"AWB123","createdAt":"2026-10-19T08:00:00.000Z","updatedAt":"2026-10-19T08:05:00.000Z"}},"OrderLineItem":{"type":"object","properties":{"productId":{"type":["string","null"]},"variantId":{"type":["string","null"],"description":"Product combination id when the line is a specific variant."},"sku":{"type":["string","null"]},"name":{"type":"string"},"nameEn":{"type":["string","null"]},"options":{"type":"array","items":{"type":"object","properties":{"name":{"type":["string","null"]},"nameEn":{"type":["string","null"]},"value":{"type":["string","null"]},"valueEn":{"type":["string","null"]}}}},"variantLabel":{"type":["string","null"]},"addons":{"type":"array","items":{"type":"string"}},"note":{"type":["string","null"]},"quantity":{"type":"integer"},"unitPrice":{"type":"number","description":"Net unit price charged."},"listUnitPrice":{"type":"number","description":"In the order's `currency`."},"discount":{"type":"number","description":"Line discount plus this line's share of order-level discounts."},"tax":{"type":"number","description":"In the order's `currency`."},"lineTotal":{"type":"number","description":"In the order's `currency`."}}},"OrderTotals":{"type":"object","properties":{"subtotal":{"type":"number","description":"In the order's `currency`."},"listSubtotal":{"type":"number","description":"In the order's `currency`."},"discountTotal":{"type":"number","description":"In the order's `currency`."},"couponDiscount":{"type":"number","description":"In the order's `currency`."},"offerDiscount":{"type":"number","description":"In the order's `currency`."},"discounts":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string"},"label":{"type":"string"},"labelEn":{"type":"string"},"amount":{"type":"number","description":"In the order's `currency`."}}}},"shipping":{"type":"number","description":"In the order's `currency`."},"codFee":{"type":"number","description":"In the order's `currency`."},"fees":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["SHIPPING","COD","PACKAGING","SERVICE","MANUAL","OTHER"]},"label":{"type":"string"},"labelEn":{"type":"string"},"amount":{"type":"number","description":"In the order's `currency`."}}}},"tax":{"type":"number","description":"In the order's `currency`."},"taxInclusive":{"type":"boolean"},"total":{"type":"number","description":"In the order's `currency`."},"amountPaid":{"type":"number","description":"In the order's `currency`."},"amountRefunded":{"type":"number","description":"In the order's `currency`."},"amountDue":{"type":"number","description":"In the order's `currency`."}}},"OrderAddress":{"type":"object","properties":{"name":{"type":["string","null"]},"phone":{"type":["string","null"]},"country":{"type":["string","null"]},"region":{"type":["string","null"]},"city":{"type":["string","null"]},"district":{"type":["string","null"]},"street":{"type":["string","null"]},"building":{"type":["string","null"]},"unit":{"type":["string","null"]},"postalCode":{"type":["string","null"]},"shortAddress":{"type":["string","null"],"description":"Saudi National Address short code."},"additionalNumber":{"type":["string","null"],"description":"Saudi National Address additional number."},"coordinates":{"type":["object","null"],"properties":{"lat":{"type":"number"},"lng":{"type":"number"}}}}},"OrderShipping":{"type":"object","properties":{"method":{"type":["string","null"],"description":"HOME_DELIVERY | BRANCH_PICKUP | INTERNATIONAL | CURBSIDE | DINE_IN | DIGITAL"},"carrierCode":{"type":["string","null"]},"carrierName":{"type":["string","null"]},"trackingNumber":{"type":["string","null"]},"trackingUrl":{"type":["string","null"],"description":"Derived from the carrier; null when the carrier has no public tracking page."},"labelStatus":{"type":["string","null"]},"shipmentStatus":{"type":["string","null"]}}},"Order":{"type":"object","properties":{"id":{"type":"string"},"number":{"type":"string"},"status":{"$ref":"#/components/schemas/OrderStatus"},"paymentStatus":{"$ref":"#/components/schemas/PaymentStatus"},"paymentMethod":{"$ref":"#/components/schemas/OrderPaymentMethod"},"currency":{"type":["string","null"]},"channel":{"type":"string"},"source":{"type":["string","null"]},"serviceType":{"type":["string","null"]},"totals":{"$ref":"#/components/schemas/OrderTotals"},"lineItems":{"type":"array","items":{"$ref":"#/components/schemas/OrderLineItem"}},"customer":{"$ref":"#/components/schemas/OrderCustomerRef"},"shippingAddress":{"$ref":"#/components/schemas/OrderAddress"},"shipping":{"$ref":"#/components/schemas/OrderShipping"},"notes":{"type":"object","properties":{"customer":{"type":["string","null"],"description":"The customer's own note on the order."},"staff":{"type":"array","description":"Internal staff notes (not shown to the customer). Deleted notes are omitted.","items":{"type":"object","properties":{"id":{"type":"string"},"body":{"type":["string","null"]},"authorName":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"}}}}}},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"example":{"id":"483920","number":"483920","status":{"code":"PENDING","group":"NEW","name":{"ar":"جديد","en":"New"},"customerName":{"ar":"تم استلام طلبك","en":"Order received"}},"paymentStatus":"paid","paymentMethod":{"code":"card","group":"card"},"currency":"SAR","channel":"external","source":"api","serviceType":"delivery","totals":{"subtotal":27,"listSubtotal":27,"discountTotal":0,"couponDiscount":0,"offerDiscount":0,"discounts":[],"shipping":0,"codFee":0,"fees":[],"tax":0,"taxInclusive":false,"total":27,"amountPaid":27,"amountRefunded":0,"amountDue":0},"lineItems":[{"productId":"clx1burger","variantId":null,"sku":"BRG-01","name":"برجر","nameEn":"Burger","options":[],"variantLabel":null,"addons":[],"note":"بدون بصل","quantity":2,"unitPrice":10,"listUnitPrice":10,"discount":0,"tax":0,"lineTotal":20}],"customer":{"id":"clx1cust","name":"سارة أحمد","phone":"+966 55 111 2233","email":"sara@example.com"},"shippingAddress":{"name":"سارة أحمد","phone":"966551112233","country":null,"region":null,"city":"الرياض","district":"العليا","street":"شارع التحلية","building":"12","unit":null,"postalCode":null,"shortAddress":"RRRD2929","additionalNumber":null,"coordinates":{"lat":24.7,"lng":46.68}},"shipping":{"method":"HOME_DELIVERY","carrierCode":"aramex","carrierName":"Aramex","trackingNumber":"AWB123","trackingUrl":"https://www.aramex.com/track/results?ShipmentNumber=AWB123","labelStatus":"ISSUED","shipmentStatus":null},"notes":{"customer":"اتصل قبل الوصول","staff":[{"id":"clx1note","body":"VIP","authorName":"API: ERP","createdAt":"2026-10-19T08:00:00.000Z"}]},"tags":[],"createdAt":"2026-10-19T08:00:00.000Z","updatedAt":"2026-10-19T08:05:00.000Z"}},"OrderCreateItem":{"type":"object","required":["quantity"],"description":"Name the product by `productId`, by `variantId` (a product combination), or by `sku` (variant SKU first, then product SKU). Prices are always the store's own; `unitPrice`/`price` are refused.","properties":{"productId":{"type":"string"},"variantId":{"type":"string"},"sku":{"type":"string"},"quantity":{"type":"integer","minimum":1,"maximum":1000},"variant":{"type":"string","description":"Free-text variant label for products with simple (non-combination) variants."},"addons":{"type":"array","items":{"type":"string"},"description":"Add-on names; each one's price is added by the server."},"note":{"type":"string","maxLength":300}}},"OrderCreateRequest":{"type":"object","required":["items","customer"],"properties":{"items":{"type":"array","minItems":1,"maxItems":150,"items":{"$ref":"#/components/schemas/OrderCreateItem"}},"customer":{"type":"object","description":"Either `{ id }` of an existing customer of this store, or `{ phone, name?, email? }`: the phone is matched against the store's customers in every spelling; a new customer is created (source API) when none matches. Existing names/emails are never overwritten, only filled in when empty.","properties":{"id":{"type":"string"},"phone":{"type":"string","minLength":5,"maxLength":30},"name":{"type":"string","maxLength":120},"email":{"type":"string","format":"email"}}},"serviceType":{"type":"string","enum":["delivery","pickup","dine_in"],"description":"Default: delivery when shippingAddress is given, else pickup. Delivery needs shippingAddress.street or shippingAddress.shortAddress."},"shippingAddress":{"type":"object","properties":{"name":{"type":"string"},"phone":{"type":"string"},"country":{"type":"string"},"region":{"type":"string"},"city":{"type":"string"},"district":{"type":"string"},"street":{"type":"string","maxLength":200},"building":{"type":"string"},"unit":{"type":"string"},"postalCode":{"type":"string"},"shortAddress":{"type":"string","description":"Saudi National Address short code."},"additionalNumber":{"type":"string"},"latitude":{"type":"number","minimum":-90,"maximum":90},"longitude":{"type":"number","minimum":-180,"maximum":180}}},"paymentMethod":{"type":"string","enum":["cod","cash","card","bank_transfer"],"default":"cod"},"paid":{"type":"boolean","default":false,"description":"true records a successful capture for the full total on the payment ledger (gateway \"api\"). Not allowed with cod. No money is charged by this API."},"note":{"type":"string","maxLength":1000,"description":"Customer-facing order note."},"staffNote":{"type":"string","maxLength":4000,"description":"Internal staff note added to the order."},"channel":{"type":"string","maxLength":40,"description":"Origin label. STORE, POS, APP, WHATSAPP or PHONE is stored as the order channel; any other text is kept as a free-form label. `source` is always \"api\"."}},"example":{"items":[{"productId":"clx1burger","quantity":2,"note":"بدون بصل"},{"sku":"CAKE-01","quantity":1}],"customer":{"name":"سارة أحمد","phone":"+966551112233","email":"sara@example.com"},"serviceType":"delivery","shippingAddress":{"city":"الرياض","district":"العليا","street":"شارع التحلية","building":"12","shortAddress":"RRRD2929","latitude":24.7,"longitude":46.68},"paymentMethod":"card","paid":true,"note":"اتصل قبل الوصول","staffNote":"VIP","channel":"erp-x"}},"OrderStatusChangeRequest":{"type":"object","required":["status"],"properties":{"status":{"type":"string","description":"A status code this store defines (see GET /order-statuses)."},"reason":{"type":"string","maxLength":500,"description":"Required by some transitions (e.g. cancellation, return)."},"notify":{"type":"boolean","const":true,"description":"Only `true` (the default) is accepted: customer notifications follow the store's templates for the new status and cannot be suppressed through the API."}},"example":{"status":"CANCELLED","reason":"طلب العميل"}},"OrderNoteRequest":{"type":"object","required":["body"],"properties":{"body":{"type":"string","maxLength":4000,"description":"@name mentions an employee of this store."}},"example":{"body":"تم التحقق من العنوان"}},"OrderNote":{"type":"object","properties":{"id":{"type":"string"},"orderId":{"type":"string"},"body":{"type":"string"},"authorName":{"type":"string","description":"\"API: <token name>\""},"createdAt":{"type":"string","format":"date-time"},"unresolvedMentions":{"type":"array","items":{"type":"string"}}}},"OrderShippingRequest":{"type":"object","required":["carrier","trackingNumber"],"properties":{"carrier":{"type":"string","description":"Carrier code: fastcoo, redbox, aramex, smsa, naqel, spl, imile, oto, deliveryone, ..."},"trackingNumber":{"type":"string","maxLength":120},"serviceCode":{"type":"string"}},"example":{"carrier":"aramex","trackingNumber":"AWB123"}},"CustomerAddress":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":["string","null"]},"name":{"type":["string","null"]},"phone":{"type":["string","null"]},"country":{"type":["string","null"]},"region":{"type":["string","null"]},"city":{"type":["string","null"]},"district":{"type":["string","null"]},"street":{"type":["string","null"]},"building":{"type":["string","null"]},"unit":{"type":["string","null"]},"postalCode":{"type":["string","null"]},"shortAddress":{"type":["string","null"]},"coordinates":{"type":["object","null"],"properties":{"lat":{"type":"number"},"lng":{"type":"number"}}},"isDefaultShipping":{"type":"boolean"},"isDefaultBilling":{"type":"boolean"}}},"Customer":{"type":"object","properties":{"id":{"type":"string"},"number":{"type":["integer","null"],"description":"Short per-store customer number."},"name":{"type":["string","null"]},"phone":{"type":"string","description":"As stored by the store (canonical digits, international form)."},"email":{"type":["string","null"]},"emailVerified":{"type":"boolean"},"marketingOptIn":{"type":"boolean"},"language":{"type":["string","null"],"enum":["ar","en",null]},"country":{"type":["string","null"]},"status":{"type":"string","enum":["ACTIVE","UNVERIFIED","SUSPENDED","ARCHIVED","DELETED_BY_REQUEST"]},"source":{"type":["string","null"],"enum":["STORE","APP","POS","BRANCH","IMPORT","DASHBOARD","API",null]},"tags":{"type":"array","items":{"type":"string"}},"loyaltyPoints":{"type":"integer"},"walletBalance":{"type":"number","description":"In the store currency."},"orderCount":{"type":"integer","description":"Orders excluding cancelled ones and open table baskets."},"totalSpent":{"type":"object","additionalProperties":{"type":"number"},"description":"Order totals per currency, cancelled orders excluded."},"lastOrderAt":{"type":["string","null"],"format":"date-time"},"registeredAt":{"type":["string","null"],"format":"date-time"},"addresses":{"type":"array","items":{"$ref":"#/components/schemas/CustomerAddress"},"description":"Only on single-customer responses (GET/POST/PATCH), not in lists."}},"example":{"id":"clx1cust","number":42,"name":"خالد سعيد","phone":"966559998877","email":"khaled@example.com","emailVerified":false,"marketingOptIn":false,"language":"ar","country":null,"status":"ACTIVE","source":"API","tags":["wholesale"],"loyaltyPoints":120,"walletBalance":15.5,"orderCount":3,"totalSpent":{"SAR":840},"lastOrderAt":"2026-10-18T19:22:00.000Z","registeredAt":"2026-09-01T10:00:00.000Z","addresses":[{"id":"clx1addr","label":"المنزل","name":null,"phone":null,"country":null,"region":null,"city":"جدة","district":null,"street":"شارع فلسطين","building":null,"unit":null,"postalCode":null,"shortAddress":"JEDA1234","coordinates":null,"isDefaultShipping":true,"isDefaultBilling":true}]}},"CustomerCreateRequest":{"type":"object","required":["phone"],"properties":{"phone":{"type":"string","description":"E.164 (`+` and 8 to 15 digits; spaces and dashes are ignored). Stored in the store's canonical form."},"name":{"type":"string","maxLength":120},"email":{"type":"string","format":"email"},"language":{"type":"string","enum":["ar","en"]},"tags":{"type":"array","items":{"type":"string"}},"addresses":{"type":"array","maxItems":20,"items":{"type":"object","description":"At least one of city, street, district, region, building or shortAddress. The first address becomes the default.","properties":{"label":{"type":"string"},"name":{"type":"string"},"phone":{"type":"string"},"country":{"type":"string"},"region":{"type":"string"},"city":{"type":"string"},"district":{"type":"string"},"street":{"type":"string"},"building":{"type":"string"},"unit":{"type":"string"},"postalCode":{"type":"string"},"shortAddress":{"type":"string","description":"Saudi National Address short code."},"latitude":{"type":"number","minimum":-90,"maximum":90},"longitude":{"type":"number","minimum":-180,"maximum":180},"isDefaultShipping":{"type":"boolean"},"isDefaultBilling":{"type":"boolean"}}}}},"example":{"name":"خالد","phone":"+966559998877","email":"khaled@example.com","tags":["wholesale"],"addresses":[{"label":"المنزل","city":"جدة","street":"شارع فلسطين","shortAddress":"JEDA1234"}]}},"CustomerUpdateRequest":{"type":"object","description":"Only the fields sent are changed.","properties":{"name":{"type":["string","null"],"maxLength":120},"email":{"type":["string","null"],"format":"email","description":"Changing it resets emailVerified."},"phone":{"type":"string","description":"E.164. 409 if another customer of this store has it in any spelling."},"language":{"type":["string","null"],"enum":["ar","en",null]},"tags":{"type":"array","items":{"type":"string"},"description":"Replaces the current tag set."},"note":{"type":"string","maxLength":4000,"description":"Appends one internal note to the customer (existing notes are not editable here)."}},"example":{"name":"خالد سعيد","tags":["vip"],"note":"عميل جملة"}},"OptionValue":{"type":"object","properties":{"group":{"type":["string","null"]},"groupEn":{"type":["string","null"]},"value":{"type":["string","null"]},"valueEn":{"type":["string","null"]}}},"OptionGroup":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"nameEn":{"type":["string","null"]},"required":{"type":"boolean"},"values":{"type":"array","items":{"type":"object","properties":{"code":{"type":["string","null"]},"label":{"type":["string","null"]},"labelEn":{"type":["string","null"]},"priceDelta":{"type":"number"}}}}}},"Variant":{"type":"object","description":"A sellable combination of option values, with its own SKU, price and stock.","properties":{"id":{"type":"string"},"productId":{"type":"string"},"sku":{"type":["string","null"]},"barcode":{"type":["string","null"]},"optionValues":{"type":"array","items":{"$ref":"#/components/schemas/OptionValue"}},"price":{"type":"number","description":"The variant's price; the product price when `priceInherited`."},"priceInherited":{"type":"boolean"},"compareAtPrice":{"type":["number","null"]},"currency":{"type":"string"},"stock":{"type":"integer"},"trackStock":{"type":"boolean","description":"The parent product's tracking flag."},"isEnabled":{"type":"boolean"},"image":{"type":["string","null"],"format":"uri"},"weight":{"type":["number","null"]},"weightUnit":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"example":{"id":"cmb_01hx9k2v7","productId":"clx8p2k0f0001","sku":"TSH-RED-M","barcode":"6281234567897","optionValues":[{"group":"اللون","groupEn":"Colour","value":"أحمر","valueEn":"Red"},{"group":"المقاس","groupEn":"Size","value":"M","valueEn":null}],"price":89,"priceInherited":true,"compareAtPrice":null,"currency":"SAR","stock":14,"trackStock":true,"isEnabled":true,"image":null,"weight":null,"weightUnit":null,"createdAt":"2026-10-01T09:12:00.000Z","updatedAt":"2026-10-18T14:03:11.000Z"}},"Product":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"nameEn":{"type":["string","null"]},"slug":{"type":["string","null"]},"slugEn":{"type":["string","null"]},"url":{"type":["string","null"],"format":"uri","description":"Storefront product page."},"description":{"type":["string","null"]},"descriptionEn":{"type":["string","null"]},"longDescription":{"type":["string","null"]},"longDescriptionEn":{"type":["string","null"]},"status":{"type":"string","enum":["active","scheduled","draft","archived"]},"isActive":{"type":"boolean"},"isHidden":{"type":"boolean"},"isFeatured":{"type":"boolean"},"sku":{"type":["string","null"]},"barcode":{"type":["string","null"]},"price":{"type":"number","description":"Base price."},"compareAtPrice":{"type":["number","null"]},"effectivePrice":{"type":"number","description":"Price after price lists and scheduled sales, for an anonymous web shopper in the store's home market."},"onSale":{"type":"boolean","description":"effectivePrice is below price."},"cost":{"type":["number","null"]},"currency":{"type":"string","description":"ISO 4217 store currency for every amount on this object."},"trackStock":{"type":"boolean"},"stock":{"type":["integer","null"],"description":"Null when stock is not tracked. For a product with variants, the sum of theirs."},"images":{"type":"array","items":{"type":"string","format":"uri"}},"categoryId":{"type":["string","null"]},"categoryIds":{"type":"array","items":{"type":"string"}},"brand":{"oneOf":[{"type":"null"},{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"nameEn":{"type":["string","null"]}}}]},"tags":{"type":"array","items":{"type":"string"}},"options":{"type":"array","items":{"$ref":"#/components/schemas/OptionGroup"}},"variants":{"type":"array","items":{"$ref":"#/components/schemas/Variant"}},"weight":{"type":"object","properties":{"net":{"type":["number","null"]},"gross":{"type":["number","null"]},"unit":{"type":["string","null"]}}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"warnings":{"type":"array","items":{"type":"string"},"description":"Create only, when something optional (e.g. opening stock) was not applied."}},"example":{"id":"clx8p2k0f0001","name":"تيشيرت قطن","nameEn":"Cotton T-shirt","slug":"تيشيرت-قطن","slugEn":"cotton-t-shirt","url":"https://mystore.shofniplus.com/products/%D8%AA%D9%8A%D8%B4%D9%8A%D8%B1%D8%AA-%D9%82%D8%B7%D9%86","description":"قطن مصري 100%","descriptionEn":"100% Egyptian cotton","longDescription":null,"longDescriptionEn":null,"status":"active","isActive":true,"isHidden":false,"isFeatured":false,"sku":"TSH-001","barcode":null,"price":89,"compareAtPrice":120,"effectivePrice":79,"onSale":true,"cost":35,"currency":"SAR","trackStock":true,"stock":14,"images":["https://mystore.shofniplus.com/uploads/clt0abc/1729250000000-a1b2-front.webp"],"categoryId":"clc1cat0001","categoryIds":["clc1cat0001","clc1cat0007"],"brand":{"id":"clb1brand01","name":"نسيج","nameEn":"Naseej"},"tags":["صيفي"],"options":[{"id":"clv1opt0001","name":"المقاس","nameEn":"Size","required":true,"values":[{"code":"m","label":"M","labelEn":null,"priceDelta":0},{"code":"l","label":"L","labelEn":null,"priceDelta":5}]}],"variants":[{"id":"cmb_01hx9k2v7","productId":"clx8p2k0f0001","sku":"TSH-RED-M","barcode":"6281234567897","optionValues":[{"group":"اللون","groupEn":"Colour","value":"أحمر","valueEn":"Red"},{"group":"المقاس","groupEn":"Size","value":"M","valueEn":null}],"price":89,"priceInherited":true,"compareAtPrice":null,"currency":"SAR","stock":14,"trackStock":true,"isEnabled":true,"image":null,"weight":null,"weightUnit":null,"createdAt":"2026-10-01T09:12:00.000Z","updatedAt":"2026-10-18T14:03:11.000Z"}],"weight":{"net":0.25,"gross":0.3,"unit":"KG"},"createdAt":"2026-10-01T09:12:00.000Z","updatedAt":"2026-10-18T14:03:11.000Z"}},"ProductCreate":{"type":"object","additionalProperties":false,"required":["name","price"],"properties":{"name":{"type":"string","maxLength":300,"description":"Arabic name (primary; the canonical URL is built from it)."},"nameEn":{"type":["string","null"],"maxLength":300},"description":{"type":["string","null"],"maxLength":5000,"description":"Short Arabic description."},"descriptionEn":{"type":["string","null"],"maxLength":5000},"longDescription":{"type":["string","null"],"description":"Full Arabic body; simple HTML, sanitised on save."},"longDescriptionEn":{"type":["string","null"]},"slug":{"type":["string","null"],"maxLength":200,"description":"Arabic URL segment. Generated from the name when omitted. Changing it moves the public URL."},"slugEn":{"type":["string","null"],"maxLength":200,"description":"English URL alias."},"sku":{"type":["string","null"],"maxLength":120,"description":"Unique within the store (products and variants, case-insensitive)."},"barcode":{"type":["string","null"],"maxLength":120,"description":"Unique within the store; EAN/UPC check digit validated."},"price":{"type":"number","minimum":0,"description":"Base selling price in the store currency."},"compareAtPrice":{"type":["number","null"],"minimum":0,"description":"Was-price. Must be higher than `price`; null clears it."},"cost":{"type":["number","null"],"minimum":0},"status":{"type":"string","enum":["active","draft","archived"],"description":"`active` publishes and switches the product on; `archived` retires it and switches it off."},"categoryId":{"type":["string","null"],"description":"Primary category. Send this or `categoryIds`, not both."},"categoryIds":{"type":"array","maxItems":20,"items":{"type":"string"},"description":"First id is the primary category, the rest are additional categories."},"brandId":{"type":["string","null"]},"tags":{"type":"array","maxItems":50,"items":{"type":"string","maxLength":100}},"images":{"type":"array","maxItems":20,"items":{"type":"string"},"description":"Image URLs, first is the main image. Entries already on the product and this store's own media URLs are kept as-is; any other public https URL is downloaded into the store's media library (JPEG, PNG, WebP, GIF, AVIF; max 8 MB; private/internal addresses refused). Replaces the whole list."},"trackStock":{"type":"boolean","description":"Whether stock is counted. Untracked products are never out of stock."},"isFeatured":{"type":"boolean"},"isHidden":{"type":"boolean","description":"Reachable by direct link but not listed."},"options":{"type":"array","maxItems":10,"items":{"type":"object","required":["name","values"],"properties":{"name":{"type":"string","maxLength":100,"description":"Arabic group name, e.g. المقاس."},"nameEn":{"type":["string","null"],"maxLength":100},"required":{"type":"boolean","default":false},"values":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"object","required":["label"],"properties":{"label":{"type":"string","maxLength":100},"labelEn":{"type":["string","null"],"maxLength":100},"priceDelta":{"type":"number","minimum":0,"default":0,"description":"Added to the price when this value is chosen (unless the variant has its own price)."}}}}}},"description":"Option groups. Replaces all groups and regenerates the variant matrix; variants for kept combinations keep their id, SKU and stock."},"stock":{"type":"integer","minimum":0,"description":"Opening stock (turns tracking on). Written to the stock ledger as PURCHASE. Ignored with a warning when `options` create variants."}}},"ProductUpdate":{"type":"object","additionalProperties":false,"minProperties":1,"properties":{"name":{"type":"string","maxLength":300,"description":"Arabic name (primary; the canonical URL is built from it)."},"nameEn":{"type":["string","null"],"maxLength":300},"description":{"type":["string","null"],"maxLength":5000,"description":"Short Arabic description."},"descriptionEn":{"type":["string","null"],"maxLength":5000},"longDescription":{"type":["string","null"],"description":"Full Arabic body; simple HTML, sanitised on save."},"longDescriptionEn":{"type":["string","null"]},"slug":{"type":["string","null"],"maxLength":200,"description":"Arabic URL segment. Generated from the name when omitted. Changing it moves the public URL."},"slugEn":{"type":["string","null"],"maxLength":200,"description":"English URL alias."},"sku":{"type":["string","null"],"maxLength":120,"description":"Unique within the store (products and variants, case-insensitive)."},"barcode":{"type":["string","null"],"maxLength":120,"description":"Unique within the store; EAN/UPC check digit validated."},"price":{"type":"number","minimum":0,"description":"Base selling price in the store currency."},"compareAtPrice":{"type":["number","null"],"minimum":0,"description":"Was-price. Must be higher than `price`; null clears it."},"cost":{"type":["number","null"],"minimum":0},"status":{"type":"string","enum":["active","draft","archived"],"description":"`active` publishes and switches the product on; `archived` retires it and switches it off."},"categoryId":{"type":["string","null"],"description":"Primary category. Send this or `categoryIds`, not both."},"categoryIds":{"type":"array","maxItems":20,"items":{"type":"string"},"description":"First id is the primary category, the rest are additional categories."},"brandId":{"type":["string","null"]},"tags":{"type":"array","maxItems":50,"items":{"type":"string","maxLength":100}},"images":{"type":"array","maxItems":20,"items":{"type":"string"},"description":"Image URLs, first is the main image. Entries already on the product and this store's own media URLs are kept as-is; any other public https URL is downloaded into the store's media library (JPEG, PNG, WebP, GIF, AVIF; max 8 MB; private/internal addresses refused). Replaces the whole list."},"trackStock":{"type":"boolean","description":"Whether stock is counted. Untracked products are never out of stock."},"isFeatured":{"type":"boolean"},"isHidden":{"type":"boolean","description":"Reachable by direct link but not listed."},"options":{"type":"array","maxItems":10,"items":{"type":"object","required":["name","values"],"properties":{"name":{"type":"string","maxLength":100,"description":"Arabic group name, e.g. المقاس."},"nameEn":{"type":["string","null"],"maxLength":100},"required":{"type":"boolean","default":false},"values":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"object","required":["label"],"properties":{"label":{"type":"string","maxLength":100},"labelEn":{"type":["string","null"],"maxLength":100},"priceDelta":{"type":"number","minimum":0,"default":0,"description":"Added to the price when this value is chosen (unless the variant has its own price)."}}}}}},"description":"Option groups. Replaces all groups and regenerates the variant matrix; variants for kept combinations keep their id, SKU and stock."},"priceChangeReason":{"type":"string","maxLength":300,"description":"Stored on the price-change ledger."}}},"ArchiveResult":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","const":"archived"},"archived":{"type":"boolean","const":true},"deleted":{"type":"boolean","const":false},"alreadyArchived":{"type":"boolean"}}},"VariantUpdate":{"type":"object","additionalProperties":false,"minProperties":1,"properties":{"price":{"type":["number","null"],"minimum":0,"description":"Null = inherit the product price."},"compareAtPrice":{"type":["number","null"],"minimum":0},"sku":{"type":["string","null"],"maxLength":120},"barcode":{"type":["string","null"],"maxLength":120},"stock":{"type":"integer","minimum":0,"description":"New on-hand balance, written to the stock ledger (reason STOCKTAKE)."},"trackStock":{"type":"boolean","description":"Send true to switch tracking on for an untracked product together with `stock`."}}},"BranchStock":{"type":"object","properties":{"branchId":{"type":"string"},"branchName":{"type":"string"},"branchCode":{"type":["string","null"]},"onHand":{"type":"integer"},"reserved":{"type":"integer"},"available":{"type":"integer","description":"onHand - reserved - safety stock - damaged, floored at 0."}}},"InventoryLine":{"type":"object","properties":{"productId":{"type":"string"},"variantId":{"type":["string","null"],"description":"Null for a product without variants."},"sku":{"type":["string","null"]},"barcode":{"type":["string","null"]},"name":{"type":"string"},"nameEn":{"type":["string","null"]},"optionValues":{"type":"array","items":{"type":"object","properties":{"group":{"type":["string","null"]},"value":{"type":["string","null"]}}}},"trackStock":{"type":"boolean"},"stock":{"type":"integer","description":"Overall on-hand balance."},"branches":{"type":"array","items":{"$ref":"#/components/schemas/BranchStock"},"description":"Per-branch figures, for stores that keep stock per branch."}}},"InventoryUpdateItem":{"type":"object","required":["quantity"],"description":"Address the item by exactly one of `sku`, `variantId`, `productId`.","properties":{"sku":{"type":"string"},"variantId":{"type":"string"},"productId":{"type":"string","description":"Only for a product without variants."},"quantity":{"type":"integer","description":"`set`: the new balance (>= 0). `adjust`: signed change."},"mode":{"type":"string","enum":["set","adjust"],"default":"set"},"branchId":{"type":"string","description":"Apply at one branch (and to the overall balance). For `set`, sets that branch's figure."},"reason":{"type":"string","enum":["STOCKTAKE","PURCHASE","RETURN","DAMAGE","CORRECTION","SALE"],"description":"Default STOCKTAKE for set, CORRECTION for adjust."},"note":{"type":"string","maxLength":300,"description":"Stored on the stock movement (e.g. an ERP document number)."},"trackStock":{"type":"boolean","description":"Send true to switch tracking on for an untracked product with this change; otherwise such items fail with `stock_not_tracked`."}}},"InventoryUpdateResult":{"type":"object","properties":{"results":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer","description":"Position in the request's `items`."},"ok":{"type":"boolean"},"sku":{"type":"string"},"productId":{"type":"string"},"variantId":{"type":["string","null"]},"branchId":{"type":["string","null"]},"before":{"type":"integer","description":"The balance before; with branchId, that branch's figure."},"after":{"type":"integer"},"changed":{"type":"boolean"},"error":{"type":"object","properties":{"code":{"type":"string","enum":["validation_failed","not_found","ambiguous_sku","stock_not_tracked","variant_required","stock_update_failed","internal_error"]},"message":{"type":"string"}}}}}},"summary":{"type":"object","properties":{"total":{"type":"integer"},"succeeded":{"type":"integer"},"failed":{"type":"integer"}}}}},"Category":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"nameEn":{"type":["string","null"]},"slug":{"type":["string","null"]},"slugEn":{"type":["string","null"]},"parentId":{"type":["string","null"]},"sortOrder":{"type":"integer"},"isHidden":{"type":"boolean"},"isArchived":{"type":"boolean"},"description":{"type":["string","null"]},"descriptionEn":{"type":["string","null"]},"fullDescription":{"type":["string","null"]},"fullDescriptionEn":{"type":["string","null"]},"image":{"type":["string","null"]},"productCount":{"type":"integer","description":"Only with `with_counts=true`: products in this category and its whole subtree."},"createdAt":{"type":"string","format":"date-time"}},"example":{"id":"clc1cat0001","name":"ملابس رجالية","nameEn":"Men's clothing","slug":"ملابس-رجالية","slugEn":"mens-clothing","parentId":null,"sortOrder":0,"isHidden":false,"isArchived":false,"description":null,"descriptionEn":null,"fullDescription":null,"fullDescriptionEn":null,"image":null,"createdAt":"2026-09-01T10:00:00.000Z"}},"CategoryInput":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string","maxLength":200,"description":"Arabic name; required on create."},"nameEn":{"type":["string","null"]},"slug":{"type":["string","null"]},"slugEn":{"type":["string","null"]},"parentId":{"type":["string","null"],"description":"Null for top level. Refused if it would create a cycle or nest deeper than 4 levels."},"isHidden":{"type":"boolean"},"description":{"type":["string","null"]},"descriptionEn":{"type":["string","null"]},"fullDescription":{"type":["string","null"]},"fullDescriptionEn":{"type":["string","null"]},"image":{"type":["string","null"],"description":"Image or icon URL."}}},"Brand":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"nameEn":{"type":["string","null"]},"slug":{"type":["string","null"]},"slugEn":{"type":["string","null"]},"description":{"type":["string","null"]},"descriptionEn":{"type":["string","null"]},"logo":{"type":["string","null"],"format":"uri"},"isArchived":{"type":"boolean"},"sortOrder":{"type":"integer"},"productCount":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"}}},"Store":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string"},"businessType":{"type":"string"},"currency":{"type":"string","description":"ISO 4217 base currency."},"country":{"type":["string","null"],"description":"ISO 3166-1 alpha-2 home country."},"timezone":{"type":"string","description":"IANA zone, e.g. Asia/Riyadh."},"languages":{"type":"array","items":{"type":"string"}},"defaultLanguage":{"type":"string"},"storefrontUrl":{"type":["string","null"],"format":"uri"},"domains":{"type":"object","properties":{"platform":{"type":["string","null"]},"custom":{"type":["string","null"]}}},"logo":{"type":["string","null"]},"contact":{"type":"object","properties":{"phone":{"type":["string","null"]},"email":{"type":["string","null"]}}},"createdAt":{"type":"string","format":"date-time"}},"example":{"name":"متجر نسيج","slug":"naseej","businessType":"ecommerce","currency":"SAR","country":"SA","timezone":"Asia/Riyadh","languages":["ar","en"],"defaultLanguage":"ar","storefrontUrl":"https://naseej.shofniplus.com","domains":{"platform":"naseej.shofniplus.com","custom":null},"logo":null,"contact":{"phone":"+966500000000","email":null},"createdAt":"2026-01-10T08:00:00.000Z"}},"OrderStatusCatalog":{"type":"object","properties":{"code":{"type":"string","description":"The value orders carry in `status`."},"group":{"type":"string","enum":["NEW","IN_PROGRESS","SHIPPED","DELIVERED","CANCELLED","RETURNED"]},"name":{"type":"string","description":"Internal (staff) Arabic name."},"nameEn":{"type":["string","null"]},"customerName":{"type":"string","description":"What the customer sees (falls back to the group's label)."},"customerNameEn":{"type":"string"},"color":{"type":["string","null"]},"sortOrder":{"type":"integer"},"isActive":{"type":"boolean"},"isSystem":{"type":"boolean"}},"example":{"code":"SHIPPED","group":"SHIPPED","name":"تم الشحن","nameEn":"Shipped","customerName":"تم الشحن","customerNameEn":"Shipped","color":"#E0E7FF","sortOrder":1,"isActive":true,"isSystem":true}},"WebhookEventType":{"type":"string","enum":["order.created","order.updated","order.status_changed","order.paid","order.cancelled","customer.created","customer.updated","product.updated","inventory.updated"]},"WebhookEndpoint":{"type":"object","required":["id","url","events","active","secretHint","createdAt","updatedAt"],"properties":{"id":{"type":"string","example":"wh_3f9a1c2b7d4e5f60a1"},"url":{"type":"string","format":"uri","example":"https://example.com/webhooks/shofni"},"description":{"type":["string","null"],"example":"ERP sync"},"events":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEventType"}},"active":{"type":"boolean"},"secretHint":{"type":"string","description":"Last 4 characters of the signing secret.","example":"whsec_…9f2a"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"WebhookEndpointWithSecret":{"allOf":[{"$ref":"#/components/schemas/WebhookEndpoint"},{"type":"object","required":["secret"],"properties":{"secret":{"type":"string","description":"Signing secret. Returned only on create and on rotation; store it now.","example":"whsec_5b1d0c…"}}}]},"WebhookDelivery":{"type":"object","properties":{"id":{"type":"string","description":"Delivery id (X-Shofni-Delivery), stable across retries."},"eventId":{"type":"string"},"type":{"type":"string","example":"order.created"},"attempt":{"type":"integer","minimum":1,"maximum":6},"at":{"type":"string","format":"date-time"},"ok":{"type":"boolean"},"status":{"type":["integer","null"],"description":"HTTP status your server answered, null when none."},"error":{"type":["string","null"],"enum":[null,"HTTP_ERROR","TIMEOUT","UNREACHABLE","BLOCKED_HOST","NOT_HTTPS","DNS_FAILED","BAD_URL"]},"durationMs":{"type":"integer"},"nextRetryAt":{"type":["string","null"],"format":"date-time"}}},"WebhookEndpointCreate":{"type":"object","required":["url","events"],"properties":{"url":{"type":"string","format":"uri","description":"https only, default port, publicly routable host."},"events":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/WebhookEventType"}},"description":{"type":["string","null"],"maxLength":200},"active":{"type":"boolean","default":true}}},"WebhookEndpointUpdate":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/WebhookEventType"}},"description":{"type":["string","null"],"maxLength":200},"active":{"type":"boolean"},"rotateSecret":{"type":"boolean","description":"Generate a new signing secret; the response then includes `secret`."}}},"WebhookEvent":{"type":"object","required":["id","type","createdAt","data"],"description":"Body of every webhook POST. Headers: `X-Shofni-Event` (type), `X-Shofni-Delivery` (delivery id), `X-Shofni-Attempt`, `X-Shofni-Signature: t=<unix>,v1=<hex HMAC-SHA256(secret, t + \".\" + rawBody)>`.","properties":{"id":{"type":"string","description":"Event id. Retries of the same event carry the same id: use it to de-duplicate.","example":"evt_0c7e0b9d3a1f4e58b2c6d1a9e4f7b3c2"},"type":{"type":"string","example":"order.created"},"createdAt":{"type":"string","format":"date-time"},"data":{"type":"object","description":"The resource, in the same shape the matching GET endpoint returns."}}},"InventoryUpdatedData":{"type":"object","properties":{"productId":{"type":"string"},"variantId":{"type":["string","null"]},"branchId":{"type":["string","null"]},"change":{"type":"integer","description":"Signed quantity applied."},"before":{"type":["integer","null"]},"after":{"type":["integer","null"]},"reason":{"type":"string","example":"PURCHASE"},"reference":{"type":["string","null"]}}}},"responses":{"Unauthorized":{"description":"Missing or invalid API token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unauthorized","message":"Missing or invalid API token."}}}}},"Forbidden":{"description":"The token lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"forbidden","message":"This token lacks the \"orders:write\" scope.","details":{"requiredScope":"orders:write"}}}}}},"NotFound":{"description":"No such resource in this store.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"Order not found."}}}}},"ValidationFailed":{"description":"The request is malformed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"validation_failed","message":"\"url\" must be an https URL.","details":{"field":"url"}}}}}},"Conflict":{"description":"The request conflicts with the current state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"conflict","message":"Conflict."}}}}},"RateLimited":{"description":"More than 120 requests in a trailing minute with this token.","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait before retrying."},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window (120)."},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window frees up."}},"content":{"application/json":{"schema":{"type":"object","required":["error","retryAfter"],"properties":{"error":{"type":"string","const":"rate_limited"},"retryAfter":{"type":"integer"}}},"example":{"error":"rate_limited","retryAfter":12}}}}}}}