openapi: 3.0.3 info: title: 'SenPrints Seller API' description: "The API is a service for creating and managing orders, including product listings, order processing, and more.\n\nRequests use standard HTTP methods: GET, POST, PUT, DELETE. Responses are in JSON format.\n\nAuthentication: send your API key as a Bearer token. Get it in the seller dashboard of the environment you call (table below) -> Settings -> General -> Get API Key. Only the account owner, signed in directly, can see, create or replace the key (not a team member). A key is valid for one year; replacing it there stops the old one at once.\n\n## Environments\n\n| Setting | Production | Development |\n| --- | --- | --- |\n| API base URL | `https://api-sg.senprints.net` | `https://apis.dev.senprints.net` |\n| API key | [seller.senprints.com](https://seller.senprints.com/settings/general) -> Settings -> General | [seller.senprints.xyz](https://seller.senprints.xyz/settings/general) -> Settings -> General |\n| MCP server | `https://api.senprints.com/mcp/seller` | `https://apis.dev.senprints.net/mcp/seller` |\n| This reference | [api-sg.senprints.net/api/documentation](https://api-sg.senprints.net/api/documentation) | [apis.dev.senprints.net/api/documentation](https://apis.dev.senprints.net/api/documentation) |\n\nThe two environments share nothing: accounts, API keys, orders, balances and webhooks of one do not exist in the other, so a production key answers HTTP 401 on development and the other way round. Paths and bodies are the same; only the base URL and the key change. Pick the server in the selector below to send the \"Test request\" calls of this page to it.\n\n## Quickstart: your first order\n\n1. Send your API key on every call: `Authorization: Bearer `, to the base URL of the environment the key comes from.\n2. Pick a product: `GET /seller-api/catalog` lists the products you can order (their `id` is the `template_id` of an order line), with their options and print areas; `GET /seller-api/catalog/info?id={template_id}` gives the variants, costs and shipping.\n3. Check the order without creating it: `POST /seller-api/orders/validate` with the order body. It answers HTTP 400 with the errors, or `valid: true`.\n4. Create it: `POST /seller-api/orders` with the same body. Use your own `order_number`: it is unique per account, so a retry cannot create the order twice.\n5. Follow it: set a webhook once (`PUT /seller-api/webhook` with `{\"url\": \"https://...\"}`) to receive `order.validated`, `order.paid`, `order.tracking_updated` and the other events, or read `GET /seller-api/orders/{id}`.\n\n```bash\n# Development: https://apis.dev.senprints.net, production: https://api-sg.senprints.net\nexport SENPRINTS_API_URL=https://apis.dev.senprints.net\nexport SENPRINTS_API_KEY=\n\ncurl -X POST \"$SENPRINTS_API_URL/seller-api/orders/validate\" \\\n -H \"Authorization: Bearer $SENPRINTS_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"order_number\": \"1001\",\n \"customer_name\": \"Jane Doe\",\n \"address\": \"1 Main St\",\n \"city\": \"Austin\",\n \"state\": \"TX\",\n \"postcode\": \"78701\",\n \"country\": \"US\",\n \"products\": [{\n \"template_id\": 101,\n \"quantity\": 1,\n \"options\": {\"color\": \"white\", \"size\": \"m\"},\n \"designs\": [{\"file_url\": \"https://example.com/design.png\", \"print_space\": \"front\"}]\n }]\n }'\n```\n\nA valid order is charged from your balance and sent to production one hour after its last update when auto fulfill is on; until then you can change it (`PUT /seller-api/orders/{id}`), hold it or cancel it.\n\n## AI assistants and agents\n\n- **No code, with MCP:** add `https://api.senprints.com/mcp/seller` (development: `https://apis.dev.senprints.net/mcp/seller`) as a custom connector in Claude, ChatGPT or any MCP client, then sign in with your SenPrints seller account of that environment. The assistant can search your orders, look up the fulfillment catalog, upload artwork, create fulfillment orders and read your sales and balance; creating an order or changing campaigns asks you to confirm first.\n- **Docs for agents:** this whole reference as Markdown at [/api/documentation.md](/api/documentation.md) (one endpoint: `?method=PUT&path=/seller-api/webhook`), the OpenAPI spec at [/api/documentation.openapi](/api/documentation.openapi), and an index at [/llms.txt](/llms.txt). \"Copy for AI\" at the top of this page copies them or opens them in ChatGPT or Claude.\n- **Try an order without paying:** `POST /seller-api/orders/validate` runs every check of `POST /seller-api/orders` and creates nothing.\n\n## Tracking and order updates\n\nSet a webhook with `PUT /seller-api/webhook` (API key only, no dashboard step; the same webhook shows in the seller dashboard -> Settings -> General) and SenPrints posts the steps of your orders you pick (all by default) to your URL: `order.validated` / `order.invalid` after the checks, `order.paid`, `order.tracking_updated` for each tracking update, `order.completed`, and `order.on_hold` / `order.cancelled`. The Webhooks section describes the payload, the signature and the retries.\n\nWithout a webhook, read the order again to follow it:\n\n- Tracking is per product line, in `products[].tracking_code`, `tracking_url` and `shipping_carrier` of `GET /seller-api/orders/{id}`. A line that has tracking moves to `fulfill_status` `on_delivery`.\n- When every line has shipped or been cancelled, the order moves to `status` `completed` and `fulfill_status` `on_delivery`: you can stop reading it.\n- To find the orders that started shipping, list them by the time of their first tracking: `GET /seller-api/orders?column_date=delivered_at&date_range=last_24_hours`. Lines can ship separately, so keep reading `GET /seller-api/orders/{id}` until the order's `fulfill_status` is `on_delivery`.\n- For an FBA order with a shipping label, a line can stay `processing` until the carrier scans the parcel.\n\nThe webhooks in the seller dashboard are different and do not cover these orders: Settings -> Notification -> Webhook only announces new storefront sales, and a store's WooCommerce webhook only covers orders created by the SenPrints WooCommerce plugin.\n\n## Errors and limits\n\nEvery response is JSON with `success`. Read it, not only the HTTP status: a failed check on an order body answers HTTP 200 with `success: false`.\n\n| HTTP | Body | Meaning |\n| --- | --- | --- |\n| 200 | `success: false`, `message: {\"field\": [\"...\"]}` | A request rule failed on `POST`/`PUT /seller-api/orders` (missing or malformed field, `order_number` already used). Nothing was changed. |\n| 400 | `success: false`, `message: \"...\"` | A business rule failed (address, product, print area), or a required field is missing. `POST /seller-api/orders/validate` answers every failed check this way, with the errors in `data.errors`. |\n| 401 | `error: \"api_key_invalid\"` or `\"api_key_expired\"` | The key is unknown, comes from the other environment, is not a seller key, or was replaced or expired. Get the current one in the seller dashboard of that environment -> Settings -> General. |\n| 404 | `success: false`, `message: \"Order not found\"` or `\"Webhook not set\"` | Not one of your fulfillment or FBA orders, or no webhook set yet. |\n| 406 | `error: \"api_key_absent\"` | No `Authorization: Bearer` header. |\n| 409 | `success: false` | An order with the same `order_number` is being created by another call. Look it up with `GET /seller-api/orders?s={order_number}`. |\n| 429 | `success: false` | Over the limit: 300 requests a minute per API key, all endpoints together. Wait the `Retry-After` seconds; `X-RateLimit-Remaining` tells how many calls are left. |\n| 500 | `success: false`, `message: \"Server internal error\"` | Our error. Sending the same `POST /seller-api/orders` again is safe: if the order was created after all, the retry answers that the `order_number` is already taken. |\n\n**Retries:** sending `POST /seller-api/orders` again with the same `order_number` never creates a second order, so retry a timeout freely. Webhook deliveries are at least once; deduplicate them on their `id`, and see each body sent and your URL's answer with `GET /seller-api/webhook/deliveries`.\n\n## Changelog\n\n- **2026-10-21**: `GET /seller-api/webhook/deliveries`, the log of webhook attempts with the body sent and your URL's answer. Rate limit of 300 requests a minute per API key (HTTP 429). A second `POST /seller-api/orders` with an `order_number` still being created answers 409. `order.cancelled` is also sent when an order is cancelled from WooCommerce or refunded on Shopify. `GET /seller-api/me` no longer returns `klaviyo_private_key`, `crisp_signature` and `crisp_token_id`. The webhook signing secret is optional and off by default (`rotate_secret`, `remove_secret`). The Seller API takes a seller API key only; other key types answer 401 `api_key_invalid`. The API key can be replaced from the dashboard. This reference as Markdown, `/llms.txt`, and the seller MCP server.\n- **2026-10-20**: Webhooks: `GET`/`PUT`/`DELETE /seller-api/webhook`, `POST /seller-api/webhook/test`, and the events `order.validated`, `order.invalid`, `order.paid`, `order.tracking_updated`, `order.completed`, `order.on_hold`, `order.cancelled`. This reference replaces the Swagger page.\n- **2026-10-12**: `POST /seller-api/orders/validate`, a dry run of `POST /seller-api/orders`. A missing `customer_name`, `address` or `country` answers HTTP 400 naming the fields, instead of HTTP 500.\n- **2026-09-04**: An order line without `designs` or `mockups`, or with `options` sent as a list, no longer answers HTTP 500." version: 1.0.0 contact: email: thangnm@senprints.com servers: - url: 'https://api-sg.senprints.net' description: Production - url: 'https://apis.dev.senprints.net' description: Development tags: - name: Orders description: '' - name: Webhooks description: "\nGet order updates pushed to your server instead of polling. Set the URL and the events you want with `PUT /seller-api/webhook`, using your API key only; no dashboard step and no review.\nThe seller can also see and change the same webhook in Dashboard -> Settings -> General.\n\n**Events**, for your fulfillment and FBA orders, in the order an order usually goes through them. You receive the ones listed in the webhook's `events` (all of them unless you pick some):\n\n- `order.validated`: the order passed the checks run after it was created or updated; `status` is `pending`. With auto fulfill on and enough balance it is charged one hour after its last update.\n- `order.invalid`: the order failed them; `fulfill_status` is `invalid` and `fulfill_log` says why. Fix it with `PUT /seller-api/orders/{id}`.\n- `order.paid`: the order was charged from your balance and sent to production; `status` is `processing`.\n- `order.tracking_updated`: a line got tracking (`products[].tracking_code`, `tracking_url`, `shipping_carrier`). Sent about one minute after the update, once per update, so an order shipped in several parcels sends several.\n- `order.completed`: every line has shipped or been cancelled; `status` is `completed`, `fulfill_status` `on_delivery`.\n- `order.on_hold`: the order is held: `status` `on_hold` when you hold it (`PUT /seller-api/orders/{id}/hold`), or `fulfill_status` `on_hold` when SenPrints holds it for review (for example a large quantity or amount).\n- `order.cancelled`: `status` became `cancelled`.\n- `ping`: sent only by `POST /seller-api/webhook/test`.\n\n**Request we send**: `POST` to your URL with a JSON body `{\"id\": \"\", \"event\": \"order.paid\", \"created_at\": \"\", \"data\": {\"order\": {...}, \"previous\": {\"status\": \"pending\", \"fulfill_status\": \"unfulfilled\"}}}` and the headers `X-SenPrints-Event`, `X-SenPrints-Delivery` (same as `id`), `X-SenPrints-Timestamp` (Unix seconds), plus `X-SenPrints-Signature` when the webhook has a signing secret. `data.order` is the same object as `GET /seller-api/orders/{id}`, read when the delivery is sent. `data.previous` is the order's `status` and `fulfill_status` before the change, `null` for `order.tracking_updated`.\n\n**Signature (optional)**: a webhook only needs a URL and events; it has no signing secret and its deliveries are not signed unless you ask. To verify deliveries, create a secret with `PUT /seller-api/webhook` and `\"rotate_secret\": true` (drop it again with `\"remove_secret\": true`). Every delivery then carries `X-SenPrints-Signature`: `sha256=` followed by the hex HMAC-SHA256 of `{X-SenPrints-Timestamp}.{raw request body}`, keyed with the `secret` returned by `GET`/`PUT /seller-api/webhook`. Compute it on the raw body before parsing the JSON, compare in constant time, and reject a timestamp more than 5 minutes old. In PHP: `hash_equals('sha256=' . hash_hmac('sha256', $timestamp . '.' . $rawBody, $secret), $signature)`. In Node.js: `'sha256=' + crypto.createHmac('sha256', secret).update(timestamp + '.' + rawBody).digest('hex')`.\n\n**Delivery**: answer any 2xx within 10 seconds. Anything else, a timeout or a redirect counts as a failure and is retried 5 times over about 3 hours (after 1 min, 5 min, 15 min, 1 h, 2 h). Delivery is at least once: deduplicate on `id`. Events can arrive out of order, so trust the `order` you receive over its arrival order, or read `GET /seller-api/orders/{id}`.\n\n**Delivery log**: every attempt, with the body sent and how your URL answered it, is listed by `GET /seller-api/webhook/deliveries` for 30 days." - name: Catalog description: '' - name: Me description: '' components: securitySchemes: default: type: http scheme: bearer description: 'Get an API key in the seller dashboard -> Settings -> General -> Get API Key: [seller.senprints.com](https://seller.senprints.com/settings/general) for production, [seller.senprints.xyz](https://seller.senprints.xyz/settings/general) for development; a key works on its own environment only (account owner only, valid for one year). A missing key answers HTTP 406 (`api_key_absent`), an invalid or expired key HTTP 401 (`api_key_invalid`, `api_key_expired`).' security: - default: [] paths: /seller-api/orders: get: summary: 'Get orders' operationId: getOrders description: 'Retrieve the list of fulfillment orders. Each item is the order object described in Get order details.' parameters: - in: query name: s description: 'Search keyword, support search by order id, order number, customer name, customer email.' example: 'Order #12345' required: false schema: type: string description: 'Search keyword, support search by order id, order number, customer name, customer email.' example: 'Order #12345' - in: query name: status description: 'The status of the order.' example: completed required: false schema: type: string description: 'The status of the order.' example: completed enum: - draft - pending - processing - completed - on_hold - cancelled - in: query name: date_range description: 'Preset date range applied to column_date. Defaults to custom.' example: custom required: false schema: type: string description: 'Preset date range applied to column_date. Defaults to custom.' example: custom enum: - lifetime - custom - today - yesterday - last_hour - last_24_hours - last_3_days - last_5_days - last_7_days - last_14_days - last_30_days - last_quarter - last_6_months - this_week - last_week - this_month - this_quarter - last_month - this_year - last_year - in: query name: start_date description: 'The start date of the custom range (YYYY-MM-DD). With date_range custom and no start_date, the last month is returned.' example: '2025-01-01' required: false schema: type: string description: 'The start date of the custom range (YYYY-MM-DD). With date_range custom and no start_date, the last month is returned.' example: '2025-01-01' - in: query name: end_date description: 'The end date of the custom range (YYYY-MM-DD), at most 365 days after start_date.' example: '2025-02-01' required: false schema: type: string description: 'The end date of the custom range (YYYY-MM-DD), at most 365 days after start_date.' example: '2025-02-01' - in: query name: column_date description: 'The date column the range applies to. Defaults to created_at.' example: created_at required: false schema: type: string description: 'The date column the range applies to. Defaults to created_at.' example: created_at enum: - created_at - updated_at - paid_at - delivered_at - fulfilled_at - in: query name: page description: 'The page number.' example: 1 required: false schema: type: integer description: 'The page number.' example: 1 - in: query name: per_page description: 'The number of items per page, 1 to 500. Defaults to 15.' example: 15 required: false schema: type: integer description: 'The number of items per page, 1 to 500. Defaults to 15.' example: 15 - in: query name: sort description: 'The column to sort by. Defaults to column_date, newest first.' example: id required: false schema: type: string description: 'The column to sort by. Defaults to column_date, newest first.' example: id enum: - id - total_amount - updated_at - created_at - in: query name: direction description: 'The direction to sort.' example: asc required: false schema: type: string description: 'The direction to sort.' example: asc enum: - asc - desc responses: 200: description: '' content: application/json: schema: type: object example: success: true message: null data: - id: 1 order_number: ORD-123456 store_name: 'ABC Store' store_domain: abc.com customer_name: 'Nguyen Van A' customer_email: email@example.com customer_phone: '0123456789' address: '123 ABC Street' address_2: 'Apartment 101' house_number: 12B mailbox_number: '456' city: Hanoi state: 'Ha Dong' postcode: '100000' country: VN order_note: 'Deliver during business hours' shipping_label: 'http://example.com/label.pdf' shipping_method: standard cross_shipping: true personalized: false status: pending fulfill_status: unfulfilled address_verified: true fulfill_log: 'Order sent to production' type: standard created_at: '2025-02-28T17:01:29+07:00' updated_at: '2025-02-28T17:01:29+07:00' paid_at: '2025-03-01T12:00:00+07:00' delivered_at: '2025-03-05T09:00:00+07:00' received_at: '2025-03-06T14:00:00+07:00' total_quantity: 3 total_product_amount: 59.99 total_shipping_amount: 5.99 total_amount: 65.98 total_paid: 65.98 total_product_cost: 30 total_shipping_cost: 3 total_seller_profit: 32.98 processing_fee: 2 total_fulfill_fee: 4 processing_fee_paid: true fulfill_fee_paid: true products: - id: 1 product_name: T-shirt sku: SKU12345 quantity: 2 price: 19.99 total_amount: 39.98 seller_profit: 10 fulfill_status: fulfilled full_printed: true barcode: ABC123456789 fulfill_fba_by: Amazon design_by: seller campaign_title: 'Valentine Campaign' tracking_code: TRACK123456 tracking_url: 'http://tracking.com/TRACK123456' shipping_carrier: DHL cross_shipping: false color: Red options: color: white size: 30x20in custom_options: - type: text label: Name value: Anna thumb_url: 'http://example.com/thumb.jpg' mockups: - id: 1 file_url: 'http://example.com/mockup.jpg' print_space: front designs: - id: 1 file_url: 'http://example.com/design.jpg' print_space: front properties: success: type: boolean example: true message: type: string example: null nullable: true data: type: array example: - id: 1 order_number: ORD-123456 store_name: 'ABC Store' store_domain: abc.com customer_name: 'Nguyen Van A' customer_email: email@example.com customer_phone: '0123456789' address: '123 ABC Street' address_2: 'Apartment 101' house_number: 12B mailbox_number: '456' city: Hanoi state: 'Ha Dong' postcode: '100000' country: VN order_note: 'Deliver during business hours' shipping_label: 'http://example.com/label.pdf' shipping_method: standard cross_shipping: true personalized: false status: pending fulfill_status: unfulfilled address_verified: true fulfill_log: 'Order sent to production' type: standard created_at: '2025-02-28T17:01:29+07:00' updated_at: '2025-02-28T17:01:29+07:00' paid_at: '2025-03-01T12:00:00+07:00' delivered_at: '2025-03-05T09:00:00+07:00' received_at: '2025-03-06T14:00:00+07:00' total_quantity: 3 total_product_amount: 59.99 total_shipping_amount: 5.99 total_amount: 65.98 total_paid: 65.98 total_product_cost: 30 total_shipping_cost: 3 total_seller_profit: 32.98 processing_fee: 2 total_fulfill_fee: 4 processing_fee_paid: true fulfill_fee_paid: true products: - id: 1 product_name: T-shirt sku: SKU12345 quantity: 2 price: 19.99 total_amount: 39.98 seller_profit: 10 fulfill_status: fulfilled full_printed: true barcode: ABC123456789 fulfill_fba_by: Amazon design_by: seller campaign_title: 'Valentine Campaign' tracking_code: TRACK123456 tracking_url: 'http://tracking.com/TRACK123456' shipping_carrier: DHL cross_shipping: false color: Red options: color: white size: 30x20in custom_options: - type: text label: Name value: Anna thumb_url: 'http://example.com/thumb.jpg' mockups: - id: 1 file_url: 'http://example.com/mockup.jpg' print_space: front designs: - id: 1 file_url: 'http://example.com/design.jpg' print_space: front items: type: object properties: id: type: integer example: 1 order_number: type: string example: ORD-123456 store_name: type: string example: 'ABC Store' store_domain: type: string example: abc.com customer_name: type: string example: 'Nguyen Van A' customer_email: type: string example: email@example.com customer_phone: type: string example: '0123456789' address: type: string example: '123 ABC Street' address_2: type: string example: 'Apartment 101' house_number: type: string example: 12B mailbox_number: type: string example: '456' city: type: string example: Hanoi state: type: string example: 'Ha Dong' postcode: type: string example: '100000' country: type: string example: VN order_note: type: string example: 'Deliver during business hours' shipping_label: type: string example: 'http://example.com/label.pdf' shipping_method: type: string example: standard cross_shipping: type: boolean example: true personalized: type: boolean example: false status: type: string example: pending fulfill_status: type: string example: unfulfilled address_verified: type: boolean example: true fulfill_log: type: string example: 'Order sent to production' type: type: string example: standard created_at: type: string example: '2025-02-28T17:01:29+07:00' updated_at: type: string example: '2025-02-28T17:01:29+07:00' paid_at: type: string example: '2025-03-01T12:00:00+07:00' delivered_at: type: string example: '2025-03-05T09:00:00+07:00' received_at: type: string example: '2025-03-06T14:00:00+07:00' total_quantity: type: integer example: 3 total_product_amount: type: number example: 59.99 total_shipping_amount: type: number example: 5.99 total_amount: type: number example: 65.98 total_paid: type: number example: 65.98 total_product_cost: type: integer example: 30 total_shipping_cost: type: integer example: 3 total_seller_profit: type: number example: 32.98 processing_fee: type: integer example: 2 total_fulfill_fee: type: integer example: 4 processing_fee_paid: type: boolean example: true fulfill_fee_paid: type: boolean example: true products: type: array example: - id: 1 product_name: T-shirt sku: SKU12345 quantity: 2 price: 19.99 total_amount: 39.98 seller_profit: 10 fulfill_status: fulfilled full_printed: true barcode: ABC123456789 fulfill_fba_by: Amazon design_by: seller campaign_title: 'Valentine Campaign' tracking_code: TRACK123456 tracking_url: 'http://tracking.com/TRACK123456' shipping_carrier: DHL cross_shipping: false color: Red options: color: white size: 30x20in custom_options: - type: text label: Name value: Anna thumb_url: 'http://example.com/thumb.jpg' mockups: - id: 1 file_url: 'http://example.com/mockup.jpg' print_space: front designs: - id: 1 file_url: 'http://example.com/design.jpg' print_space: front items: type: object properties: id: type: integer example: 1 product_name: type: string example: T-shirt sku: type: string example: SKU12345 quantity: type: integer example: 2 price: type: number example: 19.99 total_amount: type: number example: 39.98 seller_profit: type: integer example: 10 fulfill_status: type: string example: fulfilled full_printed: type: boolean example: true barcode: type: string example: ABC123456789 fulfill_fba_by: type: string example: Amazon design_by: type: string example: seller campaign_title: type: string example: 'Valentine Campaign' tracking_code: type: string example: TRACK123456 tracking_url: type: string example: 'http://tracking.com/TRACK123456' shipping_carrier: type: string example: DHL cross_shipping: type: boolean example: false color: type: string example: Red options: type: object properties: color: type: string example: white size: type: string example: 30x20in custom_options: type: array example: - type: text label: Name value: Anna items: type: object properties: type: type: string example: text label: type: string example: Name value: type: string example: Anna thumb_url: type: string example: 'http://example.com/thumb.jpg' mockups: type: array example: - id: 1 file_url: 'http://example.com/mockup.jpg' print_space: front items: type: object properties: id: type: integer example: 1 file_url: type: string example: 'http://example.com/mockup.jpg' print_space: type: string example: front designs: type: array example: - id: 1 file_url: 'http://example.com/design.jpg' print_space: front items: type: object properties: id: type: integer example: 1 file_url: type: string example: 'http://example.com/design.jpg' print_space: type: string example: front 400: description: 'Invalid query parameter' content: application/json: schema: type: object example: success: false message: 'The selected status is invalid.' data: null properties: success: type: boolean example: false message: type: string example: 'The selected status is invalid.' data: type: string example: null nullable: true 401: description: 'Invalid or expired API key' content: application/json: schema: type: object example: success: false error: api_key_invalid properties: success: type: boolean example: false error: type: string example: api_key_invalid 404: description: 'No order matches' content: application/json: schema: type: object example: success: false message: 'No orders found' data: null properties: success: type: boolean example: false message: type: string example: 'No orders found' data: type: string example: null nullable: true tags: - Orders post: summary: 'Create a new order' operationId: createANewOrder description: "Creates a fulfillment order. The call is accepted before the order is fully checked: address verification,\ndownloading the artwork files, shipping cost and supplier assignment run afterwards in a queue. Read the order\nagain with GET /seller-api/orders/{id} until status is pending (the order is valid) or fulfill_status is invalid\n(fulfill_log gives the reason), or set a webhook (PUT /seller-api/webhook) to receive order.validated or\norder.invalid instead.\n\n> **Warning:** a valid pending order is charged and sent to production automatically one hour after its\n> last update when the account has auto fulfill enabled and enough balance. To avoid the charge, hold or cancel\n> the order before then (PUT /seller-api/orders/{id}/hold or /cancel).\n\nErrors: a failed request rule (missing or malformed field) answers HTTP 200 with success=false and message as an\nobject keyed by field, so check the success field and not only the HTTP status. A failed business rule (address,\nproduct, print space) answers HTTP 400 with a text message, and so does a missing customer_name, address or\ncountry (message: Missing required fields: ...). Nothing is created in either case.\n\nRetries are safe: order_number is unique per account, so sending the same order again after a timeout creates\nnothing and answers success=false with \"order_number\": [\"The order number has already been taken.\"]. A call sent\nwhile the first one with that number is still running answers HTTP 409. Find the order already created with\nGET /seller-api/orders?s={order_number}." parameters: [] responses: 200: description: '' content: application/json: schema: oneOf: - description: 'Order accepted, validated afterwards in a queue' type: object example: success: true message: 'Order created successfully' data: id: 1 order_number: ORD-123456 store_name: 'ABC Store' store_domain: abc.com customer_name: 'Nguyen Van A' customer_email: email@example.com customer_phone: '0123456789' address: '123 ABC Street' address_2: 'Apartment 101' house_number: 12B mailbox_number: '456' city: Hanoi state: 'Ha Dong' postcode: '100000' country: VN order_note: 'Deliver during business hours' shipping_label: 'http://example.com/label.pdf' shipping_method: standard cross_shipping: true personalized: false status: draft fulfill_status: unfulfilled address_verified: true fulfill_log: null type: standard created_at: '2025-02-28T17:01:29+07:00' updated_at: '2025-02-28T17:01:29+07:00' paid_at: null delivered_at: null received_at: null total_quantity: 3 total_product_amount: 59.99 total_shipping_amount: 5.99 total_amount: 65.98 total_paid: 65.98 total_product_cost: 30 total_shipping_cost: 3 total_seller_profit: 32.98 processing_fee: 2 total_fulfill_fee: 4 processing_fee_paid: true fulfill_fee_paid: true products: - id: 1 product_name: T-shirt sku: SKU12345 quantity: 2 price: 19.99 total_amount: 39.98 seller_profit: 10 fulfill_status: fulfilled full_printed: true barcode: ABC123456789 fulfill_fba_by: Amazon design_by: seller campaign_title: 'Valentine Campaign' tracking_code: TRACK123456 tracking_url: 'http://tracking.com/TRACK123456' shipping_carrier: DHL cross_shipping: false color: Red options: color: white size: 30x20in custom_options: - type: text label: Name value: Anna thumb_url: 'http://example.com/thumb.jpg' mockups: - id: 1 file_url: 'http://example.com/mockup.jpg' print_space: front designs: - id: 1 file_url: 'http://example.com/design.jpg' print_space: front properties: success: type: boolean example: true message: type: string example: 'Order created successfully' data: type: object properties: id: type: integer example: 1 order_number: type: string example: ORD-123456 store_name: type: string example: 'ABC Store' store_domain: type: string example: abc.com customer_name: type: string example: 'Nguyen Van A' customer_email: type: string example: email@example.com customer_phone: type: string example: '0123456789' address: type: string example: '123 ABC Street' address_2: type: string example: 'Apartment 101' house_number: type: string example: 12B mailbox_number: type: string example: '456' city: type: string example: Hanoi state: type: string example: 'Ha Dong' postcode: type: string example: '100000' country: type: string example: VN order_note: type: string example: 'Deliver during business hours' shipping_label: type: string example: 'http://example.com/label.pdf' shipping_method: type: string example: standard cross_shipping: type: boolean example: true personalized: type: boolean example: false status: type: string example: draft fulfill_status: type: string example: unfulfilled address_verified: type: boolean example: true fulfill_log: type: string example: null nullable: true type: type: string example: standard created_at: type: string example: '2025-02-28T17:01:29+07:00' updated_at: type: string example: '2025-02-28T17:01:29+07:00' paid_at: type: string example: null nullable: true delivered_at: type: string example: null nullable: true received_at: type: string example: null nullable: true total_quantity: type: integer example: 3 total_product_amount: type: number example: 59.99 total_shipping_amount: type: number example: 5.99 total_amount: type: number example: 65.98 total_paid: type: number example: 65.98 total_product_cost: type: integer example: 30 total_shipping_cost: type: integer example: 3 total_seller_profit: type: number example: 32.98 processing_fee: type: integer example: 2 total_fulfill_fee: type: integer example: 4 processing_fee_paid: type: boolean example: true fulfill_fee_paid: type: boolean example: true products: type: array example: - id: 1 product_name: T-shirt sku: SKU12345 quantity: 2 price: 19.99 total_amount: 39.98 seller_profit: 10 fulfill_status: fulfilled full_printed: true barcode: ABC123456789 fulfill_fba_by: Amazon design_by: seller campaign_title: 'Valentine Campaign' tracking_code: TRACK123456 tracking_url: 'http://tracking.com/TRACK123456' shipping_carrier: DHL cross_shipping: false color: Red options: color: white size: 30x20in custom_options: - type: text label: Name value: Anna thumb_url: 'http://example.com/thumb.jpg' mockups: - id: 1 file_url: 'http://example.com/mockup.jpg' print_space: front designs: - id: 1 file_url: 'http://example.com/design.jpg' print_space: front items: type: object properties: id: type: integer example: 1 product_name: type: string example: T-shirt sku: type: string example: SKU12345 quantity: type: integer example: 2 price: type: number example: 19.99 total_amount: type: number example: 39.98 seller_profit: type: integer example: 10 fulfill_status: type: string example: fulfilled full_printed: type: boolean example: true barcode: type: string example: ABC123456789 fulfill_fba_by: type: string example: Amazon design_by: type: string example: seller campaign_title: type: string example: 'Valentine Campaign' tracking_code: type: string example: TRACK123456 tracking_url: type: string example: 'http://tracking.com/TRACK123456' shipping_carrier: type: string example: DHL cross_shipping: type: boolean example: false color: type: string example: Red options: type: object properties: color: type: string example: white size: type: string example: 30x20in custom_options: type: array example: - type: text label: Name value: Anna items: type: object properties: type: { type: string, example: text } label: { type: string, example: Name } value: { type: string, example: Anna } thumb_url: type: string example: 'http://example.com/thumb.jpg' mockups: type: array example: - id: 1 file_url: 'http://example.com/mockup.jpg' print_space: front items: type: object properties: id: { type: integer, example: 1 } file_url: { type: string, example: 'http://example.com/mockup.jpg' } print_space: { type: string, example: front } designs: type: array example: - id: 1 file_url: 'http://example.com/design.jpg' print_space: front items: type: object properties: id: { type: integer, example: 1 } file_url: { type: string, example: 'http://example.com/design.jpg' } print_space: { type: string, example: front } - description: 'A request rule failed' type: object example: success: false message: products.0.template_id: - 'The products.0.template_id field is required.' order_number: - 'The order number has already been taken.' data: null properties: success: type: boolean example: false message: type: object properties: products.0.template_id: type: array example: - 'The products.0.template_id field is required.' items: type: string order_number: type: array example: - 'The order number has already been taken.' items: type: string data: type: string example: null nullable: true 400: description: '' content: application/json: schema: oneOf: - description: 'A required field is missing' type: object example: success: false message: 'Missing required fields: customer_name, address' data: null properties: success: type: boolean example: false message: type: string example: 'Missing required fields: customer_name, address' data: type: string example: null nullable: true - description: 'A business rule failed' type: object example: success: false message: 'Product ID 123 not found' data: null properties: success: type: boolean example: false message: type: string example: 'Product ID 123 not found' data: type: string example: null nullable: true 401: description: 'Invalid or expired API key' content: application/json: schema: type: object example: success: false error: api_key_invalid properties: success: type: boolean example: false error: type: string example: api_key_invalid 409: description: 'The same order_number is being created by another call' content: application/json: schema: type: object example: success: false message: 'An order with this order_number is already being created. Look it up with GET /seller-api/orders?s={order_number} before sending it again.' data: null properties: success: type: boolean example: false message: type: string example: 'An order with this order_number is already being created. Look it up with GET /seller-api/orders?s={order_number} before sending it again.' data: type: string example: null nullable: true 500: description: 'Server error' content: application/json: schema: type: object example: success: false message: 'Server internal error' data: null properties: success: type: boolean example: false message: type: string example: 'Server internal error' data: type: string example: null nullable: true tags: - Orders requestBody: required: true content: application/json: schema: type: object properties: order_number: type: string description: 'Your order number, unique per seller.' example: ORD-123456 store_name: type: string description: 'Store name.' example: 'ABC Store' store_domain: type: string description: 'Store domain.' example: abc.com customer_name: type: string description: 'Required, also for FBA orders (HTTP 400 when the key is missing).' example: 'Nguyen Van A' customer_email: type: string description: 'Customer email.' example: email@example.com customer_phone: type: string description: 'Customer phone number.' example: '0123456789' address: type: string description: 'Required, also for FBA orders (HTTP 400 when the key is missing). city and postcode are required unless shipping_label is set.' example: '123 ABC Street' address_2: type: string description: 'Additional address.' example: 'Apartment 101' house_number: type: string description: 'House number.' example: 12B mailbox_number: type: string description: 'Mailbox number.' example: '456' city: type: string description: 'Required unless shipping_label is set (FBA order).' example: 'Los Angeles' state: type: string description: 'Required except for FBA orders and GB/AU/PR/DE/SE/NO/FR/GR/PT/RO/PL.' example: CA postcode: type: string description: 'Required unless shipping_label is set (FBA order).' example: '90001' country: type: string description: 'Required, also for FBA orders (HTTP 400 when the key is missing). Two-letter country code, for example US, CA, GB, AU, DE, FR, IT, ES, JP.' example: US shipping_method: type: string description: 'Shipping method.' example: standard enum: - standard - express order_note: type: string description: 'Order note.' example: 'Deliver during business hours' shipping_label: type: string description: 'Shipping label URL (required if the order is platform). Setting it makes the order an FBA order.' example: null products: type: array description: 'The products of the order.' example: - template_id: 101 quantity: 1 options: color: white size: m designs: - file_url: 'https://example.com/design.png' print_space: front mockups: - file_url: 'https://example.com/mockup.jpg' print_space: front items: type: object properties: campaign_title: type: string description: 'Campaign name.' example: 'Valentine Campaign' quantity: type: integer description: 'Product quantity. For an FBA order fulfilled by amazon it must be a multiple of 30, from 30 to 300.' example: 1 template_id: type: integer description: "Id of a product returned by GET /seller-api/catalog (the same id as in the product page of the catalog). An inactive or unknown id is rejected with 'Product ID N not found'." example: 101 options: type: object description: 'Product options as key-value pairs.' example: color: white size: 30x20in properties: { } custom_options: type: array description: 'Custom options for the product (e.g., text, image), each with type, label and value.' example: - type: text label: Name value: Anna items: type: object barcode: type: string description: 'Barcode (required only when fulfill_fba_by is amazon).' example: null fulfill_fba_by: type: string description: 'Fulfillment type (required only when order is platform).' example: null enum: - ebay - etsy - poshmark - tiktok - amazon design_by_sen: type: boolean description: 'If true, the design will be process by SenPrints.' example: false designs: type: array description: 'Artwork files, one per print area. Send them: an order without artwork cannot be produced and may be flagged invalid (fulfill_log: No artworks found). Each file_url must be a public URL ending in jpg, jpeg, png, gif or webp, or a URL on a trusted host (Google Drive, Dropbox, SenPrints CDNs). PSD, PDF, DST and EMB files are rejected, and the file is downloaded and checked after the order is created.' example: null items: type: object properties: file_url: type: string description: 'Artwork file URL.' example: 'https://example.com/design.png' print_space: type: string description: "Print area of the product (names are in GET /seller-api/catalog/info), or default for the first print area. It must be one of the product's own print areas, otherwise the order is rejected with 'Artwork print space X invalid'. For all-over-print products it must also match the size option." example: front required: - file_url - print_space mockups: type: array description: 'Mockup image per print area. Required for embroidery and all-over-print products: without it the order is accepted but cannot be produced (fulfill_log: No mockups found, or No mockups found for ). Same file rules as designs.' example: null items: type: object properties: file_url: type: string description: 'Mockup file URL.' example: 'https://example.com/mockup.jpg' print_space: type: string description: 'Print area, same rules as designs.' example: front required: - file_url - print_space required: - quantity - template_id - options required: - order_number - customer_name - address - city - postcode - country - products example: order_number: ORD-123456 store_name: 'ABC Store' store_domain: abc.com customer_name: 'Nguyen Van A' customer_email: email@example.com customer_phone: '0123456789' address: '123 ABC Street' address_2: 'Apartment 101' house_number: 12B mailbox_number: '456' city: 'Los Angeles' state: CA postcode: '90001' country: US shipping_method: standard order_note: 'Deliver during business hours' products: - template_id: 101 quantity: 1 options: color: white size: m designs: - file_url: 'https://example.com/design.png' print_space: front mockups: - file_url: 'https://example.com/mockup.jpg' print_space: front '/seller-api/orders/{id}': get: summary: 'Get order details' operationId: getOrderDetails description: "Retrieve the details of a specific order by its ID. To get tracking without polling, set a webhook\n(PUT /seller-api/webhook): order.tracking_updated sends this same object." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true message: null data: id: 1 order_number: ORD-123456 store_name: 'ABC Store' store_domain: abc.com customer_name: 'Nguyen Van A' customer_email: email@example.com customer_phone: '0123456789' address: '123 ABC Street' address_2: 'Apartment 101' house_number: 12B mailbox_number: '456' city: Hanoi state: 'Ha Dong' postcode: '100000' country: VN order_note: 'Deliver during business hours' shipping_label: 'http://example.com/label.pdf' shipping_method: standard cross_shipping: true personalized: false status: pending fulfill_status: unfulfilled address_verified: true fulfill_log: 'Order sent to production' type: standard created_at: '2025-02-28T17:01:29+07:00' updated_at: '2025-02-28T17:01:29+07:00' paid_at: '2025-03-01T12:00:00+07:00' delivered_at: '2025-03-05T09:00:00+07:00' received_at: '2025-03-06T14:00:00+07:00' total_quantity: 3 total_product_amount: 59.99 total_shipping_amount: 5.99 total_amount: 65.98 total_paid: 65.98 total_product_cost: 30 total_shipping_cost: 3 total_seller_profit: 32.98 processing_fee: 2 total_fulfill_fee: 4 processing_fee_paid: true fulfill_fee_paid: true products: - id: 1 product_name: T-shirt sku: SKU12345 quantity: 2 price: 19.99 total_amount: 39.98 seller_profit: 10 fulfill_status: fulfilled full_printed: true barcode: ABC123456789 fulfill_fba_by: Amazon design_by: seller campaign_title: 'Valentine Campaign' tracking_code: TRACK123456 tracking_url: 'http://tracking.com/TRACK123456' shipping_carrier: DHL cross_shipping: false color: Red options: color: white size: 30x20in custom_options: - type: text label: Name value: Anna thumb_url: 'http://example.com/thumb.jpg' mockups: - id: 1 file_url: 'http://example.com/mockup.jpg' print_space: front designs: - id: 1 file_url: 'http://example.com/design.jpg' print_space: front properties: success: type: boolean example: true message: type: string example: null nullable: true data: type: object properties: id: type: integer example: 1 description: 'Order ID' order_number: type: string example: ORD-123456 description: 'Your order number' store_name: type: string example: 'ABC Store' description: 'Store name' store_domain: type: string example: abc.com description: 'Store domain' customer_name: type: string example: 'Nguyen Van A' description: 'Customer name' customer_email: type: string example: email@example.com description: 'Customer email' customer_phone: type: string example: '0123456789' description: 'Customer phone number' address: type: string example: '123 ABC Street' description: 'Customer address' address_2: type: string example: 'Apartment 101' description: 'Additional address' house_number: type: string example: 12B description: 'House number' mailbox_number: type: string example: '456' description: 'Mailbox number' city: type: string example: Hanoi state: type: string example: 'Ha Dong' postcode: type: string example: '100000' description: 'Postal code' country: type: string example: VN description: 'Country code' order_note: type: string example: 'Deliver during business hours' description: 'Order note' shipping_label: type: string example: 'http://example.com/label.pdf' description: 'Shipping label URL' shipping_method: type: string example: standard description: 'Shipping method' cross_shipping: type: boolean example: true description: 'Whether the order uses cross shipping' personalized: type: boolean example: false description: 'Whether the order is personalized' status: type: string example: pending description: 'Order status: draft, pending, processing, completed, on_hold or cancelled. pending means the order passed validation and is paid and produced automatically one hour after its last update when auto fulfill is on. A new order is returned as draft before it is validated.' fulfill_status: type: string example: unfulfilled description: 'Fulfillment status. invalid means validation failed: read fulfill_log. on_delivery means every line has shipped or been cancelled. Other values include unfulfilled, processing, fulfilled, on_hold and cancelled.' address_verified: type: boolean example: true description: 'Whether the address has been verified' fulfill_log: type: string example: 'Order sent to production' description: 'Reason the order is invalid (for example File invalid: , We do not ship to , No artworks found), empty when the order is valid' type: type: string example: standard description: 'Order type' created_at: type: string example: '2025-02-28T17:01:29+07:00' description: 'Order creation timestamp' updated_at: type: string example: '2025-02-28T17:01:29+07:00' description: 'Order update timestamp' paid_at: type: string example: '2025-03-01T12:00:00+07:00' description: 'Timestamp when the order was paid' delivered_at: type: string example: '2025-03-05T09:00:00+07:00' description: 'When the first line of the order got tracking (handed to the carrier, not delivered to the customer)' received_at: type: string example: '2025-03-06T14:00:00+07:00' description: 'Timestamp when the order was received' total_quantity: type: integer example: 3 description: 'Total quantity of products in the order' total_product_amount: type: number example: 59.99 description: 'Total amount for products' total_shipping_amount: type: number example: 5.99 description: 'Total shipping fee' total_amount: type: number example: 65.98 description: 'Total order amount' total_paid: type: number example: 65.98 description: 'Total amount paid' total_product_cost: type: integer example: 30 description: 'Total product cost' total_shipping_cost: type: integer example: 3 description: 'Total shipping cost' total_seller_profit: type: number example: 32.98 description: 'Total profit for the seller' processing_fee: type: integer example: 2 description: 'Processing fee for the order' total_fulfill_fee: type: integer example: 4 description: 'Total fulfill fee' processing_fee_paid: type: boolean example: true description: 'Whether the processing fee has been paid' fulfill_fee_paid: type: boolean example: true description: 'Whether the fulfill fee has been paid' products: type: array example: - id: 1 product_name: T-shirt sku: SKU12345 quantity: 2 price: 19.99 total_amount: 39.98 seller_profit: 10 fulfill_status: fulfilled full_printed: true barcode: ABC123456789 fulfill_fba_by: Amazon design_by: seller campaign_title: 'Valentine Campaign' tracking_code: TRACK123456 tracking_url: 'http://tracking.com/TRACK123456' shipping_carrier: DHL cross_shipping: false color: Red options: color: white size: 30x20in custom_options: - type: text label: Name value: Anna thumb_url: 'http://example.com/thumb.jpg' mockups: - id: 1 file_url: 'http://example.com/mockup.jpg' print_space: front designs: - id: 1 file_url: 'http://example.com/design.jpg' print_space: front description: 'List of products in the order' items: type: object properties: id: type: integer example: 1 description: 'Order Product ID in the order' product_name: type: string example: T-shirt description: 'Product name' sku: type: string example: SKU12345 description: 'Product SKU' quantity: type: integer example: 2 description: 'Product quantity' price: type: number example: 19.99 description: 'Price of the product' total_amount: type: number example: 39.98 description: 'Total amount for this product line' seller_profit: type: integer example: 10 description: 'Profit earned by seller from this product' fulfill_status: type: string example: fulfilled description: 'Fulfillment status of the product. on_delivery once it has tracking.' full_printed: type: boolean example: true description: 'Whether the product is full printed' barcode: type: string example: ABC123456789 description: 'Barcode of the product' fulfill_fba_by: type: string example: Amazon description: 'Fulfillment service provider' design_by: type: string example: seller description: 'Design will be done by seller or SenPrints' campaign_title: type: string example: 'Valentine Campaign' description: 'Campaign name related to the product' tracking_code: type: string example: TRACK123456 description: 'Tracking code for this product' tracking_url: type: string example: 'http://tracking.com/TRACK123456' description: 'Tracking URL for this product' shipping_carrier: type: string example: DHL description: 'Shipping carrier used' cross_shipping: type: boolean example: false description: 'Whether the product uses cross shipping' color: type: string example: Red description: 'Product color' options: type: object properties: color: type: string example: white size: type: string example: 30x20in description: 'Product options as key-value pairs' custom_options: type: array example: - type: text label: Name value: Anna description: 'Custom options for the product (e.g., text, image)' items: type: object properties: type: type: string example: text label: type: string example: Name value: type: string example: Anna thumb_url: type: string example: 'http://example.com/thumb.jpg' description: 'Product thumbnail URL' mockups: type: array example: - id: 1 file_url: 'http://example.com/mockup.jpg' print_space: front description: 'List of product mockups (id, file_url, print_space)' items: type: object properties: id: type: integer example: 1 file_url: type: string example: 'http://example.com/mockup.jpg' print_space: type: string example: front designs: type: array example: - id: 1 file_url: 'http://example.com/design.jpg' print_space: front description: 'List of product designs (id, file_url, print_space)' items: type: object properties: id: type: integer example: 1 file_url: type: string example: 'http://example.com/design.jpg' print_space: type: string example: front 401: description: 'Invalid or expired API key' content: application/json: schema: type: object example: success: false error: api_key_invalid properties: success: type: boolean example: false error: type: string example: api_key_invalid 404: description: 'Order not found' content: application/json: schema: type: object example: success: false message: 'Order not found' data: null properties: success: type: boolean example: false message: type: string example: 'Order not found' data: type: string example: null nullable: true tags: - Orders put: summary: 'Update an order' operationId: updateAnOrder description: "Only send fields that need updating. Allowed while the order is draft, pending or on_hold (otherwise HTTP 400).\nAfter a successful update the order is validated again in the queue, which can move an on_hold order back to\npending, so a held order is no longer safe from the automatic charge (a valid pending order is paid and produced\none hour after its last update when auto fulfill is on). Errors work as for creating an order: a failed request\nrule answers HTTP 200 with success=false and message as an object keyed by field, a failed business rule\nanswers HTTP 400." parameters: [] responses: 200: description: '' content: application/json: schema: oneOf: - description: 'Order updated, validated again in the queue' type: object example: success: true message: 'Order ORD-123456 updated successfully' data: null properties: success: type: boolean example: true message: type: string example: 'Order ORD-123456 updated successfully' data: type: string example: null nullable: true - description: 'A request rule failed' type: object example: success: false message: products.0.template_id: - 'The products.0.template_id field is required.' order_number: - 'The order number has already been taken.' data: null properties: success: type: boolean example: false message: type: object properties: products.0.template_id: type: array example: - 'The products.0.template_id field is required.' items: type: string order_number: type: array example: - 'The order number has already been taken.' items: type: string data: type: string example: null nullable: true 400: description: '' content: application/json: schema: oneOf: - description: 'The order is not draft, pending or on_hold' type: object example: success: false message: 'Order not in valid status (pending, draft, on hold) to update' data: null properties: success: type: boolean example: false message: type: string example: 'Order not in valid status (pending, draft, on hold) to update' data: type: string example: null nullable: true - description: 'A business rule failed' type: object example: success: false message: 'Product ID 123 not found' data: null properties: success: type: boolean example: false message: type: string example: 'Product ID 123 not found' data: type: string example: null nullable: true 401: description: 'Invalid or expired API key' content: application/json: schema: type: object example: success: false error: api_key_invalid properties: success: type: boolean example: false error: type: string example: api_key_invalid 404: description: 'Order not found' content: application/json: schema: type: object example: success: false message: 'Order not found' data: null properties: success: type: boolean example: false message: type: string example: 'Order not found' data: type: string example: null nullable: true 500: description: 'Server error' content: application/json: schema: type: object example: success: false message: 'Server internal error' data: null properties: success: type: boolean example: false message: type: string example: 'Server internal error' data: type: string example: null nullable: true tags: - Orders requestBody: required: false content: application/json: schema: type: object properties: order_number: type: string description: 'Your order number, unique per seller.' example: ORD-123456 customer_name: type: string description: 'Customer name.' example: 'Nguyen Van A' customer_email: type: string description: 'Customer email.' example: email@example.com customer_phone: type: string description: 'Customer phone number.' example: '0123456789' address: type: string description: 'Customer address.' example: '123 ABC Street' address_2: type: string description: 'Additional address.' example: 'Apartment 101' house_number: type: string description: 'House number.' example: 12B mailbox_number: type: string description: 'Mailbox number.' example: '456' city: type: string description: City. example: 'Los Angeles' state: type: string description: 'Required when the country needs a state and the order has none.' example: CA postcode: type: string description: 'Postal code.' example: '90001' country: type: string description: 'Two-letter country code, for example US, CA, GB, AU, DE, FR, IT, ES, JP.' example: US shipping_method: type: string description: 'Shipping method.' example: standard enum: - standard - express order_note: type: string description: 'Order note.' example: 'Deliver during business hours' shipping_label: type: string description: 'Shipping label URL (required if the order is platform).' example: null products: type: array description: 'The products of the order.' example: - template_id: 101 quantity: 1 options: color: white size: m designs: - file_url: 'https://example.com/design.png' print_space: front mockups: - file_url: 'https://example.com/mockup.jpg' print_space: front items: type: object properties: id: type: integer description: 'Order Product ID, fill only when updating an existing product.' example: null campaign_title: type: string description: 'Campaign name.' example: 'Valentine Campaign' quantity: type: integer description: 'Product quantity. For an FBA order fulfilled by amazon it must be a multiple of 30, from 30 to 300.' example: 1 template_id: type: integer description: 'Id of a product returned by GET /seller-api/catalog.' example: 101 options: type: object description: 'Product options as key-value pairs.' example: color: white size: 30x20in properties: { } custom_options: type: array description: 'Custom options for the product, each with type, label and value.' example: - type: text label: Name value: Anna items: type: object barcode: type: string description: 'Barcode (required only when fulfill_fba_by is amazon).' example: null fulfill_fba_by: type: string description: 'Fulfillment type (required only when order is platform).' example: null enum: - ebay - etsy - poshmark - tiktok - amazon design_by_sen: type: boolean description: 'If true, the design will be process by SenPrints.' example: false designs: type: array description: 'Artwork files, one per print area. Same file rules as POST /seller-api/orders.' example: null items: type: object properties: id: type: integer description: 'ID of the design file.' example: null file_url: type: string description: 'Artwork file URL.' example: 'https://example.com/design.png' print_space: type: string description: 'Print area of the product (names are in GET /seller-api/catalog/info), or default for the first print area.' example: front required: - file_url - print_space mockups: type: array description: 'Mockup image per print area. Same file rules as designs.' example: null items: type: object properties: id: type: integer description: 'ID of the mockup file.' example: null file_url: type: string description: 'Mockup file URL.' example: 'https://example.com/mockup.jpg' print_space: type: string description: 'Print area, same rules as designs.' example: front required: - file_url - print_space required: - quantity - template_id - options example: order_number: ORD-123456 customer_name: 'Nguyen Van A' customer_email: email@example.com customer_phone: '0123456789' address: '123 ABC Street' address_2: 'Apartment 101' house_number: 12B mailbox_number: '456' city: 'Los Angeles' state: CA postcode: '90001' country: US shipping_method: standard order_note: 'Deliver during business hours' products: - template_id: 101 quantity: 1 options: color: white size: m designs: - file_url: 'https://example.com/design.png' print_space: front mockups: - file_url: 'https://example.com/mockup.jpg' print_space: front parameters: - in: path name: id description: 'The unique ID of the order.' example: 1 required: true schema: type: integer /seller-api/orders/validate: post: summary: 'Check an order without creating it' operationId: checkAnOrderWithoutCreatingIt description: "Dry run of POST /seller-api/orders, and takes the same body. It runs the same request rules and product checks,\nand writes nothing: no order is created, no file is stored, no job is queued and nothing is charged. Use it to\ntest a payload. A failed check answers HTTP 400, including a missing customer_name, address or country\n(POST /seller-api/orders answers HTTP 200 with success=false for failed request rules). Checks that only run\nafter an order exists (address verification, downloading the artwork files, shipping cost and supplier\nassignment) are listed in data.not_checked." parameters: [] responses: 200: description: 'The order data passed every check that can run without creating the order' content: application/json: schema: type: object example: success: true message: 'Order data is valid. Nothing was created and nothing was charged.' data: valid: true errors: [] warnings: - 'No mockups found' not_checked: - 'The address is verified after the order is created.' - 'Artwork and mockup files are downloaded and checked after the order is created.' - 'Shipping cost, supplier assignment and the order total are calculated after the order is created.' properties: success: type: boolean example: true message: type: string example: 'Order data is valid. Nothing was created and nothing was charged.' data: type: object properties: valid: type: boolean example: true description: 'True when every check passed' errors: type: array example: [] description: 'What to fix: an object keyed by field for request rules, a list of messages for product checks' warnings: type: array example: - 'No mockups found' description: "Problems that do not fail POST /seller-api/orders but leave the order unusable, for example 'No artworks found' or 'No mockups found'" items: type: string not_checked: type: array example: - 'The address is verified after the order is created.' - 'Artwork and mockup files are downloaded and checked after the order is created.' - 'Shipping cost, supplier assignment and the order total are calculated after the order is created.' description: 'Checks that only run after the order is created' items: type: string 400: description: 'The order data is not valid' content: application/json: schema: type: object example: success: false message: 'Order data is not valid' data: valid: false errors: products.0.template_id: - 'The products.0.template_id field is required.' warnings: [] not_checked: - 'The address is verified after the order is created.' - 'Artwork and mockup files are downloaded and checked after the order is created.' - 'Shipping cost, supplier assignment and the order total are calculated after the order is created.' properties: success: type: boolean example: false message: type: string example: 'Order data is not valid' data: type: object properties: valid: type: boolean example: false description: 'True when every check passed' errors: type: object properties: products.0.template_id: type: array example: - 'The products.0.template_id field is required.' items: type: string description: 'What to fix: an object keyed by field for request rules, a list of messages for product checks' warnings: type: array example: [] description: "Problems that do not fail POST /seller-api/orders but leave the order unusable, for example 'No artworks found' or 'No mockups found'" not_checked: type: array example: - 'The address is verified after the order is created.' - 'Artwork and mockup files are downloaded and checked after the order is created.' - 'Shipping cost, supplier assignment and the order total are calculated after the order is created.' description: 'Checks that only run after the order is created' items: type: string 401: description: 'Invalid or expired API key' content: application/json: schema: type: object example: success: false error: api_key_invalid properties: success: type: boolean example: false error: type: string example: api_key_invalid 500: description: 'Server error' content: application/json: schema: type: object example: success: false message: 'Server internal error' data: null properties: success: type: boolean example: false message: type: string example: 'Server internal error' data: type: string example: null nullable: true tags: - Orders requestBody: required: true content: application/json: schema: type: object properties: order_number: type: string description: 'Your order number, unique per seller.' example: ORD-123456 store_name: type: string description: 'Store name.' example: 'ABC Store' store_domain: type: string description: 'Store domain.' example: abc.com customer_name: type: string description: 'Required, also for FBA orders (HTTP 400 when the key is missing).' example: 'Nguyen Van A' customer_email: type: string description: 'Customer email.' example: email@example.com customer_phone: type: string description: 'Customer phone number.' example: '0123456789' address: type: string description: 'Required, also for FBA orders (HTTP 400 when the key is missing). city and postcode are required unless shipping_label is set.' example: '123 ABC Street' address_2: type: string description: 'Additional address.' example: 'Apartment 101' house_number: type: string description: 'House number.' example: 12B mailbox_number: type: string description: 'Mailbox number.' example: '456' city: type: string description: 'Required unless shipping_label is set (FBA order).' example: 'Los Angeles' state: type: string description: 'Required except for FBA orders and GB/AU/PR/DE/SE/NO/FR/GR/PT/RO/PL.' example: CA postcode: type: string description: 'Required unless shipping_label is set (FBA order).' example: '90001' country: type: string description: 'Required, also for FBA orders (HTTP 400 when the key is missing). Two-letter country code, for example US, CA, GB, AU, DE, FR, IT, ES, JP.' example: US shipping_method: type: string description: 'Shipping method.' example: standard enum: - standard - express order_note: type: string description: 'Order note.' example: 'Deliver during business hours' shipping_label: type: string description: 'Shipping label URL (required if the order is platform). Setting it makes the order an FBA order.' example: null products: type: array description: 'The products of the order.' example: - template_id: 101 quantity: 1 options: color: white size: m designs: - file_url: 'https://example.com/design.png' print_space: front mockups: - file_url: 'https://example.com/mockup.jpg' print_space: front items: type: object properties: campaign_title: type: string description: 'Campaign name.' example: 'Valentine Campaign' quantity: type: integer description: 'Product quantity. For an FBA order fulfilled by amazon it must be a multiple of 30, from 30 to 300.' example: 1 template_id: type: integer description: "Id of a product returned by GET /seller-api/catalog (the same id as in the product page of the catalog). An inactive or unknown id is rejected with 'Product ID N not found'." example: 101 options: type: object description: 'Product options as key-value pairs.' example: color: white size: 30x20in properties: { } custom_options: type: array description: 'Custom options for the product (e.g., text, image), each with type, label and value.' example: - type: text label: Name value: Anna items: type: object barcode: type: string description: 'Barcode (required only when fulfill_fba_by is amazon).' example: null fulfill_fba_by: type: string description: 'Fulfillment type (required only when order is platform).' example: null enum: - ebay - etsy - poshmark - tiktok - amazon design_by_sen: type: boolean description: 'If true, the design will be process by SenPrints.' example: false designs: type: array description: 'Artwork files, one per print area. Send them: an order without artwork cannot be produced and may be flagged invalid (fulfill_log: No artworks found). Each file_url must be a public URL ending in jpg, jpeg, png, gif or webp, or a URL on a trusted host (Google Drive, Dropbox, SenPrints CDNs). PSD, PDF, DST and EMB files are rejected, and the file is downloaded and checked after the order is created.' example: null items: type: object properties: file_url: type: string description: 'Artwork file URL.' example: 'https://example.com/design.png' print_space: type: string description: "Print area of the product (names are in GET /seller-api/catalog/info), or default for the first print area. It must be one of the product's own print areas, otherwise the order is rejected with 'Artwork print space X invalid'. For all-over-print products it must also match the size option." example: front required: - file_url - print_space mockups: type: array description: 'Mockup image per print area. Required for embroidery and all-over-print products: without it the order is accepted but cannot be produced (fulfill_log: No mockups found, or No mockups found for ). Same file rules as designs.' example: null items: type: object properties: file_url: type: string description: 'Mockup file URL.' example: 'https://example.com/mockup.jpg' print_space: type: string description: 'Print area, same rules as designs.' example: front required: - file_url - print_space required: - quantity - template_id - options required: - order_number - customer_name - address - city - postcode - country - products example: order_number: ORD-123456 store_name: 'ABC Store' store_domain: abc.com customer_name: 'Nguyen Van A' customer_email: email@example.com customer_phone: '0123456789' address: '123 ABC Street' address_2: 'Apartment 101' house_number: 12B mailbox_number: '456' city: 'Los Angeles' state: CA postcode: '90001' country: US shipping_method: standard order_note: 'Deliver during business hours' products: - template_id: 101 quantity: 1 options: color: white size: m designs: - file_url: 'https://example.com/design.png' print_space: front mockups: - file_url: 'https://example.com/mockup.jpg' print_space: front '/seller-api/orders/{id}/{action}': put: summary: 'Update order status' operationId: updateOrderStatus description: "hold: stops the automatic charge while the order stays untouched (editing it later validates it again and can\nreturn it to pending). resume: puts the order back to draft; it becomes pending when validation passes.\ncancel: cancels the order; do it within one hour of the last update to avoid the automatic charge of a valid\npending order." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Order ORD-123456 status updated successfully' data: null properties: success: type: boolean example: true message: type: string example: 'Order ORD-123456 status updated successfully' data: type: string example: null nullable: true 401: description: 'Invalid or expired API key' content: application/json: schema: type: object example: success: false error: api_key_invalid properties: success: type: boolean example: false error: type: string example: api_key_invalid 403: description: 'Unknown action' content: application/json: schema: type: object example: success: false message: 'Invalid action' data: null properties: success: type: boolean example: false message: type: string example: 'Invalid action' data: type: string example: null nullable: true 404: description: 'Order not found' content: application/json: schema: type: object example: success: false message: 'Resource not found' data: null errors: null properties: success: type: boolean example: false message: type: string example: 'Resource not found' data: type: string example: null nullable: true errors: type: string example: null nullable: true 500: description: 'Error updating order status' content: application/json: schema: type: object example: success: false message: 'Server internal error' data: null properties: success: type: boolean example: false message: type: string example: 'Server internal error' data: type: string example: null nullable: true tags: - Orders parameters: - in: path name: id description: 'The unique ID of the order.' example: 1 required: true schema: type: integer - in: path name: action description: 'Action to update order status: hold, resume or cancel.' example: hold required: true schema: type: string /seller-api/webhook: get: summary: 'Get the webhook' operationId: getTheWebhook description: "Returns the URL that receives your webhooks, its events, and the secret that signs them (null when\ndeliveries are not signed)." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true message: null data: url: 'https://example.com/senprints/webhook' secret: whsec_3jT9qX2mPz8LkV4nR7sW1yB6cD0fG5hJ2aE8uQ events: - order.validated - order.invalid - order.paid - order.on_hold - order.cancelled - order.completed - order.tracking_updated properties: success: type: boolean example: true message: type: string example: null nullable: true data: type: object properties: url: type: string example: 'https://example.com/senprints/webhook' description: 'URL that receives the webhooks' secret: type: string example: whsec_3jT9qX2mPz8LkV4nR7sW1yB6cD0fG5hJ2aE8uQ description: 'Signing secret for X-SenPrints-Signature, null when deliveries are not signed' events: type: array example: - order.validated - order.invalid - order.paid - order.on_hold - order.cancelled - order.completed - order.tracking_updated description: 'Events sent to the URL (the ones you picked)' items: type: string 401: description: 'Invalid or expired API key' content: application/json: schema: type: object example: success: false error: api_key_invalid properties: success: type: boolean example: false error: type: string example: api_key_invalid 404: description: 'No webhook set' content: application/json: schema: type: object example: success: false message: 'Webhook not set' data: null properties: success: type: boolean example: false message: type: string example: 'Webhook not set' data: type: string example: null nullable: true tags: - Webhooks put: summary: 'Set the webhook' operationId: setTheWebhook description: "Creates the webhook or changes its URL and events. A new webhook receives every event unless `events`\npicks some; a later call without `events` keeps the current list. Only `url` is required: the webhook\nhas no signing secret until `rotate_secret` is true, which creates one (or replaces it); `remove_secret`\ndrops it. Any other call keeps the current secret, or the lack of one. Takes effect for the next event." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Webhook saved' data: url: 'https://example.com/senprints/webhook' secret: null events: - order.paid - order.tracking_updated properties: success: type: boolean example: true message: type: string example: 'Webhook saved' data: type: object properties: url: type: string example: 'https://example.com/senprints/webhook' secret: type: string example: null nullable: true events: type: array example: - order.paid - order.tracking_updated items: type: string 400: description: 'Invalid URL' content: application/json: schema: type: object example: success: false message: 'The url must resolve to a public address.' data: null errors: url: - 'The url must resolve to a public address.' properties: success: type: boolean example: false message: type: string example: 'The url must resolve to a public address.' data: type: string example: null nullable: true errors: type: object properties: url: type: array example: - 'The url must resolve to a public address.' items: type: string 401: description: 'Invalid or expired API key' content: application/json: schema: type: object example: success: false error: api_key_invalid properties: success: type: boolean example: false error: type: string example: api_key_invalid tags: - Webhooks requestBody: required: true content: application/json: schema: type: object properties: url: type: string description: 'HTTPS URL that receives the webhooks, up to 255 characters. It must resolve to a public address and answer 2xx; redirects are not followed.' example: 'https://example.com/senprints/webhook' events: type: array description: 'Events to receive. A new webhook gets every event when this is omitted; on a change, omitting it keeps the current list.' example: - order.paid - order.tracking_updated items: type: string enum: - order.validated - order.invalid - order.paid - order.on_hold - order.cancelled - order.completed - order.tracking_updated rotate_secret: type: boolean description: 'Set true to create a signing secret, or replace the current one. A webhook has none until you ask: deliveries are not signed.' example: false remove_secret: type: boolean description: 'Set true to drop the signing secret; deliveries are no longer signed. Cannot be combined with rotate_secret.' example: false required: - url example: url: 'https://example.com/senprints/webhook' events: - order.paid - order.tracking_updated rotate_secret: false remove_secret: false delete: summary: 'Delete the webhook' operationId: deleteTheWebhook description: 'Stops the webhooks. Deliveries already queued are dropped.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Webhook deleted' data: null properties: success: type: boolean example: true message: type: string example: 'Webhook deleted' data: type: string example: null nullable: true 401: description: 'Invalid or expired API key' content: application/json: schema: type: object example: success: false error: api_key_invalid properties: success: type: boolean example: false error: type: string example: api_key_invalid 404: description: 'No webhook set' content: application/json: schema: type: object example: success: false message: 'Webhook not set' data: null properties: success: type: boolean example: false message: type: string example: 'Webhook not set' data: type: string example: null nullable: true tags: - Webhooks /seller-api/webhook/deliveries: get: summary: 'List recent deliveries' operationId: listRecentDeliveries description: "The webhook requests SenPrints sent to your URL in the last 30 days, newest first, one row per attempt:\nthe exact body posted, how your URL answered (status and the start of its response), and why an attempt\nfailed. Use it to find out why an event did not arrive, or to replay a body against your handler. A failed\nattempt is retried (see Delivery above), and each retry is a new row with the same `id`; its body is\nrebuilt with the order as it is then. Test pings are listed too." parameters: - in: query name: order_id description: 'Only the deliveries about this order.' example: 123456 required: false schema: type: integer description: 'Only the deliveries about this order.' example: 123456 - in: query name: failed_only description: 'Set 1 to list only the attempts that failed.' example: false required: false schema: type: boolean description: 'Set 1 to list only the attempts that failed.' example: false - in: query name: limit description: 'How many attempts to return, newest first, from 1 to 100. Defaults to 20 (each row carries the order body).' example: 20 required: false schema: type: integer description: 'How many attempts to return, newest first, from 1 to 100. Defaults to 20 (each row carries the order body).' example: 20 responses: 200: description: '' content: application/json: schema: type: object example: success: true message: null data: - id: 0d8f3c9e-5b6a-4a7e-9f1c-2b3d4e5f6a7b event: order.tracking_updated order_id: 123456 attempt: 2 delivered: true request_body: id: 0d8f3c9e-5b6a-4a7e-9f1c-2b3d4e5f6a7b event: order.tracking_updated created_at: '2026-10-21T09:16:02+00:00' data: order: id: 123456 order_number: ORD-123456 status: processing fulfill_status: on_delivery products: - id: 987654 fulfill_status: on_delivery tracking_code: '9400111899223344556677' tracking_url: 'https://tools.usps.com/go/TrackConfirmAction?tLabels=9400111899223344556677' shipping_carrier: USPS previous: null status_code: 200 response_body: '{"received":true}' error: null duration_ms: 184 created_at: '2026-10-21T09:16:02+00:00' - id: 0d8f3c9e-5b6a-4a7e-9f1c-2b3d4e5f6a7b event: order.tracking_updated order_id: 123456 attempt: 1 delivered: false request_body: id: 0d8f3c9e-5b6a-4a7e-9f1c-2b3d4e5f6a7b event: order.tracking_updated created_at: '2026-10-21T09:15:01+00:00' data: order: id: 123456 order_number: ORD-123456 previous: null status_code: 503 response_body: 'Service Unavailable' error: 'Your URL answered HTTP 503' duration_ms: 92 created_at: '2026-10-21T09:15:01+00:00' - id: 6c1a2b3c-4d5e-4f60-8a9b-0c1d2e3f4a5b event: ping order_id: null attempt: 1 delivered: false request_body: id: 6c1a2b3c-4d5e-4f60-8a9b-0c1d2e3f4a5b event: ping created_at: '2026-10-20T14:02:11+00:00' data: message: 'This is a test webhook from SenPrints.' status_code: null response_body: null error: 'Could not connect to your URL (timeout, refused connection or TLS error).' duration_ms: 10003 created_at: '2026-10-20T14:02:11+00:00' properties: success: type: boolean example: true message: type: string example: null nullable: true data: type: array example: - id: 0d8f3c9e-5b6a-4a7e-9f1c-2b3d4e5f6a7b event: order.tracking_updated order_id: 123456 attempt: 2 delivered: true request_body: id: 0d8f3c9e-5b6a-4a7e-9f1c-2b3d4e5f6a7b event: order.tracking_updated created_at: '2026-10-21T09:16:02+00:00' data: order: id: 123456 order_number: ORD-123456 status: processing fulfill_status: on_delivery products: - id: 987654 fulfill_status: on_delivery tracking_code: '9400111899223344556677' tracking_url: 'https://tools.usps.com/go/TrackConfirmAction?tLabels=9400111899223344556677' shipping_carrier: USPS previous: null status_code: 200 response_body: '{"received":true}' error: null duration_ms: 184 created_at: '2026-10-21T09:16:02+00:00' - id: 0d8f3c9e-5b6a-4a7e-9f1c-2b3d4e5f6a7b event: order.tracking_updated order_id: 123456 attempt: 1 delivered: false request_body: id: 0d8f3c9e-5b6a-4a7e-9f1c-2b3d4e5f6a7b event: order.tracking_updated created_at: '2026-10-21T09:15:01+00:00' data: order: id: 123456 order_number: ORD-123456 previous: null status_code: 503 response_body: 'Service Unavailable' error: 'Your URL answered HTTP 503' duration_ms: 92 created_at: '2026-10-21T09:15:01+00:00' - id: 6c1a2b3c-4d5e-4f60-8a9b-0c1d2e3f4a5b event: ping order_id: null attempt: 1 delivered: false request_body: id: 6c1a2b3c-4d5e-4f60-8a9b-0c1d2e3f4a5b event: ping created_at: '2026-10-20T14:02:11+00:00' data: message: 'This is a test webhook from SenPrints.' status_code: null response_body: null error: 'Could not connect to your URL (timeout, refused connection or TLS error).' duration_ms: 10003 created_at: '2026-10-20T14:02:11+00:00' items: type: object properties: id: type: string example: 0d8f3c9e-5b6a-4a7e-9f1c-2b3d4e5f6a7b event: type: string example: order.tracking_updated order_id: type: integer example: 123456 attempt: type: integer example: 2 delivered: type: boolean example: true request_body: type: object properties: id: type: string example: 0d8f3c9e-5b6a-4a7e-9f1c-2b3d4e5f6a7b event: type: string example: order.tracking_updated created_at: type: string example: '2026-10-21T09:16:02+00:00' data: type: object properties: order: type: object properties: id: type: integer example: 123456 order_number: type: string example: ORD-123456 status: type: string example: processing fulfill_status: type: string example: on_delivery products: type: array example: [{ id: 987654, fulfill_status: on_delivery, tracking_code: '9400111899223344556677', tracking_url: 'https://tools.usps.com/go/TrackConfirmAction?tLabels=9400111899223344556677', shipping_carrier: USPS }] items: { type: object, properties: { id: { type: integer, example: 987654 }, fulfill_status: { type: string, example: on_delivery }, tracking_code: { type: string, example: '9400111899223344556677' }, tracking_url: { type: string, example: 'https://tools.usps.com/go/TrackConfirmAction?tLabels=9400111899223344556677' }, shipping_carrier: { type: string, example: USPS } } } previous: type: string example: null nullable: true status_code: type: integer example: 200 response_body: type: string example: '{"received":true}' error: type: string example: null nullable: true duration_ms: type: integer example: 184 created_at: type: string example: '2026-10-21T09:16:02+00:00' 401: description: 'Invalid or expired API key' content: application/json: schema: type: object example: success: false error: api_key_invalid properties: success: type: boolean example: false error: type: string example: api_key_invalid tags: - Webhooks /seller-api/webhook/test: post: summary: 'Send a test event' operationId: sendATestEvent description: "Sends a `ping` event to your URL now (signed when the webhook has a secret) and reports how it answered.\nUse it to check the URL, and your signature check if you use one, before the first order ships. It is\nnot retried." parameters: [] responses: 200: description: '' content: application/json: schema: oneOf: - description: '' type: object example: success: true message: null data: delivered: true status_code: 200 error: null properties: success: type: boolean example: true message: type: string example: null nullable: true data: type: object properties: delivered: type: boolean example: true description: 'True when your URL answered 2xx' status_code: type: integer example: 200 description: 'HTTP status your URL answered, null when it could not be reached' error: type: string example: null description: 'Why the delivery failed' - description: 'The URL did not answer 2xx' type: object example: success: true message: null data: delivered: false status_code: 500 error: 'Your URL answered HTTP 500' properties: success: type: boolean example: true message: type: string example: null nullable: true data: type: object properties: delivered: type: boolean example: false description: 'True when your URL answered 2xx' status_code: type: integer example: 500 description: 'HTTP status your URL answered, null when it could not be reached' error: type: string example: 'Your URL answered HTTP 500' description: 'Why the delivery failed' 401: description: 'Invalid or expired API key' content: application/json: schema: type: object example: success: false error: api_key_invalid properties: success: type: boolean example: false error: type: string example: api_key_invalid 404: description: 'No webhook set' content: application/json: schema: type: object example: success: false message: 'Webhook not set' data: null properties: success: type: boolean example: false message: type: string example: 'Webhook not set' data: type: string example: null nullable: true tags: - Webhooks /seller-api/catalog: get: summary: 'Get the list of catalogs' operationId: getTheListOfCatalogs description: "Retrieve the list of catalogs available in the system. The tags below document GET /seller-api/catalog for Scribe.\nProducts are grouped by category. A product's `id` is the `template_id` of POST /seller-api/orders and the `id`\nof GET /seller-api/catalog/info; `options` are the values an order line picks from, and `print_spaces` the names\nits `designs[].print_space` uses (sizes in pixels)." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true message: null data: - id: 12 name: T-Shirts full_name: T-Shirts slug: t-shirts products: - id: 101 name: 'Unisex Standard T-Shirt' sku: AMST thumb_url: 'https://example.com/thumb.jpg' base_cost: 8.5 base_costs: null suggested_price: 24.99 options: color: - white - black - navy size: - s - m - l - xl - 2xl print_spaces: - name: front width: 4200 height: 4800 - name: back width: 4200 height: 4800 extra_print_cost: 2 priority: null mockup_type: flat attributes: null pricing_mode: adjust_price full_printed: 0 status: active market_location: null system_type: regular quantity: null default_option: null custom_options: null colors: - name: white hex_code: '#ffffff' - name: black hex_code: '#000000' - name: navy hex_code: '#1f2a44' sellable_option_types: [] mockups: [] selected: false mockups_psd: [] child_menu: [] properties: success: type: boolean example: true message: type: string example: null nullable: true data: type: array example: - id: 12 name: T-Shirts full_name: T-Shirts slug: t-shirts products: - id: 101 name: 'Unisex Standard T-Shirt' sku: AMST thumb_url: 'https://example.com/thumb.jpg' base_cost: 8.5 base_costs: null suggested_price: 24.99 options: color: - white - black - navy size: - s - m - l - xl - 2xl print_spaces: - name: front width: 4200 height: 4800 - name: back width: 4200 height: 4800 extra_print_cost: 2 priority: null mockup_type: flat attributes: null pricing_mode: adjust_price full_printed: 0 status: active market_location: null system_type: regular quantity: null default_option: null custom_options: null colors: - name: white hex_code: '#ffffff' - name: black hex_code: '#000000' - name: navy hex_code: '#1f2a44' sellable_option_types: [] mockups: [] selected: false mockups_psd: [] child_menu: [] items: type: object properties: id: type: integer example: 12 name: type: string example: T-Shirts full_name: type: string example: T-Shirts slug: type: string example: t-shirts products: type: array example: - id: 101 name: 'Unisex Standard T-Shirt' sku: AMST thumb_url: 'https://example.com/thumb.jpg' base_cost: 8.5 base_costs: null suggested_price: 24.99 options: color: - white - black - navy size: - s - m - l - xl - 2xl print_spaces: - name: front width: 4200 height: 4800 - name: back width: 4200 height: 4800 extra_print_cost: 2 priority: null mockup_type: flat attributes: null pricing_mode: adjust_price full_printed: 0 status: active market_location: null system_type: regular quantity: null default_option: null custom_options: null colors: - name: white hex_code: '#ffffff' - name: black hex_code: '#000000' - name: navy hex_code: '#1f2a44' sellable_option_types: [] mockups: [] selected: false mockups_psd: [] items: type: object properties: id: type: integer example: 101 name: type: string example: 'Unisex Standard T-Shirt' sku: type: string example: AMST thumb_url: type: string example: 'https://example.com/thumb.jpg' base_cost: type: number example: 8.5 base_costs: type: string example: null nullable: true suggested_price: type: number example: 24.99 options: type: object properties: color: type: array example: - white - black - navy items: type: string size: type: array example: - s - m - l - xl - 2xl items: type: string print_spaces: type: array example: - name: front width: 4200 height: 4800 - name: back width: 4200 height: 4800 items: type: object properties: name: type: string example: front width: type: integer example: 4200 height: type: integer example: 4800 extra_print_cost: type: integer example: 2 priority: type: string example: null nullable: true mockup_type: type: string example: flat attributes: type: string example: null nullable: true pricing_mode: type: string example: adjust_price full_printed: type: integer example: 0 status: type: string example: active market_location: type: string example: null nullable: true system_type: type: string example: regular quantity: type: string example: null nullable: true default_option: type: string example: null nullable: true custom_options: type: string example: null nullable: true colors: type: array example: - name: white hex_code: '#ffffff' - name: black hex_code: '#000000' - name: navy hex_code: '#1f2a44' items: type: object properties: name: type: string example: white hex_code: type: string example: '#ffffff' sellable_option_types: type: array example: [] mockups: type: array example: [] selected: type: boolean example: false mockups_psd: type: array example: [] child_menu: type: array example: [] 401: description: 'Invalid or expired API key' content: application/json: schema: type: object example: success: false error: api_key_invalid properties: success: type: boolean example: false error: type: string example: api_key_invalid tags: - Catalog /seller-api/catalog/info: get: summary: 'Get catalog info' operationId: getCatalogInfo description: "Get details of a specific catalog product. Public API get template product info for catalog; the tags below\ndocument GET /seller-api/catalog/info for Scribe.\n`variants` hold the base cost per option combination (`variant_key` like `white-s`) and location (`*` = any);\n`shipping_rules` the shipping cost per method and location; `shipping_times` the delivery days per method,\nkeyed by location code (`*` = everywhere else); `processing_time` is in days." parameters: - in: query name: id description: 'The ID of the catalog product, from GET /seller-api/catalog.' example: 1 required: true schema: type: integer description: 'The ID of the catalog product, from GET /seller-api/catalog.' example: 1 responses: 200: description: '' content: application/json: schema: type: object example: success: true message: null data: name: 'Unisex Standard T-Shirt' thumb_url: 'https://example.com/thumb.jpg' sku: AMST variants: - product_id: 101 variant_key: white-s base_cost: 8.5 location_code: '*' out_of_stock: 0 adjust_price: 0 price: 24.99 old_price: 0 weight: 0.15 quantity: null check_quantity: 0 sku: AMST-WHITE-S - product_id: 101 variant_key: black-2xl base_cost: 10.5 location_code: '*' out_of_stock: 0 adjust_price: 2 price: 26.99 old_price: 0 weight: 0.18 quantity: null check_quantity: 0 sku: AMST-BLACK-2XL shipping_rules: - product_id: 101 variant_key: null shipping_method: standard location_code: US shipping_cost: 4.99 extra_cost: 2 - product_id: 101 variant_key: null shipping_method: standard location_code: '*' shipping_cost: 8.99 extra_cost: 3 description: 'Classic fit, 100% cotton.' market_location: null colors: - name: white hex_code: '#ffffff' - name: black hex_code: '#000000' print_spaces: - name: front width: 4200 height: 4800 - name: back width: 4200 height: 4800 attributes: null options: color: - white - black size: - s - m - l - xl - 2xl size_guides: [] shipping_times: standard: US: min: 3 max: 8 '*': min: 7 max: 15 express: US: min: 2 max: 4 '*': min: 5 max: 9 processing_time: 2 properties: success: type: boolean example: true message: type: string example: null nullable: true data: type: object properties: name: type: string example: 'Unisex Standard T-Shirt' thumb_url: type: string example: 'https://example.com/thumb.jpg' sku: type: string example: AMST variants: type: array example: - product_id: 101 variant_key: white-s base_cost: 8.5 location_code: '*' out_of_stock: 0 adjust_price: 0 price: 24.99 old_price: 0 weight: 0.15 quantity: null check_quantity: 0 sku: AMST-WHITE-S - product_id: 101 variant_key: black-2xl base_cost: 10.5 location_code: '*' out_of_stock: 0 adjust_price: 2 price: 26.99 old_price: 0 weight: 0.18 quantity: null check_quantity: 0 sku: AMST-BLACK-2XL items: type: object properties: product_id: type: integer example: 101 variant_key: type: string example: white-s base_cost: type: number example: 8.5 location_code: type: string example: '*' out_of_stock: type: integer example: 0 adjust_price: type: integer example: 0 price: type: number example: 24.99 old_price: type: integer example: 0 weight: type: number example: 0.15 quantity: type: string example: null nullable: true check_quantity: type: integer example: 0 sku: type: string example: AMST-WHITE-S shipping_rules: type: array example: - product_id: 101 variant_key: null shipping_method: standard location_code: US shipping_cost: 4.99 extra_cost: 2 - product_id: 101 variant_key: null shipping_method: standard location_code: '*' shipping_cost: 8.99 extra_cost: 3 items: type: object properties: product_id: type: integer example: 101 variant_key: type: string example: null nullable: true shipping_method: type: string example: standard location_code: type: string example: US shipping_cost: type: number example: 4.99 extra_cost: type: integer example: 2 description: type: string example: 'Classic fit, 100% cotton.' market_location: type: string example: null nullable: true colors: type: array example: - name: white hex_code: '#ffffff' - name: black hex_code: '#000000' items: type: object properties: name: type: string example: white hex_code: type: string example: '#ffffff' print_spaces: type: array example: - name: front width: 4200 height: 4800 - name: back width: 4200 height: 4800 items: type: object properties: name: type: string example: front width: type: integer example: 4200 height: type: integer example: 4800 attributes: type: string example: null nullable: true options: type: object properties: color: type: array example: - white - black items: type: string size: type: array example: - s - m - l - xl - 2xl items: type: string size_guides: type: array example: [] shipping_times: type: object properties: standard: type: object properties: US: type: object properties: min: type: integer example: 3 max: type: integer example: 8 '*': type: object properties: min: type: integer example: 7 max: type: integer example: 15 express: type: object properties: US: type: object properties: min: type: integer example: 2 max: type: integer example: 4 '*': type: object properties: min: type: integer example: 5 max: type: integer example: 9 processing_time: type: integer example: 2 401: description: 'Invalid or expired API key' content: application/json: schema: type: object example: success: false error: api_key_invalid properties: success: type: boolean example: false error: type: string example: api_key_invalid 404: description: 'Product template not found' content: application/json: schema: type: object example: success: false message: 'Product template not found' data: null properties: success: type: boolean example: false message: type: string example: 'Product template not found' data: type: string example: null nullable: true tags: - Catalog /seller-api/me: get: summary: 'Get current user info' operationId: getCurrentUserInfo description: "Retrieve the details of the authenticated user. The tags below document GET /seller-api/me for Scribe.\nThe account is under `user` (not `data`) and carries more settings fields than the example shows;\n`balance` is what fulfillment orders are charged from." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true user: id: 1234 name: 'John Doe' email: john@example.com status: active role: seller balance: 152.4 hold_amount: 0 currency: USD timezone: America/New_York language: en market_location: '*' price_tag: default pricing_mode: adjust_price auto_fulfill: 1 first_order_at: '2026-03-02 08:15:00' last_order_at: '2026-10-20 17:42:10' properties: success: type: boolean example: true user: type: object properties: id: type: integer example: 1234 name: type: string example: 'John Doe' email: type: string example: john@example.com status: type: string example: active role: type: string example: seller balance: type: number example: 152.4 hold_amount: type: integer example: 0 currency: type: string example: USD timezone: type: string example: America/New_York language: type: string example: en market_location: type: string example: '*' price_tag: type: string example: default pricing_mode: type: string example: adjust_price auto_fulfill: type: integer example: 1 first_order_at: type: string example: '2026-03-02 08:15:00' last_order_at: type: string example: '2026-10-20 17:42:10' 401: description: 'Invalid or expired API key' content: application/json: schema: type: object example: success: false error: api_key_invalid properties: success: type: boolean example: false error: type: string example: api_key_invalid tags: - Me