{"openapi":"3.1.0","info":{"title":"decorate API","version":"1.0.0","description":"Server-to-server API for the decorate catalogue, wallet-paid orders, and webhooks. All money is integer USD cents. Live purchases only; no sandbox. HMAC signing: METHOD + newline + exact pathname/query + newline + timestamp + newline + nonce + newline + SHA256(raw body). The pathname includes /v1. Use the exact UTF-8 body bytes and raw query string. Timestamp tolerance ±60 seconds; nonce is 32–64 lowercase hex characters and single use. Maximum body 16 KiB; it must finish arriving within 5 seconds. Keep API secrets on your server."},"servers":[{"url":"https://api.decorate.gg/v1"}],"paths":{"/status":{"get":{"operationId":"status","summary":"Service status","description":"Check API availability without authenticating.\n\nA successful status response confirms this endpoint is available. It is not an estimated delivery time.","tags":["Account"],"security":[],"responses":{"200":{"description":"Success. Order retries return the original order with status 200.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceStatus"},"example":{"status":"operational","api":"up","store":"open","queue":2,"updated":"2026-10-15T12:00:00Z"}}}},"400":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"408":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/ping":{"get":{"operationId":"ping","summary":"Check authentication","description":"Make a small signed call to verify your integration.","tags":["Account"],"security":[{"ApiKey":[],"Timestamp":[],"Nonce":[],"Signature":[]}],"x-required-scope":"account:read","responses":{"200":{"description":"Success. Order retries return the original order with status 200.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ping"},"example":{"ok":true,"name":"My storefront","status":"active","account_status":"active"}}}},"400":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"408":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/balance":{"get":{"operationId":"balance","summary":"Retrieve balance","description":"Read the balance available for API orders.","tags":["Account"],"security":[{"ApiKey":[],"Timestamp":[],"Nonce":[],"Signature":[]}],"x-required-scope":"account:read","responses":{"200":{"description":"Success. Order retries return the original order with status 200.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Balance"},"example":{"balance_cents":4200,"currency":"USD"}}}},"400":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"408":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/catalogue":{"get":{"operationId":"catalogue","summary":"List items","description":"Live store prices, availability, and collectible previews.\n\nExample IDs in these docs are placeholders. Use an actual item ID returned by the catalogue.\n\nCheck sellable before offering an item. The catalogue includes unavailable items. Stock is null because availability is not represented as a unit count.\n\nImages are absolute URLs when a single preview exists. Frames use composited layers, so their image is null.","tags":["Catalogue"],"security":[{"ApiKey":[],"Timestamp":[],"Nonce":[],"Signature":[]}],"x-required-scope":"catalogue:read","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":2000,"default":100}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"maximum":1000000,"default":0}},{"name":"search","in":"query","schema":{"type":"string","maxLength":100}},{"name":"category","in":"query","schema":{"type":"string","maxLength":100}},{"name":"type","in":"query","schema":{"type":"string","maxLength":100,"enum":["decoration","effect","nameplate","frame","bundle"]}}],"responses":{"200":{"description":"Success. Order retries return the original order with status 200.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CataloguePage"},"example":{"items":[{"id":"ITEM_ID","name":"Example decoration","type":"decoration","collection":"Example collection","price_cents":250,"currency":"USD","image":"https://cdn.discordapp.com/media/v1/collectibles-shop/ITEM_ID/static","stock":null,"sellable":true,"available_until":null}],"count":1,"total":1,"limit":100,"offset":0}}}},"400":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"408":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/catalogue/{id}":{"get":{"operationId":"item","summary":"Retrieve an item","description":"Check one item before adding it to your cart.","tags":["Catalogue"],"security":[{"ApiKey":[],"Timestamp":[],"Nonce":[],"Signature":[]}],"x-required-scope":"catalogue:read","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success. Order retries return the original order with status 200.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CatalogueItem"},"example":{"id":"ITEM_ID","name":"Example decoration","type":"decoration","collection":"Example collection","price_cents":250,"currency":"USD","image":"https://cdn.discordapp.com/media/v1/collectibles-shop/ITEM_ID/static","stock":null,"sellable":true,"available_until":null}}}},"400":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"408":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/quote":{"post":{"operationId":"quote","summary":"Quote a cart","description":"Validate a cart and calculate its total without spending balance.","tags":["Catalogue"],"security":[{"ApiKey":[],"Timestamp":[],"Nonce":[],"Signature":[]}],"x-required-scope":"catalogue:read","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["items"],"properties":{"items":{"type":"array","minItems":1,"maxItems":25,"items":{"type":"object","additionalProperties":false,"required":["id"],"properties":{"id":{"type":"string","pattern":"^[0-9]{17,20}$"},"qty":{"type":"integer","minimum":1,"maximum":10,"default":1},"expected_price_cents":{"type":"integer","minimum":1,"maximum":500000}}}}}},"example":{"items":[{"id":"ITEM_ID","qty":1,"expected_price_cents":250}]}}}},"responses":{"200":{"description":"Success. Order retries return the original order with status 200.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quote"},"example":{"ok":true,"total_cents":250,"currency":"USD","lines":[{"id":"ITEM_ID","name":"Example decoration","qty":1,"unit_price_cents":250,"line_total_cents":250,"status":"ok"}]}}}},"400":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"408":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/orders":{"post":{"operationId":"createOrder","summary":"Create an order","description":"Purchase the whole cart from your balance.\n\nThis endpoint spends your real balance. Quote the cart first.\n\nRetries return gift links only when the key also has orders:read. A write-only key receives links:[] even for a delivered order.\n\nDeliver gift links through your own integration. The API does not accept a recipient ID or send a customer DM for you.","tags":["Orders"],"security":[{"ApiKey":[],"Timestamp":[],"Nonce":[],"Signature":[]}],"x-required-scope":"orders:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["items","idempotency_key"],"properties":{"items":{"type":"array","minItems":1,"maxItems":25,"items":{"type":"object","additionalProperties":false,"required":["id"],"properties":{"id":{"type":"string","pattern":"^[0-9]{17,20}$"},"qty":{"type":"integer","minimum":1,"maximum":10,"default":1},"expected_price_cents":{"type":"integer","minimum":1,"maximum":500000}}}},"idempotency_key":{"type":"string","minLength":8,"maxLength":100,"pattern":"^[A-Za-z0-9._:-]+$"}}},"example":{"idempotency_key":"your-order-1042","items":[{"id":"ITEM_ID","qty":1,"expected_price_cents":250}]}}}},"responses":{"200":{"description":"Success. Order retries return the original order with status 200.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"},"example":{"id":"ORDER_ID","status":"paid","total_cents":250,"currency":"USD","created_at":"2026-10-15T12:00:00Z","delivered_at":null,"lines":[{"id":"ITEM_ID","name":"Example decoration","qty":1,"unit_price_cents":250}],"links":[]}}}},"201":{"description":"Order created and balance debited.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"},"example":{"id":"ORDER_ID","status":"paid","total_cents":250,"currency":"USD","created_at":"2026-10-15T12:00:00Z","delivered_at":null,"lines":[{"id":"ITEM_ID","name":"Example decoration","qty":1,"unit_price_cents":250}],"links":[]}}}},"400":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"408":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"orders","summary":"List your orders","description":"Find your API purchases, newest first.\n\nLists return order summaries without gift links. Retrieve an individual order for its purchased items and gift links.","tags":["Orders"],"security":[{"ApiKey":[],"Timestamp":[],"Nonce":[],"Signature":[]}],"x-required-scope":"orders:read","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"maximum":1000000,"default":0}}],"responses":{"200":{"description":"Success. Order retries return the original order with status 200.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrdersPage"},"example":{"orders":[],"total":0,"limit":25,"offset":0}}}},"400":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"408":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/orders/{id}":{"get":{"operationId":"order","summary":"Retrieve an order","description":"Check progress and collect delivered gift links.\n\nOrder states are paid (awaiting delivery), delivered (gift links ready), and cancelled (refunded before delivery).\n\nOnly orders belonging to your account are accessible. Unknown and unauthorized order IDs both return 404.\n\nTreat gift links as sensitive. Anyone with a valid unclaimed link may redeem it.","tags":["Orders"],"security":[{"ApiKey":[],"Timestamp":[],"Nonce":[],"Signature":[]}],"x-required-scope":"orders:read","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success. Order retries return the original order with status 200.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"},"example":{"id":"ORDER_ID","status":"delivered","total_cents":250,"currency":"USD","created_at":"2026-10-15T12:00:00Z","delivered_at":"2026-10-15T12:05:00Z","lines":[{"id":"ITEM_ID","name":"Example decoration","qty":1,"unit_price_cents":250}],"links":["https://discord.gift/EXAMPLE"]}}}},"400":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"408":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhook":{"get":{"operationId":"webhookGet","summary":"Webhook health","description":"Check your endpoint and recent delivery health.","tags":["Webhooks"],"security":[{"ApiKey":[],"Timestamp":[],"Nonce":[],"Signature":[]}],"x-required-scope":"webhooks:read","responses":{"200":{"description":"Success. Order retries return the original order with status 200.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookHealth"},"example":{"webhook_url":"https://your-shop.example/webhooks/decorate","pending":0,"failed":0,"last_delivered_at":"2026-10-15T12:05:00Z","last_failure_at":null,"last_error":null}}}},"400":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"408":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"webhookSet","summary":"Set an endpoint","description":"Send events to your public HTTPS endpoint.\n\nSetting a URL requires both webhooks:write and orders:read because the destination receives your private order details and delivered gift links. Sending null only requires webhooks:write.\n\nThe response includes a signing secret only when a new endpoint is created. Save it immediately. Use the dashboard to rotate the separate webhook secret.\n\nChanging the endpoint URL cancels deliveries queued for the previous destination.","tags":["Webhooks"],"security":[{"ApiKey":[],"Timestamp":[],"Nonce":[],"Signature":[]}],"x-required-scope":"webhooks:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"additionalProperties":false,"properties":{"url":{"type":["string","null"],"format":"uri","pattern":"^https://"}}},"example":{"url":"https://your-shop.example/webhooks/decorate"}}}},"responses":{"200":{"description":"Success. Order retries return the original order with status 200.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookConfiguration"}}}},"400":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"408":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"webhookDelete","summary":"Remove an endpoint","description":"Stop webhook deliveries for your account.","tags":["Webhooks"],"security":[{"ApiKey":[],"Timestamp":[],"Nonce":[],"Signature":[]}],"x-required-scope":"webhooks:write","responses":{"200":{"description":"Success. Order retries return the original order with status 200.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookHealth"}}}},"400":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"408":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhook/test":{"post":{"operationId":"webhookTest","summary":"Send a test event","description":"Check your endpoint and signature verification end to end.\n\nThis sends a test event to your saved endpoint. It does not create an order or spend balance.","tags":["Webhooks"],"security":[{"ApiKey":[],"Timestamp":[],"Nonce":[],"Signature":[]}],"x-required-scope":"webhooks:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{}},"example":{}}}},"responses":{"200":{"description":"Success. Order retries return the original order with status 200.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTest"},"example":{"ok":true,"queued":true}}}},"400":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"408":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Request failed. Inspect error.type and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"ApiKey":{"type":"apiKey","in":"header","name":"X-Api-Key"},"Timestamp":{"type":"apiKey","in":"header","name":"X-Api-Timestamp","description":"Unix time in seconds."},"Nonce":{"type":"apiKey","in":"header","name":"X-Api-Nonce","description":"Fresh 32–64 lowercase hex characters."},"Signature":{"type":"apiKey","in":"header","name":"X-Api-Signature","description":"Lowercase hex HMAC-SHA256 canonical request signature."}},"schemas":{"ServiceStatus":{"type":"object","required":["status","api","store","queue","updated"],"properties":{"status":{"type":"string","enum":["operational","degraded"]},"api":{"type":"string","enum":["up","unavailable"]},"store":{"type":"string","enum":["open","closed"]},"queue":{"type":"integer","minimum":0},"updated":{"type":"string","format":"date-time"}}},"Ping":{"type":"object","required":["ok","name","status","account_status"],"properties":{"ok":{"const":true},"name":{"type":"string"},"status":{"type":"string"},"account_status":{"type":"string"}}},"Balance":{"type":"object","required":["balance_cents","currency"],"properties":{"balance_cents":{"type":"integer","minimum":0},"currency":{"type":"string","const":"USD"}}},"CatalogueItem":{"type":"object","required":["id","name","type","collection","price_cents","currency","image","stock","sellable","available_until"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string","enum":["decoration","effect","nameplate","frame","bundle"]},"collection":{"type":"string"},"price_cents":{"type":"integer","minimum":0},"currency":{"type":"string","const":"USD"},"image":{"type":["string","null"],"format":"uri"},"stock":{"type":"null"},"sellable":{"type":"boolean"},"available_until":{"type":["string","null"],"format":"date-time"}}},"CataloguePage":{"type":"object","required":["items","count","total","limit","offset"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/CatalogueItem"}},"count":{"type":"integer","minimum":0},"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":0},"offset":{"type":"integer","minimum":0}}},"OrderLine":{"type":"object","required":["id","name","qty","unit_price_cents"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"qty":{"type":"integer","minimum":1,"maximum":10},"unit_price_cents":{"type":"integer","minimum":0}}},"Order":{"type":"object","required":["id","status","currency","total_cents","created_at","delivered_at","lines","links"],"properties":{"id":{"type":"string"},"status":{"type":"string","enum":["paid","delivered","cancelled"]},"currency":{"type":"string","const":"USD"},"total_cents":{"type":"integer","minimum":0},"created_at":{"type":"string","format":"date-time"},"delivered_at":{"type":["string","null"],"format":"date-time"},"lines":{"type":"array","items":{"$ref":"#/components/schemas/OrderLine"}},"links":{"type":"array","items":{"type":"string","format":"uri"}}}},"OrderSummary":{"type":"object","required":["id","status","currency","total_cents","created_at"],"properties":{"id":{"type":"string"},"status":{"type":"string","enum":["paid","delivered","cancelled"]},"currency":{"type":"string","const":"USD"},"total_cents":{"type":"integer","minimum":0},"created_at":{"type":"string","format":"date-time"}}},"OrdersPage":{"type":"object","required":["orders","total","limit","offset"],"properties":{"orders":{"type":"array","items":{"$ref":"#/components/schemas/OrderSummary"}},"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":0},"offset":{"type":"integer","minimum":0}}},"Quote":{"type":"object","required":["ok","currency","total_cents","lines"],"properties":{"ok":{"type":"boolean"},"currency":{"type":"string","const":"USD"},"total_cents":{"type":"integer","minimum":0},"lines":{"type":"array","items":{"type":"object","required":["id","qty","status"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"qty":{"type":"integer","minimum":1,"maximum":10},"unit_price_cents":{"type":"integer","minimum":0},"line_total_cents":{"type":"integer","minimum":0},"status":{"type":"string","enum":["ok","price_changed","sold_out"]}}}}}},"WebhookHealth":{"type":"object","required":["webhook_url","pending","failed","last_delivered_at","last_failure_at","last_error"],"properties":{"webhook_url":{"type":["string","null"],"format":"uri"},"pending":{"type":"integer","minimum":0},"failed":{"type":"integer","minimum":0},"last_delivered_at":{"type":["string","null"],"format":"date-time"},"last_failure_at":{"type":["string","null"],"format":"date-time"},"last_error":{"type":["string","null"]}}},"WebhookConfiguration":{"allOf":[{"$ref":"#/components/schemas/WebhookHealth"},{"type":"object","properties":{"secret":{"type":"string","description":"Only returned when a new signing secret is generated. Save it immediately."}}}]},"WebhookTest":{"type":"object","required":["ok","queued"],"properties":{"ok":{"const":true},"queued":{"const":true}}},"WebhookEvent":{"type":"object","required":["id","event","created_at","data"],"properties":{"id":{"type":"string"},"event":{"type":"string","enum":["order.accepted","order.delivered","order.cancelled","catalogue.changed","test"]},"created_at":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{"order":{"$ref":"#/components/schemas/Order"},"revision":{"type":"string"},"refresh":{"type":"boolean"},"message":{"type":"string"}}}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["type","message"],"properties":{"type":{"type":"string"},"message":{"type":"string"}}}}},"CartItem":{"type":"object","additionalProperties":false,"required":["id"],"properties":{"id":{"type":"string","pattern":"^[0-9]{17,20}$"},"qty":{"type":"integer","minimum":1,"maximum":10,"default":1},"expected_price_cents":{"type":"integer","minimum":1,"maximum":500000}}}}}}