# API reference > Every endpoint of the REST API with parameters, request and response fields, error codes and examples — generated from the OpenAPI document. Source: https://swaglists.com/docs/api-reference Base URL: `https://swaglists.com/api/v1` · Authentication: `Authorization: Bearer sk_test_…` (test) or `sk_live_…` (live) · Version `2026-10-01` · OpenAPI 3.1 document: [https://swaglists.com/api/v1/openapi.json](https://swaglists.com/api/v1/openapi.json) · Interactive version: [https://swaglists.com/docs/api-reference](https://swaglists.com/docs/api-reference). Conventions: JSON request and response bodies with snake_case fields (unknown request fields are rejected); amounts in integer cents with a lowercase `currency`; ISO-8601 UTC timestamps; cursor pagination (`limit`, `starting_after`, `ending_before`); send an `Idempotency-Key` header on every `POST`, `PATCH` and `DELETE`; errors as `{ "error": { "type", "code", "message", "param", "doc_url", "request_id" } }` ([error codes](https://swaglists.com/docs/errors.md)). Every response has `Request-Id` and `Api-Version` headers; authenticated responses carry [rate limit](https://swaglists.com/docs/rate-limits.md) headers. ## Endpoints | Method | Path | Summary | Scope | | --- | --- | --- | --- | | GET | `/account` | [Retrieve your account](#retrieve-account) | `account:read` | | GET | `/catalog/categories` | [List catalog categories](#list-catalog-categories) | `catalog:read` | | GET | `/catalog/products` | [List catalog products](#list-catalog-products) | `catalog:read` | | GET | `/catalog/products/{id_or_slug}` | [Retrieve a catalog product](#retrieve-catalog-product) | `catalog:read` | | GET | `/files` | [List files](#list-files) | `files:read` | | POST | `/files` | [Upload a file](#create-file) | `files:write` | | GET | `/files/{id}` | [Retrieve a file](#retrieve-file) | `files:read` | | DELETE | `/files/{id}` | [Delete a file](#delete-file) | `files:write` | | GET | `/products` | [List products](#list-products) | `products:read` | | POST | `/products` | [Create a product](#create-product) | `products:write` | | GET | `/products/{id}` | [Retrieve a product](#retrieve-product) | `products:read` | | PATCH | `/products/{id}` | [Update a product](#update-product) | `products:write` | | DELETE | `/products/{id}` | [Archive a product](#delete-product) | `products:write` | | GET | `/products/by_sku/{sku}` | [Find a product variant by SKU](#retrieve-product-variant-by-sku) | `products:read` | | GET | `/products/{id}/variants` | [List product variants](#list-product-variants) | `products:read` | | POST | `/products/{id}/variants` | [Add product variants](#add-product-variants) | `products:write` | | PATCH | `/products/{id}/variants/{variant_id}` | [Update a product variant](#update-product-variant) | `products:write` | | GET | `/product_variants/{id}` | [Retrieve a product variant](#retrieve-product-variant) | `products:read` | | POST | `/shipping/rates` | [Get shipping rates](#list-shipping-rates) | `orders:read` | | POST | `/orders/estimate` | [Estimate an order](#estimate-order) | `orders:read` | | GET | `/orders` | [List orders](#list-orders) | `orders:read` | | POST | `/orders` | [Create an order](#create-order) | `orders:write` | | GET | `/orders/{id}` | [Retrieve an order](#retrieve-order) | `orders:read` | | PATCH | `/orders/{id}` | [Update a draft order](#update-order) | `orders:write` | | POST | `/orders/{id}/confirm` | [Confirm a draft, or release an order waiting for credits](#confirm-order) | `orders:write` | | POST | `/orders/{id}/cancel` | [Cancel an order](#cancel-order) | `orders:write` | | GET | `/orders/{id}/events` | [List order events](#list-order-events) | `orders:read` | | GET | `/wallet` | [Retrieve the wallet](#retrieve-wallet) | `wallet:read` | | GET | `/wallet/transactions` | [List wallet transactions](#list-wallet-transactions) | `wallet:read` | | GET | `/topups` | [List top-ups](#list-topups) | `wallet:read` | | GET | `/topups/{id}` | [Retrieve a top-up](#retrieve-topup) | `wallet:read` | | GET | `/webhook_endpoints` | [List webhook endpoints](#list-webhook-endpoints) | `webhooks:read` | | POST | `/webhook_endpoints` | [Create a webhook endpoint](#create-webhook-endpoint) | `webhooks:write` | | GET | `/webhook_endpoints/{id}` | [Retrieve a webhook endpoint](#retrieve-webhook-endpoint) | `webhooks:read` | | PATCH | `/webhook_endpoints/{id}` | [Update a webhook endpoint](#update-webhook-endpoint) | `webhooks:write` | | DELETE | `/webhook_endpoints/{id}` | [Delete a webhook endpoint](#delete-webhook-endpoint) | `webhooks:write` | | POST | `/webhook_endpoints/{id}/rotate_secret` | [Rotate the signing secret](#rotate-webhook-endpoint-secret) | `webhooks:write` | | POST | `/webhook_endpoints/{id}/test` | [Send a test event](#test-webhook-endpoint) | `webhooks:write` | | GET | `/events` | [List events](#list-events) | `webhooks:read` | | GET | `/events/{id}` | [Retrieve an event](#retrieve-event) | `webhooks:read` | | POST | `/test/wallet/fund` | [Add test credits](#fund-test-wallet) | `*` | | POST | `/test/orders/{id}/advance` | [Advance a test order](#advance-test-order) | `orders:write` | ## Account Your account and the mode (live/test) of the API key. ### Retrieve your account `GET /account` Returns the account the API key belongs to, the key's mode (live/test) and a summary of the wallet of that mode. Requires scope `account:read`. **Scope:** `account:read` **Returns** `200` — The account. [Account](https://swaglists.com/docs/objects.md#account) | Field | Type | Description | | --- | --- | --- | | `object` | "account" | Type of the object: always `account`. | | `id` | string | Unique identifier (starts with `org_`). | | `name` | string | Your account (organization) name. | | `brand_name` | string \| null | Brand printed on packing slips and shown on the tracking page. | | `support_email` | string \| null | Support email shown to your customers (packing slips, tracking page, shipment emails). | | `website` | string \| null | Your website. | | `country` | string \| null | Country of your business (ISO 3166-1 alpha-2). | | `mode` | string | Mode of the API key used for this request. One of: `live`, `test`. | | `livemode` | boolean | `true` in live mode, `false` in test mode. | | `live_mode_enabled` | boolean | Whether live mode is enabled for the account (live keys work and live orders are produced). | | `settings` | object | Order settings that change how the API behaves (Settings → Orders in the dashboard). | | `wallet` | [Wallet](https://swaglists.com/docs/objects.md#wallet) | Wallet of the key's mode. | | `created_at` | string | When the object was created (ISO-8601, UTC). | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl https://swaglists.com/api/v1/account \ -H "Authorization: Bearer $API_KEY" ``` **Example response** ```json { "object": "account", "id": "org_01k8x3q8m4h2c9t6v5r7w1y0za", "name": "Company A", "brand_name": "Company A Apparel", "support_email": "help@company-a.example", "website": "https://company-a.example", "country": "US", "mode": "live", "livemode": true, "live_mode_enabled": true, "settings": { "auto_confirm_orders": true, "insufficient_funds_behavior": "hold" }, "wallet": { "object": "wallet", "mode": "live", "livemode": true, "currency": "usd", "available": 482550, "held": 12480, "total": 495030, "low_balance_threshold": 10000 }, "created_at": "2026-10-21T14:32:05.000Z" } ``` ## Catalog Products you can customize and sell, with your wholesale prices, print areas and mockup templates. ### List catalog categories `GET /catalog/categories` All categories (with sub-categories via `parent_id`) and the number of active products in each. Requires scope `catalog:read`. **Scope:** `catalog:read` **Returns** `200` — Categories. [CatalogCategoryList](https://swaglists.com/docs/objects.md#list) | Field | Type | Description | | --- | --- | --- | | `object` | "list" | Always `list`. | | `data` | array of [CatalogCategory](https://swaglists.com/docs/objects.md#catalog_category) | The objects of this page. | | `has_more` | boolean | Whether more items exist beyond this page (in the paging direction). | | `url` | string | Path of this list endpoint. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl https://swaglists.com/api/v1/catalog/categories \ -H "Authorization: Bearer $API_KEY" ``` **Example response** ```json { "object": "list", "data": [ { "object": "catalog_category", "id": "cat_01k8w0q1w2e3r4t5y6u7i8o9p0", "slug": "t-shirts", "name": "T-Shirts", "parent_id": null, "description": "Classic and premium tees.", "image_url": null, "sort_order": 0, "product_count": 12, "created_at": "2026-10-21T14:32:05.000Z", "updated_at": "2026-10-21T14:32:05.000Z" } ], "has_more": false, "url": "/api/v1/catalog/categories" } ``` ### List catalog products `GET /catalog/products` Products you can customize and sell, featured first. Every variant carries your wholesale `price` (your price list applied, printed on the first placement); `price_from` is the lowest variant price. Requires scope `catalog:read`. **Scope:** `catalog:read` **Query parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `limit` | integer | no | Number of objects to return, 1–100 (default 20). Range 1–100. | | `starting_after` | string | no | Cursor for the next page: the id of the last object of the previous page. 1–255 characters. | | `ending_before` | string | no | Cursor for the previous page: the id of the first object of the current page. 1–255 characters. | | `q` | string | no | Search title, subtitle, brand and tags. 1–200 characters. | | `category` | string | no | Category slug or id (includes sub-categories). 1–100 characters. | | `technique` | string | no | Print technique, e.g. dtg, embroidery. 1–40 characters. | | `featured` | string | no | Only featured (true) or non-featured (false) products. One of: `true`, `false`. | **Returns** `200` — A page of catalog products. [CatalogProductList](https://swaglists.com/docs/objects.md#list) | Field | Type | Description | | --- | --- | --- | | `object` | "list" | Always `list`. | | `data` | array of [CatalogProduct](https://swaglists.com/docs/objects.md#catalog_product) | The objects of this page. | | `has_more` | boolean | Whether more items exist beyond this page (in the paging direction). | | `url` | string | Path of this list endpoint. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl "https://swaglists.com/api/v1/catalog/products?limit=3" \ -H "Authorization: Bearer $API_KEY" ``` **Example response** ```json { "object": "list", "data": [ { "object": "catalog_product", "id": "cp_01k8w1a2s3d4f5g6h7j8k9m0n1", "slug": "classic-unisex-tee", "title": "Classic Unisex Tee", "subtitle": "100% combed cotton", "description": "A soft, everyday tee.", "category": { "object": "catalog_category", "id": "cat_01k8w0q1w2e3r4t5y6u7i8o9p0", "slug": "t-shirts", "name": "T-Shirts", "parent_id": null }, "tags": [ "bestseller" ], "images": [ { "url": "https://swaglists.com/f/file_01k8w1c2v4b6n8m0q2w4e6r8t1/1767225600.9b1c/tee.png", "alt": "Classic tee" } ], "features": [ "Pre-shrunk", "Side-seamed" ], "techniques": [ "dtg" ], "material": "100% cotton", "care_instructions": "Machine wash cold, inside out.", "size_guide": null, "options": [ { "name": "Color", "values": [ { "value": "Black", "label": "Black", "hex": "#111111" } ] }, { "name": "Size", "values": [ { "value": "M", "label": "M", "hex": null } ] } ], "production_days": { "min": 2, "max": 4 }, "featured": true, "placements": [ { "object": "placement", "key": "front", "label": "Front", "description": "Front print area", "technique": "dtg", "aspect_ratio": 0.833333, "width_in": 15, "height_in": 18, "recommended_width_px": 4500, "recommended_height_px": 5400, "min_dpi": 150, "required": false, "file_requirements": { "formats": [ "png", "jpeg", "webp", "tiff", "svg" ], "max_file_size_bytes": 104857600, "max_dimension_px": 30000, "recommended_width_px": 4500, "recommended_height_px": 5400, "recommended_dpi": 300, "min_dpi": 150, "color_profile": "sRGB", "transparent_background": true } } ], "variants": [ { "object": "catalog_variant", "id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "catalog_product_id": "cp_01k8w1a2s3d4f5g6h7j8k9m0n1", "sku": "TEE-CLASSIC-BLK-M", "title": "Black / M", "options": { "Color": "Black", "Size": "M" }, "color": "Black", "color_hex": "#111111", "size": "M", "image_url": null, "available": true, "price": 1299, "currency": "usd" } ], "mockup_templates": [ { "object": "mockup_template", "id": "cmt_01k8w1b3c5v7b9n1m3a5s7d9f1", "placement_key": "front", "color": "Black", "label": "Front", "image_url": "https://swaglists.com/f/file_01k8w1c2v4b6n8m0q2w4e6r8t0/1767225600.3f9a/tee-front.png", "image_width_px": 1600, "image_height_px": 2000, "print_area": { "x": 0.3, "y": 0.25, "width": 0.4, "height": 0.48 }, "blend_mode": "multiply", "is_primary": true } ], "price_range": { "min": 1299, "max": 1599, "currency": "usd" }, "price_from": 1299, "currency": "usd", "created_at": "2026-10-21T14:32:05.000Z", "updated_at": "2026-10-21T14:32:05.000Z" } ], "has_more": false, "url": "/api/v1/catalog/products" } ``` ### Retrieve a catalog product `GET /catalog/products/{id_or_slug}` Full product: options, variants with your price and availability, placements (print areas) with recommended pixel sizes and file requirements, and mockup templates. Requires scope `catalog:read`. **Scope:** `catalog:read` **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `id_or_slug` | string | yes | Catalog product id or slug. 1–300 characters. | **Returns** `200` — The catalog product. [CatalogProduct](https://swaglists.com/docs/objects.md#catalog_product) | Field | Type | Description | | --- | --- | --- | | `object` | "catalog_product" | Type of the object: always `catalog_product`. | | `id` | string | Unique identifier (starts with `cp_`). | | `slug` | string | URL-friendly identifier; can be used instead of the id in `GET /catalog/products/{id_or_slug}`. | | `title` | string | Product title. | | `subtitle` | string \| null | Short tagline. | | `description` | string \| null | Markdown. | | `category` | [CatalogCategoryRef](https://swaglists.com/docs/objects.md#catalog_category) | Category of the product. | | `tags` | array of string | Tags (e.g. `bestseller`). | | `images` | array of object | Product photos. | | `features` | array of string | Selling points. | | `techniques` | array of string | Print techniques used (e.g. `dtg`, `embroidery`, `sublimation`, `digital`). | | `material` | string \| null | Material. | | `care_instructions` | string \| null | Care instructions. | | `size_guide` | map of any \| null | Size chart data, when available. | | `options` | array of object | Option names and values (e.g. Color, Size) in display order. | | `production_days` | object | Business days to produce before shipping. | | `featured` | boolean | Featured products are listed first. | | `placements` | array of [Placement](https://swaglists.com/docs/objects.md#placement) | Print areas you can put artwork on. | | `variants` | array of [CatalogVariant](https://swaglists.com/docs/objects.md#catalog_variant) | Active variants with your wholesale price and availability. | | `mockup_templates` | array of [MockupTemplate](https://swaglists.com/docs/objects.md#mockup_template) | Templates to render previews. | | `price_range` | object \| null | Lowest and highest wholesale variant price (first placement). | | `price_from` | integer \| null | Lowest wholesale price over active variants (cents). | | `currency` | string | Three-letter currency code, lowercase (`usd`). | | `created_at` | string \| null | When the object was created (ISO-8601, UTC). | | `updated_at` | string \| null | When the object was last changed (ISO-8601, UTC). | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl https://swaglists.com/api/v1/catalog/products/cp_01k8w1a2s3d4f5g6h7j8k9m0n1 \ -H "Authorization: Bearer $API_KEY" ``` **Example response** ```json { "object": "catalog_product", "id": "cp_01k8w1a2s3d4f5g6h7j8k9m0n1", "slug": "classic-unisex-tee", "title": "Classic Unisex Tee", "subtitle": "100% combed cotton", "description": "A soft, everyday tee.", "category": { "object": "catalog_category", "id": "cat_01k8w0q1w2e3r4t5y6u7i8o9p0", "slug": "t-shirts", "name": "T-Shirts", "parent_id": null }, "tags": [ "bestseller" ], "images": [ { "url": "https://swaglists.com/f/file_01k8w1c2v4b6n8m0q2w4e6r8t1/1767225600.9b1c/tee.png", "alt": "Classic tee" } ], "features": [ "Pre-shrunk", "Side-seamed" ], "techniques": [ "dtg" ], "material": "100% cotton", "care_instructions": "Machine wash cold, inside out.", "size_guide": null, "options": [ { "name": "Color", "values": [ { "value": "Black", "label": "Black", "hex": "#111111" } ] }, { "name": "Size", "values": [ { "value": "M", "label": "M", "hex": null } ] } ], "production_days": { "min": 2, "max": 4 }, "featured": true, "placements": [ { "object": "placement", "key": "front", "label": "Front", "description": "Front print area", "technique": "dtg", "aspect_ratio": 0.833333, "width_in": 15, "height_in": 18, "recommended_width_px": 4500, "recommended_height_px": 5400, "min_dpi": 150, "required": false, "file_requirements": { "formats": [ "png", "jpeg", "webp", "tiff", "svg" ], "max_file_size_bytes": 104857600, "max_dimension_px": 30000, "recommended_width_px": 4500, "recommended_height_px": 5400, "recommended_dpi": 300, "min_dpi": 150, "color_profile": "sRGB", "transparent_background": true } } ], "variants": [ { "object": "catalog_variant", "id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "catalog_product_id": "cp_01k8w1a2s3d4f5g6h7j8k9m0n1", "sku": "TEE-CLASSIC-BLK-M", "title": "Black / M", "options": { "Color": "Black", "Size": "M" }, "color": "Black", "color_hex": "#111111", "size": "M", "image_url": null, "available": true, "price": 1299, "currency": "usd" } ], "mockup_templates": [ { "object": "mockup_template", "id": "cmt_01k8w1b3c5v7b9n1m3a5s7d9f1", "placement_key": "front", "color": "Black", "label": "Front", "image_url": "https://swaglists.com/f/file_01k8w1c2v4b6n8m0q2w4e6r8t0/1767225600.3f9a/tee-front.png", "image_width_px": 1600, "image_height_px": 2000, "print_area": { "x": 0.3, "y": 0.25, "width": 0.4, "height": 0.48 }, "blend_mode": "multiply", "is_primary": true } ], "price_range": { "min": 1299, "max": 1599, "currency": "usd" }, "price_from": 1299, "currency": "usd", "created_at": "2026-10-21T14:32:05.000Z", "updated_at": "2026-10-21T14:32:05.000Z" } ``` ## Files Upload artwork (multipart or by URL) to use in designs. ### List files `GET /files` Your uploaded files and generated mockups, newest first. Requires scope `files:read`. **Scope:** `files:read` **Query parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `limit` | integer | no | Number of objects to return, 1–100 (default 20). Range 1–100. | | `starting_after` | string | no | Cursor for the next page: the id of the last object of the previous page. 1–255 characters. | | `ending_before` | string | no | Cursor for the previous page: the id of the first object of the current page. 1–255 characters. | | `purpose` | string | no | Filter by purpose. One of: `artwork`, `logo`, `mockup`. | **Returns** `200` — A page of files. [FileList](https://swaglists.com/docs/objects.md#list) | Field | Type | Description | | --- | --- | --- | | `object` | "list" | Always `list`. | | `data` | array of [File](https://swaglists.com/docs/objects.md#file) | The objects of this page. | | `has_more` | boolean | Whether more items exist beyond this page (in the paging direction). | | `url` | string | Path of this list endpoint. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl "https://swaglists.com/api/v1/files?limit=3" \ -H "Authorization: Bearer $API_KEY" ``` **Example response** ```json { "object": "list", "data": [ { "object": "file", "id": "file_01k8x3y1q3w5e7r9t1y3u5i7o9", "filename": "logo-front.png", "mime_type": "image/png", "size_bytes": 482113, "width_px": 4500, "height_px": 5400, "dpi": 300, "status": "ready", "purpose": "artwork", "url": "https://swaglists.com/f/file_01k8x3y1q3w5e7r9t1y3u5i7o9/1767225600.ab12cd/logo-front.png", "created_at": "2026-10-21T14:32:05.000Z" } ], "has_more": false, "url": "/api/v1/files" } ``` ### Upload a file `POST /files` Upload artwork either as `multipart/form-data` (field `file`, optional `purpose`) or as JSON `{"url": "https://…"}` — we download the image once (public http(s) URLs only, size and time limited). Images are validated (PNG, JPEG, WebP, TIFF, GIF, SVG; SVGs are sanitized and rasterized). Requires scope `files:write`. **Scope:** `files:write` · **Idempotency:** send an `Idempotency-Key` header **Request body** (`application/json`) — CreateFileFromUrlRequest Either a JSON body with `url`, or a multipart upload with `file`. | Field | Type | Required | Description | | --- | --- | --- | --- | | `url` | string | yes | Public http(s) URL of the image; we download it once. Max 2048 characters. Must be an http(s) URL. | | `purpose` | string | no | Defaults to artwork. One of: `artwork`, `logo`. | | `filename` | string | no | 1–200 characters. | **Request body** (`multipart/form-data`) — UploadFileRequest Either a JSON body with `url`, or a multipart upload with `file`. | Field | Type | Required | Description | | --- | --- | --- | --- | | `file` | file | yes | The image (PNG, JPEG, WebP, TIFF, GIF or SVG). | | `purpose` | string | no | Defaults to artwork. One of: `artwork`, `logo`. | **Returns** `201` — The stored file. [File](https://swaglists.com/docs/objects.md#file) | Field | Type | Description | | --- | --- | --- | | `object` | "file" | Type of the object: always `file`. | | `id` | string | Unique identifier (starts with `file_`). | | `filename` | string | File name. | | `mime_type` | string | Media type (images are stored as PNG, JPEG or WebP). | | `size_bytes` | integer | Size in bytes. | | `width_px` | integer \| null | Width in pixels. | | `height_px` | integer \| null | Height in pixels. | | `dpi` | number \| null | Resolution stored in the image metadata, when present (informational — print resolution depends on the placed size). | | `status` | string | ready to use, still processing (pending), failed processing, or deleted. One of: `pending`, `ready`, `failed`, `deleted`. | | `purpose` | string | artwork or logo (your uploads), or mockup (generated product mockups). One of: `artwork`, `logo`, `mockup`. | | `url` | string \| null | Signed download URL, valid for about 24 hours. | | `created_at` | string | When the object was created (ISO-8601, UTC). | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid), [`file_invalid`](https://swaglists.com/docs/errors.md#file_invalid), [`file_too_large`](https://swaglists.com/docs/errors.md#file_too_large), [`file_unsafe`](https://swaglists.com/docs/errors.md#file_unsafe), [`file_unsupported_type`](https://swaglists.com/docs/errors.md#file_unsupported_type), [`download_failed`](https://swaglists.com/docs/errors.md#download_failed), [`download_not_an_image`](https://swaglists.com/docs/errors.md#download_not_an_image), [`download_timeout`](https://swaglists.com/docs/errors.md#download_timeout) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 413 | [`request_too_large`](https://swaglists.com/docs/errors.md#request_too_large) | | 415 | [`unsupported_media_type`](https://swaglists.com/docs/errors.md#unsupported_media_type) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl -X POST https://swaglists.com/api/v1/files \ -H "Authorization: Bearer $API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -F "file=@artwork.png" \ -F "purpose=artwork" ``` **Example response** ```json { "object": "file", "id": "file_01k8x3y1q3w5e7r9t1y3u5i7o9", "filename": "logo-front.png", "mime_type": "image/png", "size_bytes": 482113, "width_px": 4500, "height_px": 5400, "dpi": 300, "status": "ready", "purpose": "artwork", "url": "https://swaglists.com/f/file_01k8x3y1q3w5e7r9t1y3u5i7o9/1767225600.ab12cd/logo-front.png", "created_at": "2026-10-21T14:32:05.000Z" } ``` ### Retrieve a file `GET /files/{id}` Returns the file with a fresh signed download URL. Requires scope `files:read`. **Scope:** `files:read` **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | File id. 1–300 characters. | **Returns** `200` — The file. [File](https://swaglists.com/docs/objects.md#file) | Field | Type | Description | | --- | --- | --- | | `object` | "file" | Type of the object: always `file`. | | `id` | string | Unique identifier (starts with `file_`). | | `filename` | string | File name. | | `mime_type` | string | Media type (images are stored as PNG, JPEG or WebP). | | `size_bytes` | integer | Size in bytes. | | `width_px` | integer \| null | Width in pixels. | | `height_px` | integer \| null | Height in pixels. | | `dpi` | number \| null | Resolution stored in the image metadata, when present (informational — print resolution depends on the placed size). | | `status` | string | ready to use, still processing (pending), failed processing, or deleted. One of: `pending`, `ready`, `failed`, `deleted`. | | `purpose` | string | artwork or logo (your uploads), or mockup (generated product mockups). One of: `artwork`, `logo`, `mockup`. | | `url` | string \| null | Signed download URL, valid for about 24 hours. | | `created_at` | string | When the object was created (ISO-8601, UTC). | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl https://swaglists.com/api/v1/files/file_01k8x3y1q3w5e7r9t1y3u5i7o9 \ -H "Authorization: Bearer $API_KEY" ``` **Example response** ```json { "object": "file", "id": "file_01k8x3y1q3w5e7r9t1y3u5i7o9", "filename": "logo-front.png", "mime_type": "image/png", "size_bytes": 482113, "width_px": 4500, "height_px": 5400, "dpi": 300, "status": "ready", "purpose": "artwork", "url": "https://swaglists.com/f/file_01k8x3y1q3w5e7r9t1y3u5i7o9/1767225600.ab12cd/logo-front.png", "created_at": "2026-10-21T14:32:05.000Z" } ``` ### Delete a file `DELETE /files/{id}` Deletes an uploaded file. Files used by a non-archived product cannot be deleted (409 file_in_use). Requires scope `files:write`. **Scope:** `files:write` · **Idempotency:** send an `Idempotency-Key` header **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | File id. 1–300 characters. | **Returns** `200` — The deleted file (status deleted). [File](https://swaglists.com/docs/objects.md#file) | Field | Type | Description | | --- | --- | --- | | `object` | "file" | Type of the object: always `file`. | | `id` | string | Unique identifier (starts with `file_`). | | `filename` | string | File name. | | `mime_type` | string | Media type (images are stored as PNG, JPEG or WebP). | | `size_bytes` | integer | Size in bytes. | | `width_px` | integer \| null | Width in pixels. | | `height_px` | integer \| null | Height in pixels. | | `dpi` | number \| null | Resolution stored in the image metadata, when present (informational — print resolution depends on the placed size). | | `status` | string | ready to use, still processing (pending), failed processing, or deleted. One of: `pending`, `ready`, `failed`, `deleted`. | | `purpose` | string | artwork or logo (your uploads), or mockup (generated product mockups). One of: `artwork`, `logo`, `mockup`. | | `url` | string \| null | Signed download URL, valid for about 24 hours. | | `created_at` | string | When the object was created (ISO-8601, UTC). | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 409 | [`idempotency_key_reused`](https://swaglists.com/docs/errors.md#idempotency_key_reused), [`idempotency_in_progress`](https://swaglists.com/docs/errors.md#idempotency_in_progress), [`file_in_use`](https://swaglists.com/docs/errors.md#file_in_use) | | 413 | [`request_too_large`](https://swaglists.com/docs/errors.md#request_too_large) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl -X DELETE https://swaglists.com/api/v1/files/file_01k8x3y1q3w5e7r9t1y3u5i7o9 \ -H "Authorization: Bearer $API_KEY" \ -H "Idempotency-Key: $(uuidgen)" ``` **Example response** ```json { "object": "file", "id": "file_01k8x3y1q3w5e7r9t1y3u5i7o9", "filename": "logo-front.png", "mime_type": "image/png", "size_bytes": 482113, "width_px": 4500, "height_px": 5400, "dpi": 300, "status": "ready", "purpose": "artwork", "url": "https://swaglists.com/f/file_01k8x3y1q3w5e7r9t1y3u5i7o9/1767225600.ab12cd/logo-front.png", "created_at": "2026-10-21T14:32:05.000Z" } ``` ## Products Your products: catalog product + designs + variants with your own SKUs. ### List products `GET /products` Your products, newest first. Archived products are excluded unless `status=archived` or `status=all`. Requires scope `products:read`. **Scope:** `products:read` **Query parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `limit` | integer | no | Number of objects to return, 1–100 (default 20). Range 1–100. | | `starting_after` | string | no | Cursor for the next page: the id of the last object of the previous page. 1–255 characters. | | `ending_before` | string | no | Cursor for the previous page: the id of the first object of the current page. 1–255 characters. | | `status` | string | no | One of: `draft`, `active`, `archived`, `all`. | | `q` | string | no | Title contains, or exact external_id / SKU / id. 1–200 characters. | | `catalog_product_id` | string | no | 1–100 characters. | **Returns** `200` — A page of products. [ProductList](https://swaglists.com/docs/objects.md#list) | Field | Type | Description | | --- | --- | --- | | `object` | "list" | Always `list`. | | `data` | array of [Product](https://swaglists.com/docs/objects.md#product) | The objects of this page. | | `has_more` | boolean | Whether more items exist beyond this page (in the paging direction). | | `url` | string | Path of this list endpoint. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl "https://swaglists.com/api/v1/products?limit=3" \ -H "Authorization: Bearer $API_KEY" ``` **Example response** ```json { "object": "list", "data": [ { "object": "product", "id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "title": "Company A Logo Tee", "description": "Our classic logo on a soft tee.", "status": "active", "catalog_product_id": "cp_01k8w1a2s3d4f5g6h7j8k9m0n1", "external_id": "shopify-product-9921", "tags": [ "logo" ], "metadata": {}, "retail_price": 2900, "currency": "usd", "designs": [ { "placement": "front", "layers": [ { "file_id": "file_01k8x3y1q3w5e7r9t1y3u5i7o9", "transform": { "x": 0.1, "y": 0.05, "width": 0.8, "height": 0.6, "rotation": 0 }, "opacity": 1 } ] } ], "variants": [ { "object": "product_variant", "id": "pvar_01k8x3z7r4f6g8h0j2k4l6z8x0", "product_id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "sku": "CA-TEE-BLK-M", "catalog_variant_id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "title": "Black / M", "options": { "Color": "Black", "Size": "M" }, "retail_price": 2900, "price": 1299, "currency": "usd", "external_id": "shopify-variant-4410", "enabled": true, "available": true } ], "mockups": [ { "url": "https://swaglists.com/f/file_01k8x3y9a1s3d5f7g9h1j3k5l7/1782777600.c0ffee/mockup-front.png", "placement": "front", "color": "Black", "is_primary": true } ], "created_at": "2026-10-21T14:32:05.000Z", "updated_at": "2026-10-21T14:32:05.000Z" } ], "has_more": false, "url": "/api/v1/products" } ``` ### Create a product `POST /products` Creates a product from a catalog product and your designs (one entry per placement; each layer references an uploaded `file_id` or a `url` we download). Variants default to every active catalog variant, each with a generated SKU unless you pass your own. Mockups are rendered in the background (`product.updated` fires when ready). Requires scope `products:write`. **Scope:** `products:write` · **Idempotency:** send an `Idempotency-Key` header **Request body** (`application/json`) — CreateProductRequest | Field | Type | Required | Description | | --- | --- | --- | --- | | `catalog_product_id` | string | yes | 1–100 characters. | | `title` | string \| null | no | 1–200 characters. | | `description` | string \| null | no | Max 20000 characters. | | `designs` | array of DesignInput | yes | 1–20 items. | | `designs[].placement` | string | yes | Placement key from the catalog product (e.g. front, back). 1–64 characters. | | `designs[].layers` | array of DesignLayerInput | yes | 1–20 items. | | `designs[].layers[].file_id` | string | no | Id of an uploaded artwork file. 1–100 characters. | | `designs[].layers[].url` | string | no | Or a public image URL; we download it into a new artwork file. Max 2048 characters. Must be an http(s) URL. | | `designs[].layers[].position` | Position | no | Where the artwork sits inside the placement's print area. Fractions of the print area (0–1; values outside allow intentional bleed). Omit to center the artwork and fit it inside the area. | | `designs[].layers[].position.x` | number | yes | Left edge of the artwork box as a fraction of the print area width. Range -10–10. | | `designs[].layers[].position.y` | number | yes | Top edge of the artwork box as a fraction of the print area height. Range -10–10. | | `designs[].layers[].position.width` | number | yes | Artwork width as a fraction of the print area width. Range >0–10. | | `designs[].layers[].position.height` | number | yes | Artwork height as a fraction of the print area height. Range >0–10. | | `designs[].layers[].position.rotation` | number | no | Clockwise rotation in degrees around the artwork center. Range -3600–3600. Default `0`. | | `designs[].layers[].transform` | Position | no | Alias of `position` (as returned on products and orders). | | `designs[].layers[].transform.x` | number | yes | Left edge of the artwork box as a fraction of the print area width. Range -10–10. | | `designs[].layers[].transform.y` | number | yes | Top edge of the artwork box as a fraction of the print area height. Range -10–10. | | `designs[].layers[].transform.width` | number | yes | Artwork width as a fraction of the print area width. Range >0–10. | | `designs[].layers[].transform.height` | number | yes | Artwork height as a fraction of the print area height. Range >0–10. | | `designs[].layers[].transform.rotation` | number | no | Clockwise rotation in degrees around the artwork center. Range -3600–3600. Default `0`. | | `designs[].layers[].opacity` | number | no | 0–1 (default 1). Range 0–1. | | `variants` | "all" or array of ProductVariantInput | no | "all" (every active catalog variant) or an explicit list. | | `variants[].catalog_variant_id` | string | yes | 1–100 characters. | | `variants[].sku` | string \| null | no | Your SKU; generated when omitted. 1–64 characters. Pattern `^[\x21-\x7E](?:[\x20-\x7E]{0,62}[\x21-\x7E])?$`. | | `variants[].retail_price` | integer \| null | no | Range 0–100000000. | | `variants[].external_id` | string \| null | no | 1–255 characters. | | `retail_price` | integer \| null | no | Default retail price for variants (cents). Range 0–100000000. | | `external_id` | string \| null | no | 1–255 characters. | | `tags` | array of string | no | Up to 50 items. | | `metadata` | map of string | no | Up to 50 key/value pairs (keys ≤ 40 chars, string values ≤ 500 chars) for your own references. Never store sensitive data here. | | `status` | string | no | Default active. One of: `draft`, `active`. | **Returns** `201` — The created product (with `warnings`). [Product](https://swaglists.com/docs/objects.md#product) | Field | Type | Description | | --- | --- | --- | | `object` | "product" | Type of the object: always `product`. | | `id` | string | Unique identifier (starts with `prod_`). | | `title` | string | Product title. | | `description` | string \| null | Product description (plain text or markdown). | | `status` | string | draft, active, or archived (archived products can no longer be ordered). One of: `draft`, `active`, `archived`. | | `catalog_product_id` | string | Catalog product this product is made from. | | `external_id` | string \| null | Your id for the product (e.g. your store's product id). | | `tags` | array of string | Your tags. | | `metadata` | map of string | Your key/value pairs (string values). | | `retail_price` | integer \| null | Default retail price of the variants (informational, used in exports), in cents. | | `currency` | "usd" | Three-letter currency code, lowercase (`usd`). | | `designs` | array of [Design](https://swaglists.com/docs/objects.md#design) | Artwork per placement. | | `variants` | array of [ProductVariant](https://swaglists.com/docs/objects.md#product_variant) | Sellable variants with your SKUs. | | `mockups` | array of object | Generated preview images. Rendered in the background; `product.updated` fires when they are ready. | | `warnings` | array of [ProductWarning](https://swaglists.com/docs/objects.md#product_warning) | Only on create/update responses: non-blocking design issues. | | `created_at` | string | When the object was created (ISO-8601, UTC). | | `updated_at` | string | When the object was last changed (ISO-8601, UTC). | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid), [`catalog_product_unavailable`](https://swaglists.com/docs/errors.md#catalog_product_unavailable), [`designs_required`](https://swaglists.com/docs/errors.md#designs_required), [`duplicate_placement`](https://swaglists.com/docs/errors.md#duplicate_placement), [`unknown_placement`](https://swaglists.com/docs/errors.md#unknown_placement), [`placement_required`](https://swaglists.com/docs/errors.md#placement_required), [`file_not_artwork`](https://swaglists.com/docs/errors.md#file_not_artwork), [`file_not_ready`](https://swaglists.com/docs/errors.md#file_not_ready), [`file_not_image`](https://swaglists.com/docs/errors.md#file_not_image), [`design_not_visible`](https://swaglists.com/docs/errors.md#design_not_visible), [`artwork_resolution_too_low`](https://swaglists.com/docs/errors.md#artwork_resolution_too_low), [`no_layers`](https://swaglists.com/docs/errors.md#no_layers), [`too_many_layers`](https://swaglists.com/docs/errors.md#too_many_layers), [`invalid_transform`](https://swaglists.com/docs/errors.md#invalid_transform), [`no_variants`](https://swaglists.com/docs/errors.md#no_variants), [`duplicate_variant`](https://swaglists.com/docs/errors.md#duplicate_variant), [`duplicate_sku`](https://swaglists.com/docs/errors.md#duplicate_sku), [`variant_unavailable`](https://swaglists.com/docs/errors.md#variant_unavailable), [`download_failed`](https://swaglists.com/docs/errors.md#download_failed) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 409 | [`idempotency_key_reused`](https://swaglists.com/docs/errors.md#idempotency_key_reused), [`idempotency_in_progress`](https://swaglists.com/docs/errors.md#idempotency_in_progress), [`sku_taken`](https://swaglists.com/docs/errors.md#sku_taken), [`external_id_taken`](https://swaglists.com/docs/errors.md#external_id_taken) | | 413 | [`request_too_large`](https://swaglists.com/docs/errors.md#request_too_large) | | 415 | [`unsupported_media_type`](https://swaglists.com/docs/errors.md#unsupported_media_type) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl -X POST https://swaglists.com/api/v1/products \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "catalog_product_id": "cp_01k8w1a2s3d4f5g6h7j8k9m0n1", "title": "Company A Logo Tee", "designs": [ { "placement": "front", "layers": [ { "file_id": "file_01k8x3y1q3w5e7r9t1y3u5i7o9", "position": { "x": 0.1, "y": 0.05, "width": 0.8, "height": 0.6, "rotation": 0 } } ] } ], "variants": "all", "retail_price": 2900, "external_id": "shopify-product-9921" }' ``` **Example response** ```json { "object": "product", "id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "title": "Company A Logo Tee", "description": "Our classic logo on a soft tee.", "status": "active", "catalog_product_id": "cp_01k8w1a2s3d4f5g6h7j8k9m0n1", "external_id": "shopify-product-9921", "tags": [ "logo" ], "metadata": {}, "retail_price": 2900, "currency": "usd", "designs": [ { "placement": "front", "layers": [ { "file_id": "file_01k8x3y1q3w5e7r9t1y3u5i7o9", "transform": { "x": 0.1, "y": 0.05, "width": 0.8, "height": 0.6, "rotation": 0 }, "opacity": 1 } ] } ], "variants": [ { "object": "product_variant", "id": "pvar_01k8x3z7r4f6g8h0j2k4l6z8x0", "product_id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "sku": "CA-TEE-BLK-M", "catalog_variant_id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "title": "Black / M", "options": { "Color": "Black", "Size": "M" }, "retail_price": 2900, "price": 1299, "currency": "usd", "external_id": "shopify-variant-4410", "enabled": true, "available": true } ], "mockups": [ { "url": "https://swaglists.com/f/file_01k8x3y9a1s3d5f7g9h1j3k5l7/1782777600.c0ffee/mockup-front.png", "placement": "front", "color": "Black", "is_primary": true } ], "created_at": "2026-10-21T14:32:05.000Z", "updated_at": "2026-10-21T14:32:05.000Z" } ``` ### Retrieve a product `GET /products/{id}` Requires scope `products:read`. **Scope:** `products:read` **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | Product id. 1–300 characters. | **Returns** `200` — The product. [Product](https://swaglists.com/docs/objects.md#product) | Field | Type | Description | | --- | --- | --- | | `object` | "product" | Type of the object: always `product`. | | `id` | string | Unique identifier (starts with `prod_`). | | `title` | string | Product title. | | `description` | string \| null | Product description (plain text or markdown). | | `status` | string | draft, active, or archived (archived products can no longer be ordered). One of: `draft`, `active`, `archived`. | | `catalog_product_id` | string | Catalog product this product is made from. | | `external_id` | string \| null | Your id for the product (e.g. your store's product id). | | `tags` | array of string | Your tags. | | `metadata` | map of string | Your key/value pairs (string values). | | `retail_price` | integer \| null | Default retail price of the variants (informational, used in exports), in cents. | | `currency` | "usd" | Three-letter currency code, lowercase (`usd`). | | `designs` | array of [Design](https://swaglists.com/docs/objects.md#design) | Artwork per placement. | | `variants` | array of [ProductVariant](https://swaglists.com/docs/objects.md#product_variant) | Sellable variants with your SKUs. | | `mockups` | array of object | Generated preview images. Rendered in the background; `product.updated` fires when they are ready. | | `warnings` | array of [ProductWarning](https://swaglists.com/docs/objects.md#product_warning) | Only on create/update responses: non-blocking design issues. | | `created_at` | string | When the object was created (ISO-8601, UTC). | | `updated_at` | string | When the object was last changed (ISO-8601, UTC). | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl https://swaglists.com/api/v1/products/prod_01k8x3z7r1t3y5u7i9o1p3a5s7 \ -H "Authorization: Bearer $API_KEY" ``` **Example response** ```json { "object": "product", "id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "title": "Company A Logo Tee", "description": "Our classic logo on a soft tee.", "status": "active", "catalog_product_id": "cp_01k8w1a2s3d4f5g6h7j8k9m0n1", "external_id": "shopify-product-9921", "tags": [ "logo" ], "metadata": {}, "retail_price": 2900, "currency": "usd", "designs": [ { "placement": "front", "layers": [ { "file_id": "file_01k8x3y1q3w5e7r9t1y3u5i7o9", "transform": { "x": 0.1, "y": 0.05, "width": 0.8, "height": 0.6, "rotation": 0 }, "opacity": 1 } ] } ], "variants": [ { "object": "product_variant", "id": "pvar_01k8x3z7r4f6g8h0j2k4l6z8x0", "product_id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "sku": "CA-TEE-BLK-M", "catalog_variant_id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "title": "Black / M", "options": { "Color": "Black", "Size": "M" }, "retail_price": 2900, "price": 1299, "currency": "usd", "external_id": "shopify-variant-4410", "enabled": true, "available": true } ], "mockups": [ { "url": "https://swaglists.com/f/file_01k8x3y9a1s3d5f7g9h1j3k5l7/1782777600.c0ffee/mockup-front.png", "placement": "front", "color": "Black", "is_primary": true } ], "created_at": "2026-10-21T14:32:05.000Z", "updated_at": "2026-10-21T14:32:05.000Z" } ``` ### Update a product `PATCH /products/{id}` Updates details and/or replaces the designs (`designs`). Omitted fields are left unchanged. Requires scope `products:write`. **Scope:** `products:write` · **Idempotency:** send an `Idempotency-Key` header **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | Product id. 1–300 characters. | **Request body** (`application/json`) — UpdateProductRequest | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | no | 1–200 characters. | | `description` | string \| null | no | Max 20000 characters. | | `status` | string | no | Setting a status restores an archived product. One of: `draft`, `active`. | | `tags` | array of string | no | Up to 50 items. | | `metadata` | map of string | no | Up to 50 key/value pairs (keys ≤ 40 chars, string values ≤ 500 chars) for your own references. Never store sensitive data here. | | `external_id` | string \| null | no | 1–255 characters. | | `retail_price` | integer \| null | no | Range 0–100000000. | | `designs` | array of DesignInput | no | Replaces all designs (mockups are regenerated). 1–20 items. | | `designs[].placement` | string | yes | Placement key from the catalog product (e.g. front, back). 1–64 characters. | | `designs[].layers` | array of DesignLayerInput | yes | 1–20 items. | | `designs[].layers[].file_id` | string | no | Id of an uploaded artwork file. 1–100 characters. | | `designs[].layers[].url` | string | no | Or a public image URL; we download it into a new artwork file. Max 2048 characters. Must be an http(s) URL. | | `designs[].layers[].position` | Position | no | Where the artwork sits inside the placement's print area. Fractions of the print area (0–1; values outside allow intentional bleed). Omit to center the artwork and fit it inside the area. | | `designs[].layers[].position.x` | number | yes | Left edge of the artwork box as a fraction of the print area width. Range -10–10. | | `designs[].layers[].position.y` | number | yes | Top edge of the artwork box as a fraction of the print area height. Range -10–10. | | `designs[].layers[].position.width` | number | yes | Artwork width as a fraction of the print area width. Range >0–10. | | `designs[].layers[].position.height` | number | yes | Artwork height as a fraction of the print area height. Range >0–10. | | `designs[].layers[].position.rotation` | number | no | Clockwise rotation in degrees around the artwork center. Range -3600–3600. Default `0`. | | `designs[].layers[].transform` | Position | no | Alias of `position` (as returned on products and orders). | | `designs[].layers[].transform.x` | number | yes | Left edge of the artwork box as a fraction of the print area width. Range -10–10. | | `designs[].layers[].transform.y` | number | yes | Top edge of the artwork box as a fraction of the print area height. Range -10–10. | | `designs[].layers[].transform.width` | number | yes | Artwork width as a fraction of the print area width. Range >0–10. | | `designs[].layers[].transform.height` | number | yes | Artwork height as a fraction of the print area height. Range >0–10. | | `designs[].layers[].transform.rotation` | number | no | Clockwise rotation in degrees around the artwork center. Range -3600–3600. Default `0`. | | `designs[].layers[].opacity` | number | no | 0–1 (default 1). Range 0–1. | **Returns** `200` — The updated product. [Product](https://swaglists.com/docs/objects.md#product) | Field | Type | Description | | --- | --- | --- | | `object` | "product" | Type of the object: always `product`. | | `id` | string | Unique identifier (starts with `prod_`). | | `title` | string | Product title. | | `description` | string \| null | Product description (plain text or markdown). | | `status` | string | draft, active, or archived (archived products can no longer be ordered). One of: `draft`, `active`, `archived`. | | `catalog_product_id` | string | Catalog product this product is made from. | | `external_id` | string \| null | Your id for the product (e.g. your store's product id). | | `tags` | array of string | Your tags. | | `metadata` | map of string | Your key/value pairs (string values). | | `retail_price` | integer \| null | Default retail price of the variants (informational, used in exports), in cents. | | `currency` | "usd" | Three-letter currency code, lowercase (`usd`). | | `designs` | array of [Design](https://swaglists.com/docs/objects.md#design) | Artwork per placement. | | `variants` | array of [ProductVariant](https://swaglists.com/docs/objects.md#product_variant) | Sellable variants with your SKUs. | | `mockups` | array of object | Generated preview images. Rendered in the background; `product.updated` fires when they are ready. | | `warnings` | array of [ProductWarning](https://swaglists.com/docs/objects.md#product_warning) | Only on create/update responses: non-blocking design issues. | | `created_at` | string | When the object was created (ISO-8601, UTC). | | `updated_at` | string | When the object was last changed (ISO-8601, UTC). | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid), [`duplicate_placement`](https://swaglists.com/docs/errors.md#duplicate_placement), [`unknown_placement`](https://swaglists.com/docs/errors.md#unknown_placement), [`placement_required`](https://swaglists.com/docs/errors.md#placement_required), [`file_not_artwork`](https://swaglists.com/docs/errors.md#file_not_artwork), [`file_not_ready`](https://swaglists.com/docs/errors.md#file_not_ready), [`file_not_image`](https://swaglists.com/docs/errors.md#file_not_image), [`design_not_visible`](https://swaglists.com/docs/errors.md#design_not_visible), [`artwork_resolution_too_low`](https://swaglists.com/docs/errors.md#artwork_resolution_too_low), [`download_failed`](https://swaglists.com/docs/errors.md#download_failed) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 409 | [`idempotency_key_reused`](https://swaglists.com/docs/errors.md#idempotency_key_reused), [`idempotency_in_progress`](https://swaglists.com/docs/errors.md#idempotency_in_progress), [`product_archived`](https://swaglists.com/docs/errors.md#product_archived), [`external_id_taken`](https://swaglists.com/docs/errors.md#external_id_taken) | | 413 | [`request_too_large`](https://swaglists.com/docs/errors.md#request_too_large) | | 415 | [`unsupported_media_type`](https://swaglists.com/docs/errors.md#unsupported_media_type) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl -X PATCH https://swaglists.com/api/v1/products/prod_01k8x3z7r1t3y5u7i9o1p3a5s7 \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "title": "Company A Logo Tee (2026)", "retail_price": 3100 }' ``` **Example response** ```json { "object": "product", "id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "title": "Company A Logo Tee", "description": "Our classic logo on a soft tee.", "status": "active", "catalog_product_id": "cp_01k8w1a2s3d4f5g6h7j8k9m0n1", "external_id": "shopify-product-9921", "tags": [ "logo" ], "metadata": {}, "retail_price": 2900, "currency": "usd", "designs": [ { "placement": "front", "layers": [ { "file_id": "file_01k8x3y1q3w5e7r9t1y3u5i7o9", "transform": { "x": 0.1, "y": 0.05, "width": 0.8, "height": 0.6, "rotation": 0 }, "opacity": 1 } ] } ], "variants": [ { "object": "product_variant", "id": "pvar_01k8x3z7r4f6g8h0j2k4l6z8x0", "product_id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "sku": "CA-TEE-BLK-M", "catalog_variant_id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "title": "Black / M", "options": { "Color": "Black", "Size": "M" }, "retail_price": 2900, "price": 1299, "currency": "usd", "external_id": "shopify-variant-4410", "enabled": true, "available": true } ], "mockups": [ { "url": "https://swaglists.com/f/file_01k8x3y9a1s3d5f7g9h1j3k5l7/1782777600.c0ffee/mockup-front.png", "placement": "front", "color": "Black", "is_primary": true } ], "created_at": "2026-10-21T14:32:05.000Z", "updated_at": "2026-10-21T14:32:05.000Z" } ``` ### Archive a product `DELETE /products/{id}` Archives the product: its variants can no longer be ordered, SKUs stay reserved and existing orders are unaffected. Restore it by PATCHing a `status`. Requires scope `products:write`. **Scope:** `products:write` · **Idempotency:** send an `Idempotency-Key` header **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | Product id. 1–300 characters. | **Returns** `200` — The archived product. [Product](https://swaglists.com/docs/objects.md#product) | Field | Type | Description | | --- | --- | --- | | `object` | "product" | Type of the object: always `product`. | | `id` | string | Unique identifier (starts with `prod_`). | | `title` | string | Product title. | | `description` | string \| null | Product description (plain text or markdown). | | `status` | string | draft, active, or archived (archived products can no longer be ordered). One of: `draft`, `active`, `archived`. | | `catalog_product_id` | string | Catalog product this product is made from. | | `external_id` | string \| null | Your id for the product (e.g. your store's product id). | | `tags` | array of string | Your tags. | | `metadata` | map of string | Your key/value pairs (string values). | | `retail_price` | integer \| null | Default retail price of the variants (informational, used in exports), in cents. | | `currency` | "usd" | Three-letter currency code, lowercase (`usd`). | | `designs` | array of [Design](https://swaglists.com/docs/objects.md#design) | Artwork per placement. | | `variants` | array of [ProductVariant](https://swaglists.com/docs/objects.md#product_variant) | Sellable variants with your SKUs. | | `mockups` | array of object | Generated preview images. Rendered in the background; `product.updated` fires when they are ready. | | `warnings` | array of [ProductWarning](https://swaglists.com/docs/objects.md#product_warning) | Only on create/update responses: non-blocking design issues. | | `created_at` | string | When the object was created (ISO-8601, UTC). | | `updated_at` | string | When the object was last changed (ISO-8601, UTC). | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 413 | [`request_too_large`](https://swaglists.com/docs/errors.md#request_too_large) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl -X DELETE https://swaglists.com/api/v1/products/prod_01k8x3z7r1t3y5u7i9o1p3a5s7 \ -H "Authorization: Bearer $API_KEY" \ -H "Idempotency-Key: $(uuidgen)" ``` **Example response** ```json { "object": "product", "id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "title": "Company A Logo Tee", "description": "Our classic logo on a soft tee.", "status": "active", "catalog_product_id": "cp_01k8w1a2s3d4f5g6h7j8k9m0n1", "external_id": "shopify-product-9921", "tags": [ "logo" ], "metadata": {}, "retail_price": 2900, "currency": "usd", "designs": [ { "placement": "front", "layers": [ { "file_id": "file_01k8x3y1q3w5e7r9t1y3u5i7o9", "transform": { "x": 0.1, "y": 0.05, "width": 0.8, "height": 0.6, "rotation": 0 }, "opacity": 1 } ] } ], "variants": [ { "object": "product_variant", "id": "pvar_01k8x3z7r4f6g8h0j2k4l6z8x0", "product_id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "sku": "CA-TEE-BLK-M", "catalog_variant_id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "title": "Black / M", "options": { "Color": "Black", "Size": "M" }, "retail_price": 2900, "price": 1299, "currency": "usd", "external_id": "shopify-variant-4410", "enabled": true, "available": true } ], "mockups": [ { "url": "https://swaglists.com/f/file_01k8x3y9a1s3d5f7g9h1j3k5l7/1782777600.c0ffee/mockup-front.png", "placement": "front", "color": "Black", "is_primary": true } ], "created_at": "2026-10-21T14:32:05.000Z", "updated_at": "2026-10-21T14:32:05.000Z" } ``` ### Find a product variant by SKU `GET /products/by_sku/{sku}` Looks up one of your product variants by its SKU (URL-encode SKUs with special characters). Requires scope `products:read`. **Scope:** `products:read` **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `sku` | string | yes | Your SKU. 1–300 characters. | **Returns** `200` — The variant. [ProductVariant](https://swaglists.com/docs/objects.md#product_variant) | Field | Type | Description | | --- | --- | --- | | `object` | "product_variant" | Type of the object: always `product_variant`. | | `id` | string | Unique identifier (starts with `pvar_`). | | `product_id` | string | Product the variant belongs to. | | `sku` | string | Your SKU (unique in your account). Order items can reference it. | | `catalog_variant_id` | string | Catalog variant that is produced for this SKU. | | `title` | string | Variant title (e.g. `Black / M`). | | `options` | map of string | Option values (e.g. `{"Color": "Black", "Size": "M"}`). | | `retail_price` | integer \| null | Your retail price (informational), cents. | | `price` | integer \| null | Your wholesale price per unit with this product's designs, cents. | | `currency` | "usd" | Three-letter currency code, lowercase (`usd`). | | `external_id` | string \| null | Your id for the variant (e.g. your store's variant id). | | `enabled` | boolean | Disabled variants cannot be ordered (their SKU stays reserved). | | `available` | boolean | Whether the variant can be ordered right now: enabled, product not archived, and the catalog variant offered and in stock. `false` while it is temporarily out of stock — mark it sold out in your store; `product.updated` fires when this changes. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl https://swaglists.com/api/v1/products/by_sku/CA-TEE-BLK-M \ -H "Authorization: Bearer $API_KEY" ``` **Example response** ```json { "object": "product_variant", "id": "pvar_01k8x3z7r4f6g8h0j2k4l6z8x0", "product_id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "sku": "CA-TEE-BLK-M", "catalog_variant_id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "title": "Black / M", "options": { "Color": "Black", "Size": "M" }, "retail_price": 2900, "price": 1299, "currency": "usd", "external_id": "shopify-variant-4410", "enabled": true, "available": true } ``` ### List product variants `GET /products/{id}/variants` All variants of the product (including disabled ones). Requires scope `products:read`. **Scope:** `products:read` **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | Product id. 1–300 characters. | **Returns** `200` — The variants. [ProductVariantList](https://swaglists.com/docs/objects.md#list) | Field | Type | Description | | --- | --- | --- | | `object` | "list" | Always `list`. | | `data` | array of [ProductVariant](https://swaglists.com/docs/objects.md#product_variant) | The objects of this page. | | `has_more` | boolean | Whether more items exist beyond this page (in the paging direction). | | `url` | string | Path of this list endpoint. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl https://swaglists.com/api/v1/products/prod_01k8x3z7r1t3y5u7i9o1p3a5s7/variants \ -H "Authorization: Bearer $API_KEY" ``` **Example response** ```json { "object": "list", "data": [ { "object": "product_variant", "id": "pvar_01k8x3z7r4f6g8h0j2k4l6z8x0", "product_id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "sku": "CA-TEE-BLK-M", "catalog_variant_id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "title": "Black / M", "options": { "Color": "Black", "Size": "M" }, "retail_price": 2900, "price": 1299, "currency": "usd", "external_id": "shopify-variant-4410", "enabled": true, "available": true } ], "has_more": false, "url": "/api/v1/products/prod_01k8x3z7r1t3y5u7i9o1p3a5s7/variants" } ``` ### Add product variants `POST /products/{id}/variants` Adds catalog variants to the product (or re-enables disabled ones). Pass `"all"` for every active catalog variant. Requires scope `products:write`. **Scope:** `products:write` · **Idempotency:** send an `Idempotency-Key` header **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | Product id. 1–300 characters. | **Request body** (`application/json`) — AddProductVariantsRequest | Field | Type | Required | Description | | --- | --- | --- | --- | | `variants` | "all" or array of ProductVariantInput | yes | "all" (every active catalog variant) or an explicit list. | | `variants[].catalog_variant_id` | string | yes | 1–100 characters. | | `variants[].sku` | string \| null | no | Your SKU; generated when omitted. 1–64 characters. Pattern `^[\x21-\x7E](?:[\x20-\x7E]{0,62}[\x21-\x7E])?$`. | | `variants[].retail_price` | integer \| null | no | Range 0–100000000. | | `variants[].external_id` | string \| null | no | 1–255 characters. | **Returns** `200` — The product with its variants. [Product](https://swaglists.com/docs/objects.md#product) | Field | Type | Description | | --- | --- | --- | | `object` | "product" | Type of the object: always `product`. | | `id` | string | Unique identifier (starts with `prod_`). | | `title` | string | Product title. | | `description` | string \| null | Product description (plain text or markdown). | | `status` | string | draft, active, or archived (archived products can no longer be ordered). One of: `draft`, `active`, `archived`. | | `catalog_product_id` | string | Catalog product this product is made from. | | `external_id` | string \| null | Your id for the product (e.g. your store's product id). | | `tags` | array of string | Your tags. | | `metadata` | map of string | Your key/value pairs (string values). | | `retail_price` | integer \| null | Default retail price of the variants (informational, used in exports), in cents. | | `currency` | "usd" | Three-letter currency code, lowercase (`usd`). | | `designs` | array of [Design](https://swaglists.com/docs/objects.md#design) | Artwork per placement. | | `variants` | array of [ProductVariant](https://swaglists.com/docs/objects.md#product_variant) | Sellable variants with your SKUs. | | `mockups` | array of object | Generated preview images. Rendered in the background; `product.updated` fires when they are ready. | | `warnings` | array of [ProductWarning](https://swaglists.com/docs/objects.md#product_warning) | Only on create/update responses: non-blocking design issues. | | `created_at` | string | When the object was created (ISO-8601, UTC). | | `updated_at` | string | When the object was last changed (ISO-8601, UTC). | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid), [`variant_unavailable`](https://swaglists.com/docs/errors.md#variant_unavailable), [`duplicate_variant`](https://swaglists.com/docs/errors.md#duplicate_variant), [`duplicate_sku`](https://swaglists.com/docs/errors.md#duplicate_sku) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 409 | [`idempotency_key_reused`](https://swaglists.com/docs/errors.md#idempotency_key_reused), [`idempotency_in_progress`](https://swaglists.com/docs/errors.md#idempotency_in_progress), [`product_archived`](https://swaglists.com/docs/errors.md#product_archived), [`variant_exists`](https://swaglists.com/docs/errors.md#variant_exists), [`sku_taken`](https://swaglists.com/docs/errors.md#sku_taken) | | 413 | [`request_too_large`](https://swaglists.com/docs/errors.md#request_too_large) | | 415 | [`unsupported_media_type`](https://swaglists.com/docs/errors.md#unsupported_media_type) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl -X POST https://swaglists.com/api/v1/products/prod_01k8x3z7r1t3y5u7i9o1p3a5s7/variants \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "variants": [ { "catalog_variant_id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "sku": "CA-TEE-BLK-L" } ] }' ``` **Example response** ```json { "object": "product", "id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "title": "Company A Logo Tee", "description": "Our classic logo on a soft tee.", "status": "active", "catalog_product_id": "cp_01k8w1a2s3d4f5g6h7j8k9m0n1", "external_id": "shopify-product-9921", "tags": [ "logo" ], "metadata": {}, "retail_price": 2900, "currency": "usd", "designs": [ { "placement": "front", "layers": [ { "file_id": "file_01k8x3y1q3w5e7r9t1y3u5i7o9", "transform": { "x": 0.1, "y": 0.05, "width": 0.8, "height": 0.6, "rotation": 0 }, "opacity": 1 } ] } ], "variants": [ { "object": "product_variant", "id": "pvar_01k8x3z7r4f6g8h0j2k4l6z8x0", "product_id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "sku": "CA-TEE-BLK-M", "catalog_variant_id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "title": "Black / M", "options": { "Color": "Black", "Size": "M" }, "retail_price": 2900, "price": 1299, "currency": "usd", "external_id": "shopify-variant-4410", "enabled": true, "available": true } ], "mockups": [ { "url": "https://swaglists.com/f/file_01k8x3y9a1s3d5f7g9h1j3k5l7/1782777600.c0ffee/mockup-front.png", "placement": "front", "color": "Black", "is_primary": true } ], "created_at": "2026-10-21T14:32:05.000Z", "updated_at": "2026-10-21T14:32:05.000Z" } ``` ### Update a product variant `PATCH /products/{id}/variants/{variant_id}` Changes the SKU (unique in your account), retail price, external id or enables/disables the variant. Requires scope `products:write`. **Scope:** `products:write` · **Idempotency:** send an `Idempotency-Key` header **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | Product id. 1–300 characters. | | `variant_id` | string | yes | Product variant id. 1–300 characters. | **Request body** (`application/json`) — UpdateProductVariantRequest | Field | Type | Required | Description | | --- | --- | --- | --- | | `sku` | string | no | 1–64 characters. Pattern `^[\x21-\x7E](?:[\x20-\x7E]{0,62}[\x21-\x7E])?$`. | | `retail_price` | integer \| null | no | Range 0–100000000. | | `enabled` | boolean | no | Disabled variants cannot be ordered; their SKU stays reserved. | | `external_id` | string \| null | no | 1–255 characters. | **Returns** `200` — The updated variant. [ProductVariant](https://swaglists.com/docs/objects.md#product_variant) | Field | Type | Description | | --- | --- | --- | | `object` | "product_variant" | Type of the object: always `product_variant`. | | `id` | string | Unique identifier (starts with `pvar_`). | | `product_id` | string | Product the variant belongs to. | | `sku` | string | Your SKU (unique in your account). Order items can reference it. | | `catalog_variant_id` | string | Catalog variant that is produced for this SKU. | | `title` | string | Variant title (e.g. `Black / M`). | | `options` | map of string | Option values (e.g. `{"Color": "Black", "Size": "M"}`). | | `retail_price` | integer \| null | Your retail price (informational), cents. | | `price` | integer \| null | Your wholesale price per unit with this product's designs, cents. | | `currency` | "usd" | Three-letter currency code, lowercase (`usd`). | | `external_id` | string \| null | Your id for the variant (e.g. your store's variant id). | | `enabled` | boolean | Disabled variants cannot be ordered (their SKU stays reserved). | | `available` | boolean | Whether the variant can be ordered right now: enabled, product not archived, and the catalog variant offered and in stock. `false` while it is temporarily out of stock — mark it sold out in your store; `product.updated` fires when this changes. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid), [`variant_unavailable`](https://swaglists.com/docs/errors.md#variant_unavailable) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 409 | [`idempotency_key_reused`](https://swaglists.com/docs/errors.md#idempotency_key_reused), [`idempotency_in_progress`](https://swaglists.com/docs/errors.md#idempotency_in_progress), [`product_archived`](https://swaglists.com/docs/errors.md#product_archived), [`sku_taken`](https://swaglists.com/docs/errors.md#sku_taken) | | 413 | [`request_too_large`](https://swaglists.com/docs/errors.md#request_too_large) | | 415 | [`unsupported_media_type`](https://swaglists.com/docs/errors.md#unsupported_media_type) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl -X PATCH https://swaglists.com/api/v1/products/prod_01k8x3z7r1t3y5u7i9o1p3a5s7/variants/pvar_01k8x3z7r4f6g8h0j2k4l6z8x0 \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "retail_price": 3100, "enabled": true }' ``` **Example response** ```json { "object": "product_variant", "id": "pvar_01k8x3z7r4f6g8h0j2k4l6z8x0", "product_id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "sku": "CA-TEE-BLK-M", "catalog_variant_id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "title": "Black / M", "options": { "Color": "Black", "Size": "M" }, "retail_price": 2900, "price": 1299, "currency": "usd", "external_id": "shopify-variant-4410", "enabled": true, "available": true } ``` ### Retrieve a product variant `GET /product_variants/{id}` Requires scope `products:read`. **Scope:** `products:read` **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | Product variant id. 1–300 characters. | **Returns** `200` — The variant. [ProductVariant](https://swaglists.com/docs/objects.md#product_variant) | Field | Type | Description | | --- | --- | --- | | `object` | "product_variant" | Type of the object: always `product_variant`. | | `id` | string | Unique identifier (starts with `pvar_`). | | `product_id` | string | Product the variant belongs to. | | `sku` | string | Your SKU (unique in your account). Order items can reference it. | | `catalog_variant_id` | string | Catalog variant that is produced for this SKU. | | `title` | string | Variant title (e.g. `Black / M`). | | `options` | map of string | Option values (e.g. `{"Color": "Black", "Size": "M"}`). | | `retail_price` | integer \| null | Your retail price (informational), cents. | | `price` | integer \| null | Your wholesale price per unit with this product's designs, cents. | | `currency` | "usd" | Three-letter currency code, lowercase (`usd`). | | `external_id` | string \| null | Your id for the variant (e.g. your store's variant id). | | `enabled` | boolean | Disabled variants cannot be ordered (their SKU stays reserved). | | `available` | boolean | Whether the variant can be ordered right now: enabled, product not archived, and the catalog variant offered and in stock. `false` while it is temporarily out of stock — mark it sold out in your store; `product.updated` fires when this changes. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl https://swaglists.com/api/v1/product_variants/pvar_01k8x3z7r4f6g8h0j2k4l6z8x0 \ -H "Authorization: Bearer $API_KEY" ``` **Example response** ```json { "object": "product_variant", "id": "pvar_01k8x3z7r4f6g8h0j2k4l6z8x0", "product_id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "sku": "CA-TEE-BLK-M", "catalog_variant_id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "title": "Black / M", "options": { "Color": "Black", "Size": "M" }, "retail_price": 2900, "price": 1299, "currency": "usd", "external_id": "shopify-variant-4410", "enabled": true, "available": true } ``` ## Shipping Shipping options and prices for a destination. ### Get shipping rates `POST /shipping/rates` Shipping options and prices for a destination and a set of items (identified exactly like order items). Use it in your checkout; the price of the method you pick is what the order will charge. Nothing is created. Requires scope `orders:read`. **Scope:** `orders:read` · **Idempotency:** send an `Idempotency-Key` header **Request body** (`application/json`) — ShippingRatesRequest | Field | Type | Required | Description | | --- | --- | --- | --- | | `recipient` | ShippingRatesRecipient | yes | — | | `recipient.country_code` | string | yes | ISO 3166-1 alpha-2 country code. Pattern `^[A-Za-z]{2}$`. | | `recipient.state_code` | string \| null | no | State, province or region — preferably the ISO 3166-2 subdivision code without the country prefix (e.g. CA, NY, ON, NSW; "US-CA" also works). Full names (e.g. "British Columbia", "New South Wales") are converted to the code for the US, Canada and Australia; for other countries the value is kept as sent. An empty string means not set. Max 64 characters. | | `recipient.postal_code` | string \| null | no | Max 20 characters. | | `items` | array of OrderItemInput | yes | 1–100 items. | | `items[].product_variant_id` | string | no | One of your product variants. 1–100 characters. | | `items[].sku` | string | no | Or your product variant SKU. 1–64 characters. | | `items[].catalog_variant_id` | string | no | Or a catalog variant with inline `designs` (on-the-fly personalization). 1–100 characters. | | `items[].designs` | array of DesignInput | no | Required with catalog_variant_id. 1–20 items. | | `items[].designs[].placement` | string | yes | Placement key from the catalog product (e.g. front, back). 1–64 characters. | | `items[].designs[].layers` | array of DesignLayerInput | yes | 1–20 items. | | `items[].designs[].layers[].file_id` | string | no | Id of an uploaded artwork file. 1–100 characters. | | `items[].designs[].layers[].url` | string | no | Or a public image URL; we download it into a new artwork file. Max 2048 characters. Must be an http(s) URL. | | `items[].designs[].layers[].position` | Position | no | Where the artwork sits inside the placement's print area. Fractions of the print area (0–1; values outside allow intentional bleed). Omit to center the artwork and fit it inside the area. | | `items[].designs[].layers[].position.x` | number | yes | Left edge of the artwork box as a fraction of the print area width. Range -10–10. | | `items[].designs[].layers[].position.y` | number | yes | Top edge of the artwork box as a fraction of the print area height. Range -10–10. | | `items[].designs[].layers[].position.width` | number | yes | Artwork width as a fraction of the print area width. Range >0–10. | | `items[].designs[].layers[].position.height` | number | yes | Artwork height as a fraction of the print area height. Range >0–10. | | `items[].designs[].layers[].position.rotation` | number | no | Clockwise rotation in degrees around the artwork center. Range -3600–3600. Default `0`. | | `items[].designs[].layers[].transform` | Position | no | Alias of `position` (as returned on products and orders). | | `items[].designs[].layers[].transform.x` | number | yes | Left edge of the artwork box as a fraction of the print area width. Range -10–10. | | `items[].designs[].layers[].transform.y` | number | yes | Top edge of the artwork box as a fraction of the print area height. Range -10–10. | | `items[].designs[].layers[].transform.width` | number | yes | Artwork width as a fraction of the print area width. Range >0–10. | | `items[].designs[].layers[].transform.height` | number | yes | Artwork height as a fraction of the print area height. Range >0–10. | | `items[].designs[].layers[].transform.rotation` | number | no | Clockwise rotation in degrees around the artwork center. Range -3600–3600. Default `0`. | | `items[].designs[].layers[].opacity` | number | no | 0–1 (default 1). Range 0–1. | | `items[].quantity` | integer | yes | Units of this item (at most 1000 per line). Range 1–1000. | | `items[].external_line_id` | string \| null | no | Your line item id. 1–128 characters. | | `items[].metadata` | map of string | no | Up to 50 key/value pairs (keys ≤ 40 chars, string values ≤ 500 chars) for your own references. Never store sensitive data here. | | `items[].retail_price` | integer \| null | no | What YOUR customer paid per unit (cents). Printed on international packing slips and declared for customs instead of our price. Default: the product variant's (or product's) retail price. Range 0–100000000. | **Returns** `200` — Available shipping methods. [ShippingRateList](https://swaglists.com/docs/objects.md#list) | Field | Type | Description | | --- | --- | --- | | `object` | "list" | Always `list`. | | `data` | array of [ShippingRate](https://swaglists.com/docs/objects.md#shipping_rate) | The objects of this page. | | `has_more` | boolean | Whether more items exist beyond this page (in the paging direction). | | `url` | string | Path of this list endpoint. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid), [`variant_unavailable`](https://swaglists.com/docs/errors.md#variant_unavailable), [`variant_disabled`](https://swaglists.com/docs/errors.md#variant_disabled), [`product_archived`](https://swaglists.com/docs/errors.md#product_archived), [`product_has_no_designs`](https://swaglists.com/docs/errors.md#product_has_no_designs), [`placement_required`](https://swaglists.com/docs/errors.md#placement_required), [`unknown_placement`](https://swaglists.com/docs/errors.md#unknown_placement), [`file_not_artwork`](https://swaglists.com/docs/errors.md#file_not_artwork), [`file_not_ready`](https://swaglists.com/docs/errors.md#file_not_ready), [`file_not_image`](https://swaglists.com/docs/errors.md#file_not_image), [`design_not_visible`](https://swaglists.com/docs/errors.md#design_not_visible), [`artwork_resolution_too_low`](https://swaglists.com/docs/errors.md#artwork_resolution_too_low), [`item_unavailable`](https://swaglists.com/docs/errors.md#item_unavailable) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 413 | [`request_too_large`](https://swaglists.com/docs/errors.md#request_too_large) | | 415 | [`unsupported_media_type`](https://swaglists.com/docs/errors.md#unsupported_media_type) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl -X POST https://swaglists.com/api/v1/shipping/rates \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "recipient": { "country_code": "US", "state_code": "CA", "postal_code": "94107" }, "items": [ { "sku": "CA-TEE-BLK-M", "quantity": 2 } ] }' ``` **Example response** ```json { "object": "list", "data": [ { "object": "shipping_rate", "method": "standard", "name": "Standard", "price": 475, "currency": "usd", "min_days": 3, "max_days": 5, "estimated_delivery_days": { "min": 5, "max": 9 } } ], "has_more": false, "url": "/api/v1/shipping/rates" } ``` ## Orders Create, estimate, confirm and cancel orders; track their status and shipments. ### Estimate an order `POST /orders/estimate` Prices an order exactly like POST /orders would (items, shipping, tax, delivery estimate, whether your wallet covers it) without creating anything. Requires scope `orders:read`. **Scope:** `orders:read` · **Idempotency:** send an `Idempotency-Key` header **Request body** (`application/json`) — CreateOrderRequest | Field | Type | Required | Description | | --- | --- | --- | --- | | `external_id` | string \| null | no | Your order id; unique per mode. Retrieve with GET /orders/ext:. Up to 128 printable ASCII characters. 1–128 characters. Pattern `^[\x20-\x7e]+$`. | | `recipient` | RecipientInput | yes | — | | `recipient.name` | string | yes | 1–100 characters. | | `recipient.company` | string \| null | no | Max 100 characters. | | `recipient.address1` | string | yes | 1–150 characters. | | `recipient.address2` | string \| null | no | Max 150 characters. | | `recipient.city` | string | yes | 1–100 characters. | | `recipient.state_code` | string \| null | no | State, province or region — preferably the ISO 3166-2 subdivision code without the country prefix (e.g. CA, NY, ON, NSW; "US-CA" also works). Full names (e.g. "British Columbia", "New South Wales") are converted to the code for the US, Canada and Australia; for other countries the value is kept as sent. An empty string means not set. Required for the US, Canada and Australia; for the US and Canada it must be a valid state/province code or name. Max 64 characters. | | `recipient.postal_code` | string \| null | no | Postal / ZIP code. Required unless the destination country has no postal codes (e.g. HK, AE). Max 20 characters. | | `recipient.country_code` | string | yes | ISO 3166-1 alpha-2 country code. Pattern `^[A-Za-z]{2}$`. | | `recipient.phone` | string \| null | no | Max 40 characters. | | `recipient.tax_id` | string \| null | no | Recipient tax id required by customs for some destinations, e.g. the CPF/CNPJ for Brazil. Write-only (never returned). Max 40 characters. | | `recipient.email` | string \| null | no | Used for delivery notifications (if you enable them). An empty string means no email. Max 254 characters. Email address. | | `shipping_method` | string | no | Default standard. One of: `economy`, `standard`, `express`, `priority`. | | `items` | array of OrderItemInput | yes | 1–100 items. | | `items[].product_variant_id` | string | no | One of your product variants. 1–100 characters. | | `items[].sku` | string | no | Or your product variant SKU. 1–64 characters. | | `items[].catalog_variant_id` | string | no | Or a catalog variant with inline `designs` (on-the-fly personalization). 1–100 characters. | | `items[].designs` | array of DesignInput | no | Required with catalog_variant_id. 1–20 items. | | `items[].designs[].placement` | string | yes | Placement key from the catalog product (e.g. front, back). 1–64 characters. | | `items[].designs[].layers` | array of DesignLayerInput | yes | 1–20 items. | | `items[].designs[].layers[].file_id` | string | no | Id of an uploaded artwork file. 1–100 characters. | | `items[].designs[].layers[].url` | string | no | Or a public image URL; we download it into a new artwork file. Max 2048 characters. Must be an http(s) URL. | | `items[].designs[].layers[].position` | Position | no | Where the artwork sits inside the placement's print area. Fractions of the print area (0–1; values outside allow intentional bleed). Omit to center the artwork and fit it inside the area. | | `items[].designs[].layers[].position.x` | number | yes | Left edge of the artwork box as a fraction of the print area width. Range -10–10. | | `items[].designs[].layers[].position.y` | number | yes | Top edge of the artwork box as a fraction of the print area height. Range -10–10. | | `items[].designs[].layers[].position.width` | number | yes | Artwork width as a fraction of the print area width. Range >0–10. | | `items[].designs[].layers[].position.height` | number | yes | Artwork height as a fraction of the print area height. Range >0–10. | | `items[].designs[].layers[].position.rotation` | number | no | Clockwise rotation in degrees around the artwork center. Range -3600–3600. Default `0`. | | `items[].designs[].layers[].transform` | Position | no | Alias of `position` (as returned on products and orders). | | `items[].designs[].layers[].transform.x` | number | yes | Left edge of the artwork box as a fraction of the print area width. Range -10–10. | | `items[].designs[].layers[].transform.y` | number | yes | Top edge of the artwork box as a fraction of the print area height. Range -10–10. | | `items[].designs[].layers[].transform.width` | number | yes | Artwork width as a fraction of the print area width. Range >0–10. | | `items[].designs[].layers[].transform.height` | number | yes | Artwork height as a fraction of the print area height. Range >0–10. | | `items[].designs[].layers[].transform.rotation` | number | no | Clockwise rotation in degrees around the artwork center. Range -3600–3600. Default `0`. | | `items[].designs[].layers[].opacity` | number | no | 0–1 (default 1). Range 0–1. | | `items[].quantity` | integer | yes | Units of this item (at most 1000 per line). Range 1–1000. | | `items[].external_line_id` | string \| null | no | Your line item id. 1–128 characters. | | `items[].metadata` | map of string | no | Up to 50 key/value pairs (keys ≤ 40 chars, string values ≤ 500 chars) for your own references. Never store sensitive data here. | | `items[].retail_price` | integer \| null | no | What YOUR customer paid per unit (cents). Printed on international packing slips and declared for customs instead of our price. Default: the product variant's (or product's) retail price. Range 0–100000000. | | `packing_slip` | PackingSlipInput | no | — | | `packing_slip.message` | string \| null | no | Max 500 characters. | | `packing_slip.brand_name` | string \| null | no | Overrides your account brand name on the packing slip. Max 100 characters. | | `packing_slip.logo_file_id` | string \| null | no | An uploaded logo/artwork file to print instead of your account logo. 1–100 characters. | | `packing_slip.customer_order_number` | string \| null | no | Max 64 characters. | | `gift_message` | string \| null | no | Max 500 characters. | | `customer_note` | string \| null | no | Max 1000 characters. | | `metadata` | map of string | no | Up to 50 key/value pairs (keys ≤ 40 chars, string values ≤ 500 chars) for your own references. Never store sensitive data here. | | `confirm` | boolean | no | true: reserve credits and start production now; false: create a draft. Default: your account's auto-confirm setting. | **Returns** `200` — The estimate. [OrderEstimate](https://swaglists.com/docs/objects.md#order_estimate) | Field | Type | Description | | --- | --- | --- | | `object` | "order_estimate" | Type of the object: always `order_estimate`. | | `livemode` | boolean | `true` in live mode, `false` in test mode. | | `currency` | string | Three-letter currency code, lowercase (`usd`). | | `shipping_method` | string | Shipping method the estimate was priced with. One of: `economy`, `standard`, `express`, `priority`. | | `items` | array of object | Priced items, in the order you sent them. | | `subtotal` | integer | Items total in cents. | | `shipping` | integer | Shipping price in cents. | | `tax` | integer | Tax in cents. | | `total` | integer | Exactly what POST /orders would charge. | | `available_shipping_methods` | array of [ShippingRate](https://swaglists.com/docs/objects.md#shipping_rate) | Every shipping method you could choose, with its price. | | `estimated_delivery_days` | object | Business days from order to delivery, including production. | | `wallet_available` | integer | Available credits (cents). | | `sufficient_funds` | boolean | Whether your available credits cover `total`. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid), [`variant_unavailable`](https://swaglists.com/docs/errors.md#variant_unavailable), [`variant_disabled`](https://swaglists.com/docs/errors.md#variant_disabled), [`product_archived`](https://swaglists.com/docs/errors.md#product_archived), [`product_has_no_designs`](https://swaglists.com/docs/errors.md#product_has_no_designs), [`placement_required`](https://swaglists.com/docs/errors.md#placement_required), [`unknown_placement`](https://swaglists.com/docs/errors.md#unknown_placement), [`file_not_artwork`](https://swaglists.com/docs/errors.md#file_not_artwork), [`file_not_ready`](https://swaglists.com/docs/errors.md#file_not_ready), [`file_not_image`](https://swaglists.com/docs/errors.md#file_not_image), [`design_not_visible`](https://swaglists.com/docs/errors.md#design_not_visible), [`artwork_resolution_too_low`](https://swaglists.com/docs/errors.md#artwork_resolution_too_low), [`item_unavailable`](https://swaglists.com/docs/errors.md#item_unavailable), [`shipping_method_unavailable`](https://swaglists.com/docs/errors.md#shipping_method_unavailable), [`variant_unpriceable`](https://swaglists.com/docs/errors.md#variant_unpriceable) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 413 | [`request_too_large`](https://swaglists.com/docs/errors.md#request_too_large) | | 415 | [`unsupported_media_type`](https://swaglists.com/docs/errors.md#unsupported_media_type) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl -X POST https://swaglists.com/api/v1/orders/estimate \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "external_id": "1042", "recipient": { "name": "Jane Doe", "address1": "123 Market St", "city": "San Francisco", "state_code": "CA", "postal_code": "94107", "country_code": "US", "email": "jane@example.com" }, "shipping_method": "standard", "items": [ { "sku": "CA-TEE-BLK-M", "quantity": 2, "external_line_id": "line-1" } ], "packing_slip": { "message": "Thanks for shopping with Company A!", "customer_order_number": "#1042" }, "confirm": true }' ``` **Example response** ```json { "object": "order_estimate", "livemode": true, "currency": "usd", "shipping_method": "standard", "items": [ { "index": 0, "catalog_variant_id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "product_variant_id": "pvar_01k8x3z7r4f6g8h0j2k4l6z8x0", "sku": "CA-TEE-BLK-M", "title": "Company A Logo Tee", "variant_title": "Black / M", "quantity": 2, "unit_price": 1299, "total_price": 2598 } ], "subtotal": 2598, "shipping": 700, "tax": 0, "total": 3298, "available_shipping_methods": [ { "object": "shipping_rate", "method": "standard", "name": "Standard", "price": 475, "currency": "usd", "min_days": 3, "max_days": 5, "estimated_delivery_days": { "min": 5, "max": 9 } } ], "estimated_delivery_days": { "min": 5, "max": 9 }, "wallet_available": 482550, "sufficient_funds": true } ``` ### List orders `GET /orders` Orders of the key's mode, newest first. Requires scope `orders:read`. **Scope:** `orders:read` **Query parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `limit` | integer | no | Number of objects to return, 1–100 (default 20). Range 1–100. | | `starting_after` | string | no | Cursor for the next page: the id of the last object of the previous page. 1–255 characters. | | `ending_before` | string | no | Cursor for the previous page: the id of the first object of the current page. 1–255 characters. | | `status` | string or array of string | no | Filter by status; comma-separated or repeated (draft, on_hold, processing, in_production, partially_shipped, shipped, delivered, canceled, failed). | | `external_id` | string | no | Exact match on your order id. 1–128 characters. | | `q` | string | no | Search order number, external id, recipient name or email. 1–200 characters. | | `created[gte]` | string | no | Created at or after this time. Unix seconds or milliseconds, an ISO-8601 date (2026-10-01 = midnight UTC) or an ISO-8601 date-time (with Z or an offset; without an offset it is UTC). Years 2000–2100. | | `created[lte]` | string | no | Created at or before this time. Unix seconds or milliseconds, an ISO-8601 date (2026-10-01 = midnight UTC) or an ISO-8601 date-time (with Z or an offset; without an offset it is UTC). Years 2000–2100. | **Returns** `200` — A page of orders. [OrderList](https://swaglists.com/docs/objects.md#list) | Field | Type | Description | | --- | --- | --- | | `object` | "list" | Always `list`. | | `data` | array of [Order](https://swaglists.com/docs/objects.md#order) | The objects of this page. | | `has_more` | boolean | Whether more items exist beyond this page (in the paging direction). | | `url` | string | Path of this list endpoint. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl "https://swaglists.com/api/v1/orders?limit=3" \ -H "Authorization: Bearer $API_KEY" ``` **Example response** ```json { "object": "list", "data": [ { "object": "order", "id": "ord_01k8x4b2q9w7e3r5t1y8u6i0pa", "number": 1042, "external_id": "1042", "livemode": true, "status": "shipped", "hold_reason": null, "funds_status": "captured", "source": "api", "recipient": { "name": "Jane Doe", "company": null, "address1": "123 Market St", "address2": "Apt 4", "city": "San Francisco", "state_code": "CA", "postal_code": "94107", "country_code": "US", "phone": null, "email": "jane@example.com" }, "shipping_method": "standard", "currency": "usd", "subtotal": 2598, "shipping": 700, "tax": 0, "discount": 0, "total": 3298, "refunded": 0, "items": [ { "object": "order_item", "id": "oi_01k8x4b2qa3s5d7f9g1h3j5k7l", "product_id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "product_variant_id": "pvar_01k8x3z7r4f6g8h0j2k4l6z8x0", "catalog_product_id": "cp_01k8w1a2s3d4f5g6h7j8k9m0n1", "catalog_variant_id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "sku": "CA-TEE-BLK-M", "title": "Company A Logo Tee", "variant_title": "Black / M", "quantity": 2, "shipped_quantity": 2, "unit_price": 1299, "total_price": 2598, "retail_price": 2500, "status": "shipped", "designs": [ { "placement": "front", "layers": [ { "file_id": "file_01k8x3y1q3w5e7r9t1y3u5i7o9", "transform": { "x": 0.1, "y": 0.05, "width": 0.8, "height": 0.6, "rotation": 0 }, "opacity": 1 } ] } ], "mockup_url": null, "external_line_id": "line-1", "metadata": {} } ], "shipments": [ { "object": "shipment", "id": "shp_01k8x9z1m3n5b7v9c1x3z5a7s9", "order_id": "ord_01k8x4b2q9w7e3r5t1y8u6i0pa", "status": "in_transit", "carrier": "usps", "service": "USPS Ground Advantage", "tracking_number": "9400111899223197428490", "tracking_url": "https://tools.usps.com/go/TrackConfirmAction?tLabels=9400111899223197428490", "items": [ { "order_item_id": "oi_01k8x4b2qa3s5d7f9g1h3j5k7l", "quantity": 2 } ], "shipped_at": "2026-10-23T09:12:44.000Z", "estimated_delivery_at": null, "delivered_at": null, "created_at": "2026-10-23T09:12:44.000Z" } ], "tracking_page_url": "https://swaglists.com/track/Zx81kLm2pQ", "packing_slip": { "message": "Thanks for shopping with Company A!", "brand_name": null, "logo_file_id": null, "customer_order_number": "#1042" }, "gift_message": null, "customer_note": null, "metadata": {}, "created_at": "2026-10-21T14:32:05.000Z", "updated_at": "2026-10-23T09:12:44.000Z", "placed_at": "2026-10-21T14:32:05.000Z", "in_production_at": "2026-10-21T14:32:05.000Z", "shipped_at": "2026-10-23T09:12:44.000Z", "delivered_at": null, "canceled_at": null, "cancel_reason": null, "failed_at": null, "failure_reason": null } ], "has_more": false, "url": "/api/v1/orders" } ``` ### Create an order `POST /orders` Creates an order for your end customer. Items reference your product variants (`product_variant_id` or `sku`) or a catalog variant with inline `designs`. With `confirm` (default: your account setting) the order total is reserved from your wallet and production starts; without enough credits the order waits `on_hold` (hold_reason insufficient_funds) — or, if your account rejects such orders, you get 402 insufficient_funds and nothing is created. `external_id` is unique per mode. Always send an Idempotency-Key. Requires scope `orders:write`. **Scope:** `orders:write` · **Idempotency:** send an `Idempotency-Key` header **Request body** (`application/json`) — CreateOrderRequest | Field | Type | Required | Description | | --- | --- | --- | --- | | `external_id` | string \| null | no | Your order id; unique per mode. Retrieve with GET /orders/ext:. Up to 128 printable ASCII characters. 1–128 characters. Pattern `^[\x20-\x7e]+$`. | | `recipient` | RecipientInput | yes | — | | `recipient.name` | string | yes | 1–100 characters. | | `recipient.company` | string \| null | no | Max 100 characters. | | `recipient.address1` | string | yes | 1–150 characters. | | `recipient.address2` | string \| null | no | Max 150 characters. | | `recipient.city` | string | yes | 1–100 characters. | | `recipient.state_code` | string \| null | no | State, province or region — preferably the ISO 3166-2 subdivision code without the country prefix (e.g. CA, NY, ON, NSW; "US-CA" also works). Full names (e.g. "British Columbia", "New South Wales") are converted to the code for the US, Canada and Australia; for other countries the value is kept as sent. An empty string means not set. Required for the US, Canada and Australia; for the US and Canada it must be a valid state/province code or name. Max 64 characters. | | `recipient.postal_code` | string \| null | no | Postal / ZIP code. Required unless the destination country has no postal codes (e.g. HK, AE). Max 20 characters. | | `recipient.country_code` | string | yes | ISO 3166-1 alpha-2 country code. Pattern `^[A-Za-z]{2}$`. | | `recipient.phone` | string \| null | no | Max 40 characters. | | `recipient.tax_id` | string \| null | no | Recipient tax id required by customs for some destinations, e.g. the CPF/CNPJ for Brazil. Write-only (never returned). Max 40 characters. | | `recipient.email` | string \| null | no | Used for delivery notifications (if you enable them). An empty string means no email. Max 254 characters. Email address. | | `shipping_method` | string | no | Default standard. One of: `economy`, `standard`, `express`, `priority`. | | `items` | array of OrderItemInput | yes | 1–100 items. | | `items[].product_variant_id` | string | no | One of your product variants. 1–100 characters. | | `items[].sku` | string | no | Or your product variant SKU. 1–64 characters. | | `items[].catalog_variant_id` | string | no | Or a catalog variant with inline `designs` (on-the-fly personalization). 1–100 characters. | | `items[].designs` | array of DesignInput | no | Required with catalog_variant_id. 1–20 items. | | `items[].designs[].placement` | string | yes | Placement key from the catalog product (e.g. front, back). 1–64 characters. | | `items[].designs[].layers` | array of DesignLayerInput | yes | 1–20 items. | | `items[].designs[].layers[].file_id` | string | no | Id of an uploaded artwork file. 1–100 characters. | | `items[].designs[].layers[].url` | string | no | Or a public image URL; we download it into a new artwork file. Max 2048 characters. Must be an http(s) URL. | | `items[].designs[].layers[].position` | Position | no | Where the artwork sits inside the placement's print area. Fractions of the print area (0–1; values outside allow intentional bleed). Omit to center the artwork and fit it inside the area. | | `items[].designs[].layers[].position.x` | number | yes | Left edge of the artwork box as a fraction of the print area width. Range -10–10. | | `items[].designs[].layers[].position.y` | number | yes | Top edge of the artwork box as a fraction of the print area height. Range -10–10. | | `items[].designs[].layers[].position.width` | number | yes | Artwork width as a fraction of the print area width. Range >0–10. | | `items[].designs[].layers[].position.height` | number | yes | Artwork height as a fraction of the print area height. Range >0–10. | | `items[].designs[].layers[].position.rotation` | number | no | Clockwise rotation in degrees around the artwork center. Range -3600–3600. Default `0`. | | `items[].designs[].layers[].transform` | Position | no | Alias of `position` (as returned on products and orders). | | `items[].designs[].layers[].transform.x` | number | yes | Left edge of the artwork box as a fraction of the print area width. Range -10–10. | | `items[].designs[].layers[].transform.y` | number | yes | Top edge of the artwork box as a fraction of the print area height. Range -10–10. | | `items[].designs[].layers[].transform.width` | number | yes | Artwork width as a fraction of the print area width. Range >0–10. | | `items[].designs[].layers[].transform.height` | number | yes | Artwork height as a fraction of the print area height. Range >0–10. | | `items[].designs[].layers[].transform.rotation` | number | no | Clockwise rotation in degrees around the artwork center. Range -3600–3600. Default `0`. | | `items[].designs[].layers[].opacity` | number | no | 0–1 (default 1). Range 0–1. | | `items[].quantity` | integer | yes | Units of this item (at most 1000 per line). Range 1–1000. | | `items[].external_line_id` | string \| null | no | Your line item id. 1–128 characters. | | `items[].metadata` | map of string | no | Up to 50 key/value pairs (keys ≤ 40 chars, string values ≤ 500 chars) for your own references. Never store sensitive data here. | | `items[].retail_price` | integer \| null | no | What YOUR customer paid per unit (cents). Printed on international packing slips and declared for customs instead of our price. Default: the product variant's (or product's) retail price. Range 0–100000000. | | `packing_slip` | PackingSlipInput | no | — | | `packing_slip.message` | string \| null | no | Max 500 characters. | | `packing_slip.brand_name` | string \| null | no | Overrides your account brand name on the packing slip. Max 100 characters. | | `packing_slip.logo_file_id` | string \| null | no | An uploaded logo/artwork file to print instead of your account logo. 1–100 characters. | | `packing_slip.customer_order_number` | string \| null | no | Max 64 characters. | | `gift_message` | string \| null | no | Max 500 characters. | | `customer_note` | string \| null | no | Max 1000 characters. | | `metadata` | map of string | no | Up to 50 key/value pairs (keys ≤ 40 chars, string values ≤ 500 chars) for your own references. Never store sensitive data here. | | `confirm` | boolean | no | true: reserve credits and start production now; false: create a draft. Default: your account's auto-confirm setting. | **Returns** `201` — The created order. [Order](https://swaglists.com/docs/objects.md#order) | Field | Type | Description | | --- | --- | --- | | `object` | "order" | Type of the object: always `order`. | | `id` | string | Unique identifier (starts with `ord_`). | | `number` | integer | Sequential human-friendly order number. | | `external_id` | string \| null | Your order id (unique per mode). Look the order up with `GET /orders/ext:`. | | `livemode` | boolean | `true` in live mode, `false` in test mode. | | `status` | string | draft → processing → in_production → (partially_)shipped → delivered; on_hold (see hold_reason), canceled, failed. One of: `draft`, `on_hold`, `processing`, `in_production`, `partially_shipped`, `shipped`, `delivered`, `canceled`, `failed`. | | `hold_reason` | string \| null | Why the order is on hold; only set while `status` is `on_hold`. One of: `insufficient_funds`, `manual_review`, `artwork_issue`, `address_issue`, `fulfillment_issue`. | | `funds_status` | string | State of the credits for this order: `none` (draft), `awaiting` (on hold for credits), `held` (reserved), `partially_captured`/`captured` (spent), `released` (returned unspent), `partially_refunded`/`refunded`. One of: `none`, `awaiting`, `held`, `partially_captured`, `captured`, `released`, `partially_refunded`, `refunded`. | | `source` | string | Where the order was created. One of: `api`, `dashboard`, `import`, `admin`. | | `recipient` | [Recipient](https://swaglists.com/docs/objects.md#recipient) | Shipping address of the end customer. | | `shipping_method` | string | Shipping speed of the order. One of: `economy`, `standard`, `express`, `priority`. | | `currency` | string | Three-letter currency code, lowercase (`usd`). | | `subtotal` | integer | Items total in cents. | | `shipping` | integer | Shipping price in cents. | | `tax` | integer | Tax in cents (0 unless tax applies to the destination). | | `discount` | integer | Discount in cents. | | `total` | integer | Credits charged for this order (cents). | | `refunded` | integer | Credits refunded to your wallet for this order, in cents. | | `items` | array of [OrderItem](https://swaglists.com/docs/objects.md#order_item) | Line items of the order. | | `shipments` | array of [Shipment](https://swaglists.com/docs/objects.md#shipment) | Parcels shipped so far (an order can ship in several parcels). | | `tracking_page_url` | string \| null | Your branded tracking page for the end customer. null while the order is a draft (the page exists once it is confirmed). | | `packing_slip` | object \| null | Packing slip overrides of this order (null when none were sent). | | `gift_message` | string \| null | Gift message included with the parcel. | | `customer_note` | string \| null | Note from your customer. | | `metadata` | map of string | Your key/value pairs (string values). | | `created_at` | string \| null | When the object was created (ISO-8601, UTC). | | `updated_at` | string \| null | When the object was last changed (ISO-8601, UTC). | | `placed_at` | string \| null | When the order was confirmed (credits reserved, or the order put on hold for funds). | | `in_production_at` | string \| null | When production started. | | `shipped_at` | string \| null | When the order shipped. | | `delivered_at` | string \| null | When every shipment was delivered. | | `canceled_at` | string \| null | When the order was canceled. | | `cancel_reason` | string \| null | Reason given when the order was canceled. | | `failed_at` | string \| null | When the order failed. | | `failure_reason` | string \| null | Why the order failed (reserved credits were released). | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid), [`variant_unavailable`](https://swaglists.com/docs/errors.md#variant_unavailable), [`variant_disabled`](https://swaglists.com/docs/errors.md#variant_disabled), [`product_archived`](https://swaglists.com/docs/errors.md#product_archived), [`product_has_no_designs`](https://swaglists.com/docs/errors.md#product_has_no_designs), [`placement_required`](https://swaglists.com/docs/errors.md#placement_required), [`unknown_placement`](https://swaglists.com/docs/errors.md#unknown_placement), [`file_not_artwork`](https://swaglists.com/docs/errors.md#file_not_artwork), [`file_not_ready`](https://swaglists.com/docs/errors.md#file_not_ready), [`file_not_image`](https://swaglists.com/docs/errors.md#file_not_image), [`design_not_visible`](https://swaglists.com/docs/errors.md#design_not_visible), [`artwork_resolution_too_low`](https://swaglists.com/docs/errors.md#artwork_resolution_too_low), [`file_download_failed`](https://swaglists.com/docs/errors.md#file_download_failed), [`download_failed`](https://swaglists.com/docs/errors.md#download_failed), [`download_not_an_image`](https://swaglists.com/docs/errors.md#download_not_an_image), [`download_timeout`](https://swaglists.com/docs/errors.md#download_timeout), [`file_too_large`](https://swaglists.com/docs/errors.md#file_too_large), [`file_invalid`](https://swaglists.com/docs/errors.md#file_invalid), [`file_unsupported_type`](https://swaglists.com/docs/errors.md#file_unsupported_type), [`file_unsafe`](https://swaglists.com/docs/errors.md#file_unsafe), [`item_unavailable`](https://swaglists.com/docs/errors.md#item_unavailable), [`shipping_method_unavailable`](https://swaglists.com/docs/errors.md#shipping_method_unavailable), [`variant_unpriceable`](https://swaglists.com/docs/errors.md#variant_unpriceable) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 402 | [`insufficient_funds`](https://swaglists.com/docs/errors.md#insufficient_funds) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 409 | [`idempotency_key_reused`](https://swaglists.com/docs/errors.md#idempotency_key_reused), [`idempotency_in_progress`](https://swaglists.com/docs/errors.md#idempotency_in_progress), [`duplicate_external_id`](https://swaglists.com/docs/errors.md#duplicate_external_id) | | 413 | [`request_too_large`](https://swaglists.com/docs/errors.md#request_too_large) | | 415 | [`unsupported_media_type`](https://swaglists.com/docs/errors.md#unsupported_media_type) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl -X POST https://swaglists.com/api/v1/orders \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "external_id": "1042", "recipient": { "name": "Jane Doe", "address1": "123 Market St", "city": "San Francisco", "state_code": "CA", "postal_code": "94107", "country_code": "US", "email": "jane@example.com" }, "shipping_method": "standard", "items": [ { "sku": "CA-TEE-BLK-M", "quantity": 2, "external_line_id": "line-1" } ], "packing_slip": { "message": "Thanks for shopping with Company A!", "customer_order_number": "#1042" }, "confirm": true }' ``` **Example response** ```json { "object": "order", "id": "ord_01k8x4b2q9w7e3r5t1y8u6i0pa", "number": 1042, "external_id": "1042", "livemode": true, "status": "shipped", "hold_reason": null, "funds_status": "captured", "source": "api", "recipient": { "name": "Jane Doe", "company": null, "address1": "123 Market St", "address2": "Apt 4", "city": "San Francisco", "state_code": "CA", "postal_code": "94107", "country_code": "US", "phone": null, "email": "jane@example.com" }, "shipping_method": "standard", "currency": "usd", "subtotal": 2598, "shipping": 700, "tax": 0, "discount": 0, "total": 3298, "refunded": 0, "items": [ { "object": "order_item", "id": "oi_01k8x4b2qa3s5d7f9g1h3j5k7l", "product_id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "product_variant_id": "pvar_01k8x3z7r4f6g8h0j2k4l6z8x0", "catalog_product_id": "cp_01k8w1a2s3d4f5g6h7j8k9m0n1", "catalog_variant_id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "sku": "CA-TEE-BLK-M", "title": "Company A Logo Tee", "variant_title": "Black / M", "quantity": 2, "shipped_quantity": 2, "unit_price": 1299, "total_price": 2598, "retail_price": 2500, "status": "shipped", "designs": [ { "placement": "front", "layers": [ { "file_id": "file_01k8x3y1q3w5e7r9t1y3u5i7o9", "transform": { "x": 0.1, "y": 0.05, "width": 0.8, "height": 0.6, "rotation": 0 }, "opacity": 1 } ] } ], "mockup_url": null, "external_line_id": "line-1", "metadata": {} } ], "shipments": [ { "object": "shipment", "id": "shp_01k8x9z1m3n5b7v9c1x3z5a7s9", "order_id": "ord_01k8x4b2q9w7e3r5t1y8u6i0pa", "status": "in_transit", "carrier": "usps", "service": "USPS Ground Advantage", "tracking_number": "9400111899223197428490", "tracking_url": "https://tools.usps.com/go/TrackConfirmAction?tLabels=9400111899223197428490", "items": [ { "order_item_id": "oi_01k8x4b2qa3s5d7f9g1h3j5k7l", "quantity": 2 } ], "shipped_at": "2026-10-23T09:12:44.000Z", "estimated_delivery_at": null, "delivered_at": null, "created_at": "2026-10-23T09:12:44.000Z" } ], "tracking_page_url": "https://swaglists.com/track/Zx81kLm2pQ", "packing_slip": { "message": "Thanks for shopping with Company A!", "brand_name": null, "logo_file_id": null, "customer_order_number": "#1042" }, "gift_message": null, "customer_note": null, "metadata": {}, "created_at": "2026-10-21T14:32:05.000Z", "updated_at": "2026-10-23T09:12:44.000Z", "placed_at": "2026-10-21T14:32:05.000Z", "in_production_at": "2026-10-21T14:32:05.000Z", "shipped_at": "2026-10-23T09:12:44.000Z", "delivered_at": null, "canceled_at": null, "cancel_reason": null, "failed_at": null, "failure_reason": null } ``` ### Retrieve an order `GET /orders/{id}` Look up by id or by your own id with the "ext:" prefix (GET /orders/ext:1042). Requires scope `orders:read`. **Scope:** `orders:read` **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | Order id, or "ext:" + your external_id (e.g. ext:1042). 1–300 characters. | **Returns** `200` — The order. [Order](https://swaglists.com/docs/objects.md#order) | Field | Type | Description | | --- | --- | --- | | `object` | "order" | Type of the object: always `order`. | | `id` | string | Unique identifier (starts with `ord_`). | | `number` | integer | Sequential human-friendly order number. | | `external_id` | string \| null | Your order id (unique per mode). Look the order up with `GET /orders/ext:`. | | `livemode` | boolean | `true` in live mode, `false` in test mode. | | `status` | string | draft → processing → in_production → (partially_)shipped → delivered; on_hold (see hold_reason), canceled, failed. One of: `draft`, `on_hold`, `processing`, `in_production`, `partially_shipped`, `shipped`, `delivered`, `canceled`, `failed`. | | `hold_reason` | string \| null | Why the order is on hold; only set while `status` is `on_hold`. One of: `insufficient_funds`, `manual_review`, `artwork_issue`, `address_issue`, `fulfillment_issue`. | | `funds_status` | string | State of the credits for this order: `none` (draft), `awaiting` (on hold for credits), `held` (reserved), `partially_captured`/`captured` (spent), `released` (returned unspent), `partially_refunded`/`refunded`. One of: `none`, `awaiting`, `held`, `partially_captured`, `captured`, `released`, `partially_refunded`, `refunded`. | | `source` | string | Where the order was created. One of: `api`, `dashboard`, `import`, `admin`. | | `recipient` | [Recipient](https://swaglists.com/docs/objects.md#recipient) | Shipping address of the end customer. | | `shipping_method` | string | Shipping speed of the order. One of: `economy`, `standard`, `express`, `priority`. | | `currency` | string | Three-letter currency code, lowercase (`usd`). | | `subtotal` | integer | Items total in cents. | | `shipping` | integer | Shipping price in cents. | | `tax` | integer | Tax in cents (0 unless tax applies to the destination). | | `discount` | integer | Discount in cents. | | `total` | integer | Credits charged for this order (cents). | | `refunded` | integer | Credits refunded to your wallet for this order, in cents. | | `items` | array of [OrderItem](https://swaglists.com/docs/objects.md#order_item) | Line items of the order. | | `shipments` | array of [Shipment](https://swaglists.com/docs/objects.md#shipment) | Parcels shipped so far (an order can ship in several parcels). | | `tracking_page_url` | string \| null | Your branded tracking page for the end customer. null while the order is a draft (the page exists once it is confirmed). | | `packing_slip` | object \| null | Packing slip overrides of this order (null when none were sent). | | `gift_message` | string \| null | Gift message included with the parcel. | | `customer_note` | string \| null | Note from your customer. | | `metadata` | map of string | Your key/value pairs (string values). | | `created_at` | string \| null | When the object was created (ISO-8601, UTC). | | `updated_at` | string \| null | When the object was last changed (ISO-8601, UTC). | | `placed_at` | string \| null | When the order was confirmed (credits reserved, or the order put on hold for funds). | | `in_production_at` | string \| null | When production started. | | `shipped_at` | string \| null | When the order shipped. | | `delivered_at` | string \| null | When every shipment was delivered. | | `canceled_at` | string \| null | When the order was canceled. | | `cancel_reason` | string \| null | Reason given when the order was canceled. | | `failed_at` | string \| null | When the order failed. | | `failure_reason` | string \| null | Why the order failed (reserved credits were released). | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl https://swaglists.com/api/v1/orders/ord_01k8x4b2q9w7e3r5t1y8u6i0pa \ -H "Authorization: Bearer $API_KEY" ``` **Example response** ```json { "object": "order", "id": "ord_01k8x4b2q9w7e3r5t1y8u6i0pa", "number": 1042, "external_id": "1042", "livemode": true, "status": "shipped", "hold_reason": null, "funds_status": "captured", "source": "api", "recipient": { "name": "Jane Doe", "company": null, "address1": "123 Market St", "address2": "Apt 4", "city": "San Francisco", "state_code": "CA", "postal_code": "94107", "country_code": "US", "phone": null, "email": "jane@example.com" }, "shipping_method": "standard", "currency": "usd", "subtotal": 2598, "shipping": 700, "tax": 0, "discount": 0, "total": 3298, "refunded": 0, "items": [ { "object": "order_item", "id": "oi_01k8x4b2qa3s5d7f9g1h3j5k7l", "product_id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "product_variant_id": "pvar_01k8x3z7r4f6g8h0j2k4l6z8x0", "catalog_product_id": "cp_01k8w1a2s3d4f5g6h7j8k9m0n1", "catalog_variant_id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "sku": "CA-TEE-BLK-M", "title": "Company A Logo Tee", "variant_title": "Black / M", "quantity": 2, "shipped_quantity": 2, "unit_price": 1299, "total_price": 2598, "retail_price": 2500, "status": "shipped", "designs": [ { "placement": "front", "layers": [ { "file_id": "file_01k8x3y1q3w5e7r9t1y3u5i7o9", "transform": { "x": 0.1, "y": 0.05, "width": 0.8, "height": 0.6, "rotation": 0 }, "opacity": 1 } ] } ], "mockup_url": null, "external_line_id": "line-1", "metadata": {} } ], "shipments": [ { "object": "shipment", "id": "shp_01k8x9z1m3n5b7v9c1x3z5a7s9", "order_id": "ord_01k8x4b2q9w7e3r5t1y8u6i0pa", "status": "in_transit", "carrier": "usps", "service": "USPS Ground Advantage", "tracking_number": "9400111899223197428490", "tracking_url": "https://tools.usps.com/go/TrackConfirmAction?tLabels=9400111899223197428490", "items": [ { "order_item_id": "oi_01k8x4b2qa3s5d7f9g1h3j5k7l", "quantity": 2 } ], "shipped_at": "2026-10-23T09:12:44.000Z", "estimated_delivery_at": null, "delivered_at": null, "created_at": "2026-10-23T09:12:44.000Z" } ], "tracking_page_url": "https://swaglists.com/track/Zx81kLm2pQ", "packing_slip": { "message": "Thanks for shopping with Company A!", "brand_name": null, "logo_file_id": null, "customer_order_number": "#1042" }, "gift_message": null, "customer_note": null, "metadata": {}, "created_at": "2026-10-21T14:32:05.000Z", "updated_at": "2026-10-23T09:12:44.000Z", "placed_at": "2026-10-21T14:32:05.000Z", "in_production_at": "2026-10-21T14:32:05.000Z", "shipped_at": "2026-10-23T09:12:44.000Z", "delivered_at": null, "canceled_at": null, "cancel_reason": null, "failed_at": null, "failure_reason": null } ``` ### Update a draft order `PATCH /orders/{id}` Changes a draft order (recipient, items, shipping method, …). Confirmed orders cannot be changed (409). Requires scope `orders:write`. **Scope:** `orders:write` · **Idempotency:** send an `Idempotency-Key` header **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | Order id, or "ext:" + your external_id (e.g. ext:1042). 1–300 characters. | **Request body** (`application/json`) — UpdateOrderRequest | Field | Type | Required | Description | | --- | --- | --- | --- | | `external_id` | string \| null | no | Your order id; unique per mode. Retrieve with GET /orders/ext:. Up to 128 printable ASCII characters. 1–128 characters. Pattern `^[\x20-\x7e]+$`. | | `recipient` | RecipientInput | no | — | | `recipient.name` | string | yes | 1–100 characters. | | `recipient.company` | string \| null | no | Max 100 characters. | | `recipient.address1` | string | yes | 1–150 characters. | | `recipient.address2` | string \| null | no | Max 150 characters. | | `recipient.city` | string | yes | 1–100 characters. | | `recipient.state_code` | string \| null | no | State, province or region — preferably the ISO 3166-2 subdivision code without the country prefix (e.g. CA, NY, ON, NSW; "US-CA" also works). Full names (e.g. "British Columbia", "New South Wales") are converted to the code for the US, Canada and Australia; for other countries the value is kept as sent. An empty string means not set. Required for the US, Canada and Australia; for the US and Canada it must be a valid state/province code or name. Max 64 characters. | | `recipient.postal_code` | string \| null | no | Postal / ZIP code. Required unless the destination country has no postal codes (e.g. HK, AE). Max 20 characters. | | `recipient.country_code` | string | yes | ISO 3166-1 alpha-2 country code. Pattern `^[A-Za-z]{2}$`. | | `recipient.phone` | string \| null | no | Max 40 characters. | | `recipient.tax_id` | string \| null | no | Recipient tax id required by customs for some destinations, e.g. the CPF/CNPJ for Brazil. Write-only (never returned). Max 40 characters. | | `recipient.email` | string \| null | no | Used for delivery notifications (if you enable them). An empty string means no email. Max 254 characters. Email address. | | `shipping_method` | string | no | One of: `economy`, `standard`, `express`, `priority`. | | `items` | array of OrderItemInput | no | Replaces all items. 1–100 items. | | `items[].product_variant_id` | string | no | One of your product variants. 1–100 characters. | | `items[].sku` | string | no | Or your product variant SKU. 1–64 characters. | | `items[].catalog_variant_id` | string | no | Or a catalog variant with inline `designs` (on-the-fly personalization). 1–100 characters. | | `items[].designs` | array of DesignInput | no | Required with catalog_variant_id. 1–20 items. | | `items[].designs[].placement` | string | yes | Placement key from the catalog product (e.g. front, back). 1–64 characters. | | `items[].designs[].layers` | array of DesignLayerInput | yes | 1–20 items. | | `items[].designs[].layers[].file_id` | string | no | Id of an uploaded artwork file. 1–100 characters. | | `items[].designs[].layers[].url` | string | no | Or a public image URL; we download it into a new artwork file. Max 2048 characters. Must be an http(s) URL. | | `items[].designs[].layers[].position` | Position | no | Where the artwork sits inside the placement's print area. Fractions of the print area (0–1; values outside allow intentional bleed). Omit to center the artwork and fit it inside the area. | | `items[].designs[].layers[].position.x` | number | yes | Left edge of the artwork box as a fraction of the print area width. Range -10–10. | | `items[].designs[].layers[].position.y` | number | yes | Top edge of the artwork box as a fraction of the print area height. Range -10–10. | | `items[].designs[].layers[].position.width` | number | yes | Artwork width as a fraction of the print area width. Range >0–10. | | `items[].designs[].layers[].position.height` | number | yes | Artwork height as a fraction of the print area height. Range >0–10. | | `items[].designs[].layers[].position.rotation` | number | no | Clockwise rotation in degrees around the artwork center. Range -3600–3600. Default `0`. | | `items[].designs[].layers[].transform` | Position | no | Alias of `position` (as returned on products and orders). | | `items[].designs[].layers[].transform.x` | number | yes | Left edge of the artwork box as a fraction of the print area width. Range -10–10. | | `items[].designs[].layers[].transform.y` | number | yes | Top edge of the artwork box as a fraction of the print area height. Range -10–10. | | `items[].designs[].layers[].transform.width` | number | yes | Artwork width as a fraction of the print area width. Range >0–10. | | `items[].designs[].layers[].transform.height` | number | yes | Artwork height as a fraction of the print area height. Range >0–10. | | `items[].designs[].layers[].transform.rotation` | number | no | Clockwise rotation in degrees around the artwork center. Range -3600–3600. Default `0`. | | `items[].designs[].layers[].opacity` | number | no | 0–1 (default 1). Range 0–1. | | `items[].quantity` | integer | yes | Units of this item (at most 1000 per line). Range 1–1000. | | `items[].external_line_id` | string \| null | no | Your line item id. 1–128 characters. | | `items[].metadata` | map of string | no | Up to 50 key/value pairs (keys ≤ 40 chars, string values ≤ 500 chars) for your own references. Never store sensitive data here. | | `items[].retail_price` | integer \| null | no | What YOUR customer paid per unit (cents). Printed on international packing slips and declared for customs instead of our price. Default: the product variant's (or product's) retail price. Range 0–100000000. | | `packing_slip` | PackingSlipInput | no | — | | `packing_slip.message` | string \| null | no | Max 500 characters. | | `packing_slip.brand_name` | string \| null | no | Overrides your account brand name on the packing slip. Max 100 characters. | | `packing_slip.logo_file_id` | string \| null | no | An uploaded logo/artwork file to print instead of your account logo. 1–100 characters. | | `packing_slip.customer_order_number` | string \| null | no | Max 64 characters. | | `gift_message` | string \| null | no | Max 500 characters. | | `customer_note` | string \| null | no | Max 1000 characters. | | `metadata` | map of string | no | Up to 50 key/value pairs (keys ≤ 40 chars, string values ≤ 500 chars) for your own references. Never store sensitive data here. | **Returns** `200` — The updated order. [Order](https://swaglists.com/docs/objects.md#order) | Field | Type | Description | | --- | --- | --- | | `object` | "order" | Type of the object: always `order`. | | `id` | string | Unique identifier (starts with `ord_`). | | `number` | integer | Sequential human-friendly order number. | | `external_id` | string \| null | Your order id (unique per mode). Look the order up with `GET /orders/ext:`. | | `livemode` | boolean | `true` in live mode, `false` in test mode. | | `status` | string | draft → processing → in_production → (partially_)shipped → delivered; on_hold (see hold_reason), canceled, failed. One of: `draft`, `on_hold`, `processing`, `in_production`, `partially_shipped`, `shipped`, `delivered`, `canceled`, `failed`. | | `hold_reason` | string \| null | Why the order is on hold; only set while `status` is `on_hold`. One of: `insufficient_funds`, `manual_review`, `artwork_issue`, `address_issue`, `fulfillment_issue`. | | `funds_status` | string | State of the credits for this order: `none` (draft), `awaiting` (on hold for credits), `held` (reserved), `partially_captured`/`captured` (spent), `released` (returned unspent), `partially_refunded`/`refunded`. One of: `none`, `awaiting`, `held`, `partially_captured`, `captured`, `released`, `partially_refunded`, `refunded`. | | `source` | string | Where the order was created. One of: `api`, `dashboard`, `import`, `admin`. | | `recipient` | [Recipient](https://swaglists.com/docs/objects.md#recipient) | Shipping address of the end customer. | | `shipping_method` | string | Shipping speed of the order. One of: `economy`, `standard`, `express`, `priority`. | | `currency` | string | Three-letter currency code, lowercase (`usd`). | | `subtotal` | integer | Items total in cents. | | `shipping` | integer | Shipping price in cents. | | `tax` | integer | Tax in cents (0 unless tax applies to the destination). | | `discount` | integer | Discount in cents. | | `total` | integer | Credits charged for this order (cents). | | `refunded` | integer | Credits refunded to your wallet for this order, in cents. | | `items` | array of [OrderItem](https://swaglists.com/docs/objects.md#order_item) | Line items of the order. | | `shipments` | array of [Shipment](https://swaglists.com/docs/objects.md#shipment) | Parcels shipped so far (an order can ship in several parcels). | | `tracking_page_url` | string \| null | Your branded tracking page for the end customer. null while the order is a draft (the page exists once it is confirmed). | | `packing_slip` | object \| null | Packing slip overrides of this order (null when none were sent). | | `gift_message` | string \| null | Gift message included with the parcel. | | `customer_note` | string \| null | Note from your customer. | | `metadata` | map of string | Your key/value pairs (string values). | | `created_at` | string \| null | When the object was created (ISO-8601, UTC). | | `updated_at` | string \| null | When the object was last changed (ISO-8601, UTC). | | `placed_at` | string \| null | When the order was confirmed (credits reserved, or the order put on hold for funds). | | `in_production_at` | string \| null | When production started. | | `shipped_at` | string \| null | When the order shipped. | | `delivered_at` | string \| null | When every shipment was delivered. | | `canceled_at` | string \| null | When the order was canceled. | | `cancel_reason` | string \| null | Reason given when the order was canceled. | | `failed_at` | string \| null | When the order failed. | | `failure_reason` | string \| null | Why the order failed (reserved credits were released). | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid), [`variant_unavailable`](https://swaglists.com/docs/errors.md#variant_unavailable), [`variant_disabled`](https://swaglists.com/docs/errors.md#variant_disabled), [`product_archived`](https://swaglists.com/docs/errors.md#product_archived), [`product_has_no_designs`](https://swaglists.com/docs/errors.md#product_has_no_designs), [`placement_required`](https://swaglists.com/docs/errors.md#placement_required), [`unknown_placement`](https://swaglists.com/docs/errors.md#unknown_placement), [`file_not_artwork`](https://swaglists.com/docs/errors.md#file_not_artwork), [`file_not_ready`](https://swaglists.com/docs/errors.md#file_not_ready), [`file_not_image`](https://swaglists.com/docs/errors.md#file_not_image), [`design_not_visible`](https://swaglists.com/docs/errors.md#design_not_visible), [`artwork_resolution_too_low`](https://swaglists.com/docs/errors.md#artwork_resolution_too_low), [`file_download_failed`](https://swaglists.com/docs/errors.md#file_download_failed), [`download_failed`](https://swaglists.com/docs/errors.md#download_failed), [`download_not_an_image`](https://swaglists.com/docs/errors.md#download_not_an_image), [`download_timeout`](https://swaglists.com/docs/errors.md#download_timeout), [`file_too_large`](https://swaglists.com/docs/errors.md#file_too_large), [`file_invalid`](https://swaglists.com/docs/errors.md#file_invalid), [`file_unsupported_type`](https://swaglists.com/docs/errors.md#file_unsupported_type), [`file_unsafe`](https://swaglists.com/docs/errors.md#file_unsafe), [`item_unavailable`](https://swaglists.com/docs/errors.md#item_unavailable), [`shipping_method_unavailable`](https://swaglists.com/docs/errors.md#shipping_method_unavailable), [`variant_unpriceable`](https://swaglists.com/docs/errors.md#variant_unpriceable) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 409 | [`idempotency_key_reused`](https://swaglists.com/docs/errors.md#idempotency_key_reused), [`idempotency_in_progress`](https://swaglists.com/docs/errors.md#idempotency_in_progress), [`order_not_editable`](https://swaglists.com/docs/errors.md#order_not_editable), [`duplicate_external_id`](https://swaglists.com/docs/errors.md#duplicate_external_id) | | 413 | [`request_too_large`](https://swaglists.com/docs/errors.md#request_too_large) | | 415 | [`unsupported_media_type`](https://swaglists.com/docs/errors.md#unsupported_media_type) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl -X PATCH https://swaglists.com/api/v1/orders/ord_01k8x4b2q9w7e3r5t1y8u6i0pa \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "shipping_method": "express" }' ``` **Example response** ```json { "object": "order", "id": "ord_01k8x4b2q9w7e3r5t1y8u6i0pa", "number": 1042, "external_id": "1042", "livemode": true, "status": "shipped", "hold_reason": null, "funds_status": "captured", "source": "api", "recipient": { "name": "Jane Doe", "company": null, "address1": "123 Market St", "address2": "Apt 4", "city": "San Francisco", "state_code": "CA", "postal_code": "94107", "country_code": "US", "phone": null, "email": "jane@example.com" }, "shipping_method": "standard", "currency": "usd", "subtotal": 2598, "shipping": 700, "tax": 0, "discount": 0, "total": 3298, "refunded": 0, "items": [ { "object": "order_item", "id": "oi_01k8x4b2qa3s5d7f9g1h3j5k7l", "product_id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "product_variant_id": "pvar_01k8x3z7r4f6g8h0j2k4l6z8x0", "catalog_product_id": "cp_01k8w1a2s3d4f5g6h7j8k9m0n1", "catalog_variant_id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "sku": "CA-TEE-BLK-M", "title": "Company A Logo Tee", "variant_title": "Black / M", "quantity": 2, "shipped_quantity": 2, "unit_price": 1299, "total_price": 2598, "retail_price": 2500, "status": "shipped", "designs": [ { "placement": "front", "layers": [ { "file_id": "file_01k8x3y1q3w5e7r9t1y3u5i7o9", "transform": { "x": 0.1, "y": 0.05, "width": 0.8, "height": 0.6, "rotation": 0 }, "opacity": 1 } ] } ], "mockup_url": null, "external_line_id": "line-1", "metadata": {} } ], "shipments": [ { "object": "shipment", "id": "shp_01k8x9z1m3n5b7v9c1x3z5a7s9", "order_id": "ord_01k8x4b2q9w7e3r5t1y8u6i0pa", "status": "in_transit", "carrier": "usps", "service": "USPS Ground Advantage", "tracking_number": "9400111899223197428490", "tracking_url": "https://tools.usps.com/go/TrackConfirmAction?tLabels=9400111899223197428490", "items": [ { "order_item_id": "oi_01k8x4b2qa3s5d7f9g1h3j5k7l", "quantity": 2 } ], "shipped_at": "2026-10-23T09:12:44.000Z", "estimated_delivery_at": null, "delivered_at": null, "created_at": "2026-10-23T09:12:44.000Z" } ], "tracking_page_url": "https://swaglists.com/track/Zx81kLm2pQ", "packing_slip": { "message": "Thanks for shopping with Company A!", "brand_name": null, "logo_file_id": null, "customer_order_number": "#1042" }, "gift_message": null, "customer_note": null, "metadata": {}, "created_at": "2026-10-21T14:32:05.000Z", "updated_at": "2026-10-23T09:12:44.000Z", "placed_at": "2026-10-21T14:32:05.000Z", "in_production_at": "2026-10-21T14:32:05.000Z", "shipped_at": "2026-10-23T09:12:44.000Z", "delivered_at": null, "canceled_at": null, "cancel_reason": null, "failed_at": null, "failure_reason": null } ``` ### Confirm a draft, or release an order waiting for credits `POST /orders/{id}/confirm` Draft: reserves the order total from your wallet and starts production (or puts the order on hold for funds). Order on hold for insufficient credits (`hold_reason: insufficient_funds`): reserves its total now and releases it to production — answers 402 `insufficient_funds` (order unchanged) if your available credits still don't cover it. Use this to release orders when your account uses manual release (`insufficient_funds_behavior: hold_manual`). Nothing is ever sent to production without its credits reserved. Requires scope `orders:write`. **Scope:** `orders:write` · **Idempotency:** send an `Idempotency-Key` header **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | Order id, or "ext:" + your external_id (e.g. ext:1042). 1–300 characters. | **Returns** `200` — The confirmed order. [Order](https://swaglists.com/docs/objects.md#order) | Field | Type | Description | | --- | --- | --- | | `object` | "order" | Type of the object: always `order`. | | `id` | string | Unique identifier (starts with `ord_`). | | `number` | integer | Sequential human-friendly order number. | | `external_id` | string \| null | Your order id (unique per mode). Look the order up with `GET /orders/ext:`. | | `livemode` | boolean | `true` in live mode, `false` in test mode. | | `status` | string | draft → processing → in_production → (partially_)shipped → delivered; on_hold (see hold_reason), canceled, failed. One of: `draft`, `on_hold`, `processing`, `in_production`, `partially_shipped`, `shipped`, `delivered`, `canceled`, `failed`. | | `hold_reason` | string \| null | Why the order is on hold; only set while `status` is `on_hold`. One of: `insufficient_funds`, `manual_review`, `artwork_issue`, `address_issue`, `fulfillment_issue`. | | `funds_status` | string | State of the credits for this order: `none` (draft), `awaiting` (on hold for credits), `held` (reserved), `partially_captured`/`captured` (spent), `released` (returned unspent), `partially_refunded`/`refunded`. One of: `none`, `awaiting`, `held`, `partially_captured`, `captured`, `released`, `partially_refunded`, `refunded`. | | `source` | string | Where the order was created. One of: `api`, `dashboard`, `import`, `admin`. | | `recipient` | [Recipient](https://swaglists.com/docs/objects.md#recipient) | Shipping address of the end customer. | | `shipping_method` | string | Shipping speed of the order. One of: `economy`, `standard`, `express`, `priority`. | | `currency` | string | Three-letter currency code, lowercase (`usd`). | | `subtotal` | integer | Items total in cents. | | `shipping` | integer | Shipping price in cents. | | `tax` | integer | Tax in cents (0 unless tax applies to the destination). | | `discount` | integer | Discount in cents. | | `total` | integer | Credits charged for this order (cents). | | `refunded` | integer | Credits refunded to your wallet for this order, in cents. | | `items` | array of [OrderItem](https://swaglists.com/docs/objects.md#order_item) | Line items of the order. | | `shipments` | array of [Shipment](https://swaglists.com/docs/objects.md#shipment) | Parcels shipped so far (an order can ship in several parcels). | | `tracking_page_url` | string \| null | Your branded tracking page for the end customer. null while the order is a draft (the page exists once it is confirmed). | | `packing_slip` | object \| null | Packing slip overrides of this order (null when none were sent). | | `gift_message` | string \| null | Gift message included with the parcel. | | `customer_note` | string \| null | Note from your customer. | | `metadata` | map of string | Your key/value pairs (string values). | | `created_at` | string \| null | When the object was created (ISO-8601, UTC). | | `updated_at` | string \| null | When the object was last changed (ISO-8601, UTC). | | `placed_at` | string \| null | When the order was confirmed (credits reserved, or the order put on hold for funds). | | `in_production_at` | string \| null | When production started. | | `shipped_at` | string \| null | When the order shipped. | | `delivered_at` | string \| null | When every shipment was delivered. | | `canceled_at` | string \| null | When the order was canceled. | | `cancel_reason` | string \| null | Reason given when the order was canceled. | | `failed_at` | string \| null | When the order failed. | | `failure_reason` | string \| null | Why the order failed (reserved credits were released). | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid), [`item_unavailable`](https://swaglists.com/docs/errors.md#item_unavailable) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 402 | [`insufficient_funds`](https://swaglists.com/docs/errors.md#insufficient_funds) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 409 | [`idempotency_key_reused`](https://swaglists.com/docs/errors.md#idempotency_key_reused), [`idempotency_in_progress`](https://swaglists.com/docs/errors.md#idempotency_in_progress), [`order_not_draft`](https://swaglists.com/docs/errors.md#order_not_draft), [`order_not_confirmable`](https://swaglists.com/docs/errors.md#order_not_confirmable) | | 413 | [`request_too_large`](https://swaglists.com/docs/errors.md#request_too_large) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl -X POST https://swaglists.com/api/v1/orders/ord_01k8x4b2q9w7e3r5t1y8u6i0pa/confirm \ -H "Authorization: Bearer $API_KEY" \ -H "Idempotency-Key: $(uuidgen)" ``` **Example response** ```json { "object": "order", "id": "ord_01k8x4b2q9w7e3r5t1y8u6i0pa", "number": 1042, "external_id": "1042", "livemode": true, "status": "shipped", "hold_reason": null, "funds_status": "captured", "source": "api", "recipient": { "name": "Jane Doe", "company": null, "address1": "123 Market St", "address2": "Apt 4", "city": "San Francisco", "state_code": "CA", "postal_code": "94107", "country_code": "US", "phone": null, "email": "jane@example.com" }, "shipping_method": "standard", "currency": "usd", "subtotal": 2598, "shipping": 700, "tax": 0, "discount": 0, "total": 3298, "refunded": 0, "items": [ { "object": "order_item", "id": "oi_01k8x4b2qa3s5d7f9g1h3j5k7l", "product_id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "product_variant_id": "pvar_01k8x3z7r4f6g8h0j2k4l6z8x0", "catalog_product_id": "cp_01k8w1a2s3d4f5g6h7j8k9m0n1", "catalog_variant_id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "sku": "CA-TEE-BLK-M", "title": "Company A Logo Tee", "variant_title": "Black / M", "quantity": 2, "shipped_quantity": 2, "unit_price": 1299, "total_price": 2598, "retail_price": 2500, "status": "shipped", "designs": [ { "placement": "front", "layers": [ { "file_id": "file_01k8x3y1q3w5e7r9t1y3u5i7o9", "transform": { "x": 0.1, "y": 0.05, "width": 0.8, "height": 0.6, "rotation": 0 }, "opacity": 1 } ] } ], "mockup_url": null, "external_line_id": "line-1", "metadata": {} } ], "shipments": [ { "object": "shipment", "id": "shp_01k8x9z1m3n5b7v9c1x3z5a7s9", "order_id": "ord_01k8x4b2q9w7e3r5t1y8u6i0pa", "status": "in_transit", "carrier": "usps", "service": "USPS Ground Advantage", "tracking_number": "9400111899223197428490", "tracking_url": "https://tools.usps.com/go/TrackConfirmAction?tLabels=9400111899223197428490", "items": [ { "order_item_id": "oi_01k8x4b2qa3s5d7f9g1h3j5k7l", "quantity": 2 } ], "shipped_at": "2026-10-23T09:12:44.000Z", "estimated_delivery_at": null, "delivered_at": null, "created_at": "2026-10-23T09:12:44.000Z" } ], "tracking_page_url": "https://swaglists.com/track/Zx81kLm2pQ", "packing_slip": { "message": "Thanks for shopping with Company A!", "brand_name": null, "logo_file_id": null, "customer_order_number": "#1042" }, "gift_message": null, "customer_note": null, "metadata": {}, "created_at": "2026-10-21T14:32:05.000Z", "updated_at": "2026-10-23T09:12:44.000Z", "placed_at": "2026-10-21T14:32:05.000Z", "in_production_at": "2026-10-21T14:32:05.000Z", "shipped_at": "2026-10-23T09:12:44.000Z", "delivered_at": null, "canceled_at": null, "cancel_reason": null, "failed_at": null, "failure_reason": null } ``` ### Cancel an order `POST /orders/{id}/cancel` Cancels an order that has not gone into production yet. Reserved credits are released and captured credits refunded to your wallet. Orders in production or shipped cannot be canceled (409). Requires scope `orders:write`. **Scope:** `orders:write` · **Idempotency:** send an `Idempotency-Key` header **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | Order id, or "ext:" + your external_id (e.g. ext:1042). 1–300 characters. | **Request body** (`application/json`, optional) — CancelOrderRequest | Field | Type | Required | Description | | --- | --- | --- | --- | | `reason` | string \| null | no | 1–500 characters. | **Returns** `200` — The canceled order. [Order](https://swaglists.com/docs/objects.md#order) | Field | Type | Description | | --- | --- | --- | | `object` | "order" | Type of the object: always `order`. | | `id` | string | Unique identifier (starts with `ord_`). | | `number` | integer | Sequential human-friendly order number. | | `external_id` | string \| null | Your order id (unique per mode). Look the order up with `GET /orders/ext:`. | | `livemode` | boolean | `true` in live mode, `false` in test mode. | | `status` | string | draft → processing → in_production → (partially_)shipped → delivered; on_hold (see hold_reason), canceled, failed. One of: `draft`, `on_hold`, `processing`, `in_production`, `partially_shipped`, `shipped`, `delivered`, `canceled`, `failed`. | | `hold_reason` | string \| null | Why the order is on hold; only set while `status` is `on_hold`. One of: `insufficient_funds`, `manual_review`, `artwork_issue`, `address_issue`, `fulfillment_issue`. | | `funds_status` | string | State of the credits for this order: `none` (draft), `awaiting` (on hold for credits), `held` (reserved), `partially_captured`/`captured` (spent), `released` (returned unspent), `partially_refunded`/`refunded`. One of: `none`, `awaiting`, `held`, `partially_captured`, `captured`, `released`, `partially_refunded`, `refunded`. | | `source` | string | Where the order was created. One of: `api`, `dashboard`, `import`, `admin`. | | `recipient` | [Recipient](https://swaglists.com/docs/objects.md#recipient) | Shipping address of the end customer. | | `shipping_method` | string | Shipping speed of the order. One of: `economy`, `standard`, `express`, `priority`. | | `currency` | string | Three-letter currency code, lowercase (`usd`). | | `subtotal` | integer | Items total in cents. | | `shipping` | integer | Shipping price in cents. | | `tax` | integer | Tax in cents (0 unless tax applies to the destination). | | `discount` | integer | Discount in cents. | | `total` | integer | Credits charged for this order (cents). | | `refunded` | integer | Credits refunded to your wallet for this order, in cents. | | `items` | array of [OrderItem](https://swaglists.com/docs/objects.md#order_item) | Line items of the order. | | `shipments` | array of [Shipment](https://swaglists.com/docs/objects.md#shipment) | Parcels shipped so far (an order can ship in several parcels). | | `tracking_page_url` | string \| null | Your branded tracking page for the end customer. null while the order is a draft (the page exists once it is confirmed). | | `packing_slip` | object \| null | Packing slip overrides of this order (null when none were sent). | | `gift_message` | string \| null | Gift message included with the parcel. | | `customer_note` | string \| null | Note from your customer. | | `metadata` | map of string | Your key/value pairs (string values). | | `created_at` | string \| null | When the object was created (ISO-8601, UTC). | | `updated_at` | string \| null | When the object was last changed (ISO-8601, UTC). | | `placed_at` | string \| null | When the order was confirmed (credits reserved, or the order put on hold for funds). | | `in_production_at` | string \| null | When production started. | | `shipped_at` | string \| null | When the order shipped. | | `delivered_at` | string \| null | When every shipment was delivered. | | `canceled_at` | string \| null | When the order was canceled. | | `cancel_reason` | string \| null | Reason given when the order was canceled. | | `failed_at` | string \| null | When the order failed. | | `failure_reason` | string \| null | Why the order failed (reserved credits were released). | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 409 | [`idempotency_key_reused`](https://swaglists.com/docs/errors.md#idempotency_key_reused), [`idempotency_in_progress`](https://swaglists.com/docs/errors.md#idempotency_in_progress), [`order_not_cancelable`](https://swaglists.com/docs/errors.md#order_not_cancelable) | | 413 | [`request_too_large`](https://swaglists.com/docs/errors.md#request_too_large) | | 415 | [`unsupported_media_type`](https://swaglists.com/docs/errors.md#unsupported_media_type) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl -X POST https://swaglists.com/api/v1/orders/ord_01k8x4b2q9w7e3r5t1y8u6i0pa/cancel \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "reason": "Customer changed their mind" }' ``` **Example response** ```json { "object": "order", "id": "ord_01k8x4b2q9w7e3r5t1y8u6i0pa", "number": 1042, "external_id": "1042", "livemode": true, "status": "shipped", "hold_reason": null, "funds_status": "captured", "source": "api", "recipient": { "name": "Jane Doe", "company": null, "address1": "123 Market St", "address2": "Apt 4", "city": "San Francisco", "state_code": "CA", "postal_code": "94107", "country_code": "US", "phone": null, "email": "jane@example.com" }, "shipping_method": "standard", "currency": "usd", "subtotal": 2598, "shipping": 700, "tax": 0, "discount": 0, "total": 3298, "refunded": 0, "items": [ { "object": "order_item", "id": "oi_01k8x4b2qa3s5d7f9g1h3j5k7l", "product_id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "product_variant_id": "pvar_01k8x3z7r4f6g8h0j2k4l6z8x0", "catalog_product_id": "cp_01k8w1a2s3d4f5g6h7j8k9m0n1", "catalog_variant_id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "sku": "CA-TEE-BLK-M", "title": "Company A Logo Tee", "variant_title": "Black / M", "quantity": 2, "shipped_quantity": 2, "unit_price": 1299, "total_price": 2598, "retail_price": 2500, "status": "shipped", "designs": [ { "placement": "front", "layers": [ { "file_id": "file_01k8x3y1q3w5e7r9t1y3u5i7o9", "transform": { "x": 0.1, "y": 0.05, "width": 0.8, "height": 0.6, "rotation": 0 }, "opacity": 1 } ] } ], "mockup_url": null, "external_line_id": "line-1", "metadata": {} } ], "shipments": [ { "object": "shipment", "id": "shp_01k8x9z1m3n5b7v9c1x3z5a7s9", "order_id": "ord_01k8x4b2q9w7e3r5t1y8u6i0pa", "status": "in_transit", "carrier": "usps", "service": "USPS Ground Advantage", "tracking_number": "9400111899223197428490", "tracking_url": "https://tools.usps.com/go/TrackConfirmAction?tLabels=9400111899223197428490", "items": [ { "order_item_id": "oi_01k8x4b2qa3s5d7f9g1h3j5k7l", "quantity": 2 } ], "shipped_at": "2026-10-23T09:12:44.000Z", "estimated_delivery_at": null, "delivered_at": null, "created_at": "2026-10-23T09:12:44.000Z" } ], "tracking_page_url": "https://swaglists.com/track/Zx81kLm2pQ", "packing_slip": { "message": "Thanks for shopping with Company A!", "brand_name": null, "logo_file_id": null, "customer_order_number": "#1042" }, "gift_message": null, "customer_note": null, "metadata": {}, "created_at": "2026-10-21T14:32:05.000Z", "updated_at": "2026-10-23T09:12:44.000Z", "placed_at": "2026-10-21T14:32:05.000Z", "in_production_at": "2026-10-21T14:32:05.000Z", "shipped_at": "2026-10-23T09:12:44.000Z", "delivered_at": null, "canceled_at": null, "cancel_reason": null, "failed_at": null, "failure_reason": null } ``` ### List order events `GET /orders/{id}/events` The order timeline (created, confirmed, in production, shipped, …), oldest first. Requires scope `orders:read`. **Scope:** `orders:read` **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | Order id, or "ext:" + your external_id (e.g. ext:1042). 1–300 characters. | **Returns** `200` — Order events. [OrderEventList](https://swaglists.com/docs/objects.md#list) | Field | Type | Description | | --- | --- | --- | | `object` | "list" | Always `list`. | | `data` | array of [OrderEvent](https://swaglists.com/docs/objects.md#order_event) | The objects of this page. | | `has_more` | boolean | Whether more items exist beyond this page (in the paging direction). | | `url` | string | Path of this list endpoint. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl https://swaglists.com/api/v1/orders/ord_01k8x4b2q9w7e3r5t1y8u6i0pa/events \ -H "Authorization: Bearer $API_KEY" ``` **Example response** ```json { "object": "list", "data": [ { "object": "order_event", "id": "oev_01k8x4b2qc5v7b9n1m3k5j7h9g", "type": "status_changed", "message": "Order is in production", "from_status": "processing", "to_status": "in_production", "created_at": "2026-10-21T14:32:05.000Z" } ], "has_more": false, "url": "/api/v1/orders/ord_01k8x4b2q9w7e3r5t1y8u6i0pa/events" } ``` ## Wallet Prepaid credits: balance, transactions and top-ups. ### Retrieve the wallet `GET /wallet` Credit balance of the key's mode (test mode has its own wallet with free test credits). Requires scope `wallet:read`. **Scope:** `wallet:read` **Returns** `200` — The wallet. [Wallet](https://swaglists.com/docs/objects.md#wallet) | Field | Type | Description | | --- | --- | --- | | `object` | "wallet" | Type of the object: always `wallet`. | | `mode` | string | `live` or `test`. One of: `live`, `test`. | | `livemode` | boolean | `true` in live mode, `false` in test mode. | | `currency` | string | Three-letter currency code, lowercase (`usd`). | | `available` | integer | Spendable credits in cents. May be negative after a payment dispute. | | `held` | integer | Credits reserved for in-flight orders, in cents. | | `total` | integer | available + held, in cents. | | `low_balance_threshold` | integer \| null | Low-balance notification threshold in cents. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl https://swaglists.com/api/v1/wallet \ -H "Authorization: Bearer $API_KEY" ``` **Example response** ```json { "object": "wallet", "mode": "live", "livemode": true, "currency": "usd", "available": 482550, "held": 12480, "total": 495030, "low_balance_threshold": 10000 } ``` ### List wallet transactions `GET /wallet/transactions` Every balance change (top-ups, bonuses, holds, captures, refunds, adjustments), newest first. Requires scope `wallet:read`. **Scope:** `wallet:read` **Query parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `limit` | integer | no | Number of objects to return, 1–100 (default 20). Range 1–100. | | `starting_after` | string | no | Cursor for the next page: the id of the last object of the previous page. 1–255 characters. | | `ending_before` | string | no | Cursor for the previous page: the id of the first object of the current page. 1–255 characters. | | `type` | string | no | Filter by transaction type. One of: `topup`, `bonus`, `hold`, `release`, `capture`, `charge`, `refund`, `adjustment`, `reversal`, `test_credit`. | | `order_id` | string | no | Only transactions of this order. 1–100 characters. | **Returns** `200` — A page of transactions. [TransactionList](https://swaglists.com/docs/objects.md#list) | Field | Type | Description | | --- | --- | --- | | `object` | "list" | Always `list`. | | `data` | array of [Transaction](https://swaglists.com/docs/objects.md#transaction) | The objects of this page. | | `has_more` | boolean | Whether more items exist beyond this page (in the paging direction). | | `url` | string | Path of this list endpoint. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl "https://swaglists.com/api/v1/wallet/transactions?limit=3" \ -H "Authorization: Bearer $API_KEY" ``` **Example response** ```json { "object": "list", "data": [ { "object": "transaction", "id": "txn_01k8x4b2q8w0e2r4t6y8u0i2o4", "type": "hold", "amount": -2598, "held_delta": 2598, "balance_after": 479952, "currency": "usd", "description": "Credits reserved for order ord_01k8x4b2q9w7e3r5t1y8u6i0pa", "order_id": "ord_01k8x4b2q9w7e3r5t1y8u6i0pa", "topup_id": null, "created_at": "2026-10-21T14:32:05.000Z" } ], "has_more": false, "url": "/api/v1/wallet/transactions" } ``` ### List top-ups `GET /topups` Credit purchases (made in the dashboard), newest first. Top-ups are live-mode only; test keys get an empty list. Requires scope `wallet:read`. **Scope:** `wallet:read` **Query parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `limit` | integer | no | Number of objects to return, 1–100 (default 20). Range 1–100. | | `starting_after` | string | no | Cursor for the next page: the id of the last object of the previous page. 1–255 characters. | | `ending_before` | string | no | Cursor for the previous page: the id of the first object of the current page. 1–255 characters. | **Returns** `200` — A page of top-ups. [TopupList](https://swaglists.com/docs/objects.md#list) | Field | Type | Description | | --- | --- | --- | | `object` | "list" | Always `list`. | | `data` | array of [Topup](https://swaglists.com/docs/objects.md#topup) | The objects of this page. | | `has_more` | boolean | Whether more items exist beyond this page (in the paging direction). | | `url` | string | Path of this list endpoint. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl "https://swaglists.com/api/v1/topups?limit=3" \ -H "Authorization: Bearer $API_KEY" ``` **Example response** ```json { "object": "list", "data": [ { "object": "topup", "id": "top_01k8x1q3w5e7r9t1y3u5i7o9p1", "status": "succeeded", "amount": 500000, "bonus": 25000, "bonus_percent": 5, "credits": 525000, "currency": "usd", "payment_method_type": "us_bank_account", "receipt_url": null, "created_at": "2026-10-21T14:32:05.000Z", "succeeded_at": "2026-10-21T14:32:05.000Z" } ], "has_more": false, "url": "/api/v1/topups" } ``` ### Retrieve a top-up `GET /topups/{id}` Requires scope `wallet:read`. **Scope:** `wallet:read` **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | Top-up id. 1–300 characters. | **Returns** `200` — The top-up. [Topup](https://swaglists.com/docs/objects.md#topup) | Field | Type | Description | | --- | --- | --- | | `object` | "topup" | Type of the object: always `topup`. | | `id` | string | Unique identifier (starts with `top_`). | | `status` | string | Payment status of the top-up. One of: `pending`, `processing`, `succeeded`, `failed`, `canceled`, `refunded`, `partially_refunded`, `disputed`. | | `amount` | integer | Amount paid (cents). | | `bonus` | integer | Bonus credits granted (cents). | | `bonus_percent` | number | Bonus percentage, e.g. 5 for 5%. | | `credits` | integer | Credits added = amount + bonus (cents). | | `currency` | string | Three-letter currency code, lowercase (`usd`). | | `payment_method_type` | string \| null | How it was paid (e.g. `card`, `us_bank_account`). | | `receipt_url` | string \| null | Payment receipt, when available. | | `created_at` | string | When the object was created (ISO-8601, UTC). | | `succeeded_at` | string \| null | When the credits were added. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl https://swaglists.com/api/v1/topups/top_01k8x1q3w5e7r9t1y3u5i7o9p1 \ -H "Authorization: Bearer $API_KEY" ``` **Example response** ```json { "object": "topup", "id": "top_01k8x1q3w5e7r9t1y3u5i7o9p1", "status": "succeeded", "amount": 500000, "bonus": 25000, "bonus_percent": 5, "credits": 525000, "currency": "usd", "payment_method_type": "us_bank_account", "receipt_url": null, "created_at": "2026-10-21T14:32:05.000Z", "succeeded_at": "2026-10-21T14:32:05.000Z" } ``` ## Webhooks Endpoints we notify about events (Standard Webhooks signatures). ### List webhook endpoints `GET /webhook_endpoints` Endpoints of the key's mode, newest first. Requires scope `webhooks:read`. **Scope:** `webhooks:read` **Query parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `limit` | integer | no | Number of objects to return, 1–100 (default 20). Range 1–100. | | `starting_after` | string | no | Cursor for the next page: the id of the last object of the previous page. 1–255 characters. | | `ending_before` | string | no | Cursor for the previous page: the id of the first object of the current page. 1–255 characters. | | `status` | string | no | Filter by status. One of: `enabled`, `disabled`. | **Returns** `200` — A page of endpoints. [WebhookEndpointList](https://swaglists.com/docs/objects.md#list) | Field | Type | Description | | --- | --- | --- | | `object` | "list" | Always `list`. | | `data` | array of [WebhookEndpoint](https://swaglists.com/docs/objects.md#webhook_endpoint) | The objects of this page. | | `has_more` | boolean | Whether more items exist beyond this page (in the paging direction). | | `url` | string | Path of this list endpoint. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl "https://swaglists.com/api/v1/webhook_endpoints?limit=3" \ -H "Authorization: Bearer $API_KEY" ``` **Example response** ```json { "object": "list", "data": [ { "object": "webhook_endpoint", "id": "we_01k8x2m4n6b8v0c2x4z6a8s0d2", "url": "https://company-a.example/webhooks/print", "description": "Production order updates", "enabled_events": [ "order.shipped", "order.delivered" ], "status": "enabled", "disabled_reason": null, "mode": "live", "livemode": true, "created_at": "2026-10-21T14:32:05.000Z" } ], "has_more": false, "url": "/api/v1/webhook_endpoints" } ``` ### Create a webhook endpoint `POST /webhook_endpoints` Registers a URL for events of the key's mode. Live endpoints must use HTTPS on a public host. The response contains the signing `secret` (whsec_…) — this is the only time it is shown. Requires scope `webhooks:write`. **Scope:** `webhooks:write` · **Idempotency:** send an `Idempotency-Key` header **Request body** (`application/json`) — CreateWebhookEndpointRequest | Field | Type | Required | Description | | --- | --- | --- | --- | | `url` | string | yes | HTTPS URL (test mode also allows http). 1–2048 characters. | | `enabled_events` | array of string | no | Event types to receive, or ["*"] for all. Available: order.created, order.updated, order.confirmed, order.on_hold, order.processing, order.in_production, order.partially_shipped, order.shipped, order.delivered, order.canceled, order.failed, order.refunded, shipment.created, shipment.updated, shipment.delivered, product.created, product.updated, product.deleted, catalog.price_changed, wallet.credited, wallet.low_balance, topup.succeeded, topup.failed, file.processed. 1–200 items. | | `description` | string \| null | no | Max 500 characters. | **Returns** `201` — The endpoint, including its secret. [WebhookEndpoint](https://swaglists.com/docs/objects.md#webhook_endpoint) | Field | Type | Description | | --- | --- | --- | | `object` | "webhook_endpoint" | Type of the object: always `webhook_endpoint`. | | `id` | string | Unique identifier (starts with `we_`). | | `url` | string | URL we POST events to. | | `description` | string \| null | Your description. | | `enabled_events` | array of string | Event types delivered to this endpoint; ["*"] = all. | | `status` | string | `enabled` endpoints receive events. One of: `enabled`, `disabled`. | | `disabled_reason` | string \| null | Why the endpoint was disabled: `disabled_by_user`, `failing_deliveries` (every delivery failed for 5 days) or `endpoint_gone` (it answered HTTP 410). | | `mode` | string | `live` or `test`. One of: `live`, `test`. | | `livemode` | boolean | `true` in live mode, `false` in test mode. | | `created_at` | string | When the object was created (ISO-8601, UTC). | | `secret` | string | Signing secret (whsec_…). Only returned when the endpoint is created and when the secret is rotated — store it safely. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid), [`webhook_endpoint_limit_reached`](https://swaglists.com/docs/errors.md#webhook_endpoint_limit_reached) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 409 | [`idempotency_key_reused`](https://swaglists.com/docs/errors.md#idempotency_key_reused), [`idempotency_in_progress`](https://swaglists.com/docs/errors.md#idempotency_in_progress) | | 413 | [`request_too_large`](https://swaglists.com/docs/errors.md#request_too_large) | | 415 | [`unsupported_media_type`](https://swaglists.com/docs/errors.md#unsupported_media_type) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl -X POST https://swaglists.com/api/v1/webhook_endpoints \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "url": "https://company-a.example/webhooks/print", "enabled_events": [ "order.shipped", "order.delivered" ], "description": "Production order updates" }' ``` **Example response** ```json { "object": "webhook_endpoint", "id": "we_01k8x2m4n6b8v0c2x4z6a8s0d2", "url": "https://company-a.example/webhooks/print", "description": "Production order updates", "enabled_events": [ "order.shipped", "order.delivered" ], "status": "enabled", "disabled_reason": null, "mode": "live", "livemode": true, "created_at": "2026-10-21T14:32:05.000Z" } ``` ### Retrieve a webhook endpoint `GET /webhook_endpoints/{id}` Requires scope `webhooks:read`. **Scope:** `webhooks:read` **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | Webhook endpoint id. 1–300 characters. | **Returns** `200` — The endpoint (without its secret). [WebhookEndpoint](https://swaglists.com/docs/objects.md#webhook_endpoint) | Field | Type | Description | | --- | --- | --- | | `object` | "webhook_endpoint" | Type of the object: always `webhook_endpoint`. | | `id` | string | Unique identifier (starts with `we_`). | | `url` | string | URL we POST events to. | | `description` | string \| null | Your description. | | `enabled_events` | array of string | Event types delivered to this endpoint; ["*"] = all. | | `status` | string | `enabled` endpoints receive events. One of: `enabled`, `disabled`. | | `disabled_reason` | string \| null | Why the endpoint was disabled: `disabled_by_user`, `failing_deliveries` (every delivery failed for 5 days) or `endpoint_gone` (it answered HTTP 410). | | `mode` | string | `live` or `test`. One of: `live`, `test`. | | `livemode` | boolean | `true` in live mode, `false` in test mode. | | `created_at` | string | When the object was created (ISO-8601, UTC). | | `secret` | string | Signing secret (whsec_…). Only returned when the endpoint is created and when the secret is rotated — store it safely. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl https://swaglists.com/api/v1/webhook_endpoints/we_01k8x2m4n6b8v0c2x4z6a8s0d2 \ -H "Authorization: Bearer $API_KEY" ``` **Example response** ```json { "object": "webhook_endpoint", "id": "we_01k8x2m4n6b8v0c2x4z6a8s0d2", "url": "https://company-a.example/webhooks/print", "description": "Production order updates", "enabled_events": [ "order.shipped", "order.delivered" ], "status": "enabled", "disabled_reason": null, "mode": "live", "livemode": true, "created_at": "2026-10-21T14:32:05.000Z" } ``` ### Update a webhook endpoint `PATCH /webhook_endpoints/{id}` Change the URL, subscribed events or description, or disable/re-enable the endpoint. Requires scope `webhooks:write`. **Scope:** `webhooks:write` · **Idempotency:** send an `Idempotency-Key` header **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | Webhook endpoint id. 1–300 characters. | **Request body** (`application/json`) — UpdateWebhookEndpointRequest | Field | Type | Required | Description | | --- | --- | --- | --- | | `url` | string | no | 1–2048 characters. | | `enabled_events` | array of string | no | Event types to receive, or ["*"] for all. Available: order.created, order.updated, order.confirmed, order.on_hold, order.processing, order.in_production, order.partially_shipped, order.shipped, order.delivered, order.canceled, order.failed, order.refunded, shipment.created, shipment.updated, shipment.delivered, product.created, product.updated, product.deleted, catalog.price_changed, wallet.credited, wallet.low_balance, topup.succeeded, topup.failed, file.processed. 1–200 items. | | `description` | string \| null | no | Max 500 characters. | | `status` | string | no | Disable to pause deliveries; re-enable to resume. One of: `enabled`, `disabled`. | **Returns** `200` — The updated endpoint. [WebhookEndpoint](https://swaglists.com/docs/objects.md#webhook_endpoint) | Field | Type | Description | | --- | --- | --- | | `object` | "webhook_endpoint" | Type of the object: always `webhook_endpoint`. | | `id` | string | Unique identifier (starts with `we_`). | | `url` | string | URL we POST events to. | | `description` | string \| null | Your description. | | `enabled_events` | array of string | Event types delivered to this endpoint; ["*"] = all. | | `status` | string | `enabled` endpoints receive events. One of: `enabled`, `disabled`. | | `disabled_reason` | string \| null | Why the endpoint was disabled: `disabled_by_user`, `failing_deliveries` (every delivery failed for 5 days) or `endpoint_gone` (it answered HTTP 410). | | `mode` | string | `live` or `test`. One of: `live`, `test`. | | `livemode` | boolean | `true` in live mode, `false` in test mode. | | `created_at` | string | When the object was created (ISO-8601, UTC). | | `secret` | string | Signing secret (whsec_…). Only returned when the endpoint is created and when the secret is rotated — store it safely. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 413 | [`request_too_large`](https://swaglists.com/docs/errors.md#request_too_large) | | 415 | [`unsupported_media_type`](https://swaglists.com/docs/errors.md#unsupported_media_type) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl -X PATCH https://swaglists.com/api/v1/webhook_endpoints/we_01k8x2m4n6b8v0c2x4z6a8s0d2 \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "enabled_events": [ "*" ], "status": "enabled" }' ``` **Example response** ```json { "object": "webhook_endpoint", "id": "we_01k8x2m4n6b8v0c2x4z6a8s0d2", "url": "https://company-a.example/webhooks/print", "description": "Production order updates", "enabled_events": [ "order.shipped", "order.delivered" ], "status": "enabled", "disabled_reason": null, "mode": "live", "livemode": true, "created_at": "2026-10-21T14:32:05.000Z" } ``` ### Delete a webhook endpoint `DELETE /webhook_endpoints/{id}` Permanently deletes the endpoint and its delivery history (events remain listable). Requires scope `webhooks:write`. **Scope:** `webhooks:write` · **Idempotency:** send an `Idempotency-Key` header **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | Webhook endpoint id. 1–300 characters. | **Returns** `200` — Deletion confirmation. DeletedWebhookEndpoint | Field | Type | Description | | --- | --- | --- | | `id` | string | Unique identifier (starts with `we_`). | | `object` | "webhook_endpoint" | Type of the object: always `webhook_endpoint`. | | `deleted` | boolean | — | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 413 | [`request_too_large`](https://swaglists.com/docs/errors.md#request_too_large) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl -X DELETE https://swaglists.com/api/v1/webhook_endpoints/we_01k8x2m4n6b8v0c2x4z6a8s0d2 \ -H "Authorization: Bearer $API_KEY" \ -H "Idempotency-Key: $(uuidgen)" ``` **Example response** ```json { "id": "we_01k8x2m4n6b8v0c2x4z6a8s0d2", "object": "webhook_endpoint", "deleted": true } ``` ### Rotate the signing secret `POST /webhook_endpoints/{id}/rotate_secret` Issues a new signing secret (returned once). With `expire_old_in_seconds`, deliveries are signed with both secrets until the old one expires so you can roll without downtime. Requires scope `webhooks:write`. **Scope:** `webhooks:write` · **Idempotency:** send an `Idempotency-Key` header **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | Webhook endpoint id. 1–300 characters. | **Request body** (`application/json`, optional) — RotateWebhookSecretRequest | Field | Type | Required | Description | | --- | --- | --- | --- | | `expire_old_in_seconds` | integer | no | Keep signing with the old secret as well for this many seconds (0–86400, default 0). Range 0–86400. | **Returns** `200` — The endpoint with its new secret. [WebhookEndpoint](https://swaglists.com/docs/objects.md#webhook_endpoint) | Field | Type | Description | | --- | --- | --- | | `object` | "webhook_endpoint" | Type of the object: always `webhook_endpoint`. | | `id` | string | Unique identifier (starts with `we_`). | | `url` | string | URL we POST events to. | | `description` | string \| null | Your description. | | `enabled_events` | array of string | Event types delivered to this endpoint; ["*"] = all. | | `status` | string | `enabled` endpoints receive events. One of: `enabled`, `disabled`. | | `disabled_reason` | string \| null | Why the endpoint was disabled: `disabled_by_user`, `failing_deliveries` (every delivery failed for 5 days) or `endpoint_gone` (it answered HTTP 410). | | `mode` | string | `live` or `test`. One of: `live`, `test`. | | `livemode` | boolean | `true` in live mode, `false` in test mode. | | `created_at` | string | When the object was created (ISO-8601, UTC). | | `secret` | string | Signing secret (whsec_…). Only returned when the endpoint is created and when the secret is rotated — store it safely. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 413 | [`request_too_large`](https://swaglists.com/docs/errors.md#request_too_large) | | 415 | [`unsupported_media_type`](https://swaglists.com/docs/errors.md#unsupported_media_type) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl -X POST https://swaglists.com/api/v1/webhook_endpoints/we_01k8x2m4n6b8v0c2x4z6a8s0d2/rotate_secret \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "expire_old_in_seconds": 3600 }' ``` **Example response** ```json { "object": "webhook_endpoint", "id": "we_01k8x2m4n6b8v0c2x4z6a8s0d2", "url": "https://company-a.example/webhooks/print", "description": "Production order updates", "enabled_events": [ "order.shipped", "order.delivered" ], "status": "enabled", "disabled_reason": null, "mode": "live", "livemode": true, "created_at": "2026-10-21T14:32:05.000Z" } ``` ### Send a test event `POST /webhook_endpoints/{id}/test` Sends a `webhook_endpoint.test` event (data.object = the endpoint) to this endpoint only — use it to verify your signature check. Requires scope `webhooks:write`. **Scope:** `webhooks:write` · **Idempotency:** send an `Idempotency-Key` header **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | Webhook endpoint id. 1–300 characters. | **Returns** `200` — The test event and its delivery. WebhookTestResult | Field | Type | Description | | --- | --- | --- | | `object` | "webhook_test" | Type of the object: always `webhook_test`. | | `event` | [Event](https://swaglists.com/docs/objects.md#event) | Something that happened in your account. Also the exact body POSTed to webhook endpoints. | | `delivery` | [WebhookDelivery](https://swaglists.com/docs/objects.md#webhook_delivery) | — | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 409 | [`idempotency_key_reused`](https://swaglists.com/docs/errors.md#idempotency_key_reused), [`idempotency_in_progress`](https://swaglists.com/docs/errors.md#idempotency_in_progress), [`webhook_endpoint_disabled`](https://swaglists.com/docs/errors.md#webhook_endpoint_disabled) | | 413 | [`request_too_large`](https://swaglists.com/docs/errors.md#request_too_large) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl -X POST https://swaglists.com/api/v1/webhook_endpoints/we_01k8x2m4n6b8v0c2x4z6a8s0d2/test \ -H "Authorization: Bearer $API_KEY" \ -H "Idempotency-Key: $(uuidgen)" ``` **Example response** ```json { "object": "webhook_test", "event": { "id": "evt_01k8x4b2r1t3y5u7i9o1p3a5s7", "object": "event", "type": "webhook_endpoint.test", "api_version": "2026-10-01", "created_at": "2026-10-21T14:32:05.000Z", "livemode": true, "data": { "object": { "object": "webhook_endpoint", "id": "we_01k8x2m4n6b8v0c2x4z6a8s0d2", "url": "https://company-a.example/webhooks/print", "description": "Production order updates", "enabled_events": [ "order.shipped", "order.delivered" ], "status": "enabled", "disabled_reason": null, "mode": "live", "livemode": true, "created_at": "2026-10-21T14:32:05.000Z" } } }, "delivery": { "object": "webhook_delivery", "id": "whd_01k8x4b2r3e5w7q9a1s3d5f7g9", "event_id": "evt_01k8x4b2r1t3y5u7i9o1p3a5s7", "endpoint_id": "we_01k8x2m4n6b8v0c2x4z6a8s0d2", "status": "pending", "attempts": 0, "response_status": null, "next_attempt_at": "2026-10-21T14:32:05.000Z", "last_attempt_at": null, "created_at": "2026-10-21T14:32:05.000Z" } } ``` ## Events Everything that happened in your account; the same objects delivered to webhooks. ### List events `GET /events` Events of the key's mode from the last 30 days, newest first — the same objects delivered to webhook endpoints. Filter by `type` (exact, or a prefix wildcard such as `order.*`). Requires scope `webhooks:read`. **Scope:** `webhooks:read` **Query parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `limit` | integer | no | Number of objects to return, 1–100 (default 20). Range 1–100. | | `starting_after` | string | no | Cursor for the next page: the id of the last object of the previous page. 1–255 characters. | | `ending_before` | string | no | Cursor for the previous page: the id of the first object of the current page. 1–255 characters. | | `type` | string | no | Event type or wildcard, e.g. "order.shipped" or "order.*". 1–100 characters. | | `related_object_id` | string | no | Only events about this object (e.g. an order id). 1–100 characters. | | `created[gte]` | string | no | Created at or after this time. Unix seconds or milliseconds, an ISO-8601 date (2026-10-01 = midnight UTC) or an ISO-8601 date-time (with Z or an offset; without an offset it is UTC). Years 2000–2100. | | `created[lte]` | string | no | Created at or before this time. Unix seconds or milliseconds, an ISO-8601 date (2026-10-01 = midnight UTC) or an ISO-8601 date-time (with Z or an offset; without an offset it is UTC). Years 2000–2100. | **Returns** `200` — A page of events. [EventList](https://swaglists.com/docs/objects.md#list) | Field | Type | Description | | --- | --- | --- | | `object` | "list" | Always `list`. | | `data` | array of [Event](https://swaglists.com/docs/objects.md#event) | The objects of this page. | | `has_more` | boolean | Whether more items exist beyond this page (in the paging direction). | | `url` | string | Path of this list endpoint. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl "https://swaglists.com/api/v1/events?limit=3" \ -H "Authorization: Bearer $API_KEY" ``` **Example response** ```json { "object": "list", "data": [ { "id": "evt_01k8x4b2r1t3y5u7i9o1p3a5s7", "object": "event", "type": "order.shipped", "api_version": "2026-10-01", "created_at": "2026-10-21T14:32:05.000Z", "livemode": true, "data": { "object": { "object": "order", "id": "ord_01k8x4b2q9w7e3r5t1y8u6i0pa", "number": 1042, "external_id": "1042", "livemode": true, "status": "shipped", "hold_reason": null, "funds_status": "captured", "source": "api", "recipient": { "name": "Jane Doe", "company": null, "address1": "123 Market St", "address2": "Apt 4", "city": "San Francisco", "state_code": "CA", "postal_code": "94107", "country_code": "US", "phone": null, "email": "jane@example.com" }, "shipping_method": "standard", "currency": "usd", "subtotal": 2598, "shipping": 700, "tax": 0, "discount": 0, "total": 3298, "refunded": 0, "items": [ { "object": "order_item", "id": "oi_01k8x4b2qa3s5d7f9g1h3j5k7l", "product_id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "product_variant_id": "pvar_01k8x3z7r4f6g8h0j2k4l6z8x0", "catalog_product_id": "cp_01k8w1a2s3d4f5g6h7j8k9m0n1", "catalog_variant_id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "sku": "CA-TEE-BLK-M", "title": "Company A Logo Tee", "variant_title": "Black / M", "quantity": 2, "shipped_quantity": 2, "unit_price": 1299, "total_price": 2598, "retail_price": 2500, "status": "shipped", "designs": [ { "placement": "front", "layers": [ { "file_id": "file_01k8x3y1q3w5e7r9t1y3u5i7o9", "transform": { "x": 0.1, "y": 0.05, "width": 0.8, "height": 0.6, "rotation": 0 }, "opacity": 1 } ] } ], "mockup_url": null, "external_line_id": "line-1", "metadata": {} } ], "shipments": [ { "object": "shipment", "id": "shp_01k8x9z1m3n5b7v9c1x3z5a7s9", "order_id": "ord_01k8x4b2q9w7e3r5t1y8u6i0pa", "status": "in_transit", "carrier": "usps", "service": "USPS Ground Advantage", "tracking_number": "9400111899223197428490", "tracking_url": "https://tools.usps.com/go/TrackConfirmAction?tLabels=9400111899223197428490", "items": [ { "order_item_id": "oi_01k8x4b2qa3s5d7f9g1h3j5k7l", "quantity": 2 } ], "shipped_at": "2026-10-23T09:12:44.000Z", "estimated_delivery_at": null, "delivered_at": null, "created_at": "2026-10-23T09:12:44.000Z" } ], "tracking_page_url": "https://swaglists.com/track/Zx81kLm2pQ", "packing_slip": { "message": "Thanks for shopping with Company A!", "brand_name": null, "logo_file_id": null, "customer_order_number": "#1042" }, "gift_message": null, "customer_note": null, "metadata": {}, "created_at": "2026-10-21T14:32:05.000Z", "updated_at": "2026-10-23T09:12:44.000Z", "placed_at": "2026-10-21T14:32:05.000Z", "in_production_at": "2026-10-21T14:32:05.000Z", "shipped_at": "2026-10-23T09:12:44.000Z", "delivered_at": null, "canceled_at": null, "cancel_reason": null, "failed_at": null, "failure_reason": null } } } ], "has_more": false, "url": "/api/v1/events" } ``` ### Retrieve an event `GET /events/{id}` Requires scope `webhooks:read`. **Scope:** `webhooks:read` **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | Event id. 1–300 characters. | **Returns** `200` — The event. [Event](https://swaglists.com/docs/objects.md#event) | Field | Type | Description | | --- | --- | --- | | `id` | string | Event id. Also sent as the `webhook-id` header and stable across retries — deduplicate on it. | | `object` | "event" | Type of the object: always `event`. | | `type` | string | Event type (e.g. `order.shipped`). | | `api_version` | string | API version the payload was rendered with. | | `created_at` | string | When the event happened (ISO-8601, UTC). | | `livemode` | boolean | `true` in live mode, `false` in test mode. | | `data` | map of any | `object` is the resource as of the event (same shape as the API returns); `previous_attributes` lists changed fields on *.updated events. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl https://swaglists.com/api/v1/events/evt_01k8x4b2r1t3y5u7i9o1p3a5s7 \ -H "Authorization: Bearer $API_KEY" ``` **Example response** ```json { "id": "evt_01k8x4b2r1t3y5u7i9o1p3a5s7", "object": "event", "type": "order.shipped", "api_version": "2026-10-01", "created_at": "2026-10-21T14:32:05.000Z", "livemode": true, "data": { "object": { "object": "order", "id": "ord_01k8x4b2q9w7e3r5t1y8u6i0pa", "number": 1042, "external_id": "1042", "livemode": true, "status": "shipped", "hold_reason": null, "funds_status": "captured", "source": "api", "recipient": { "name": "Jane Doe", "company": null, "address1": "123 Market St", "address2": "Apt 4", "city": "San Francisco", "state_code": "CA", "postal_code": "94107", "country_code": "US", "phone": null, "email": "jane@example.com" }, "shipping_method": "standard", "currency": "usd", "subtotal": 2598, "shipping": 700, "tax": 0, "discount": 0, "total": 3298, "refunded": 0, "items": [ { "object": "order_item", "id": "oi_01k8x4b2qa3s5d7f9g1h3j5k7l", "product_id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "product_variant_id": "pvar_01k8x3z7r4f6g8h0j2k4l6z8x0", "catalog_product_id": "cp_01k8w1a2s3d4f5g6h7j8k9m0n1", "catalog_variant_id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "sku": "CA-TEE-BLK-M", "title": "Company A Logo Tee", "variant_title": "Black / M", "quantity": 2, "shipped_quantity": 2, "unit_price": 1299, "total_price": 2598, "retail_price": 2500, "status": "shipped", "designs": [ { "placement": "front", "layers": [ { "file_id": "file_01k8x3y1q3w5e7r9t1y3u5i7o9", "transform": { "x": 0.1, "y": 0.05, "width": 0.8, "height": 0.6, "rotation": 0 }, "opacity": 1 } ] } ], "mockup_url": null, "external_line_id": "line-1", "metadata": {} } ], "shipments": [ { "object": "shipment", "id": "shp_01k8x9z1m3n5b7v9c1x3z5a7s9", "order_id": "ord_01k8x4b2q9w7e3r5t1y8u6i0pa", "status": "in_transit", "carrier": "usps", "service": "USPS Ground Advantage", "tracking_number": "9400111899223197428490", "tracking_url": "https://tools.usps.com/go/TrackConfirmAction?tLabels=9400111899223197428490", "items": [ { "order_item_id": "oi_01k8x4b2qa3s5d7f9g1h3j5k7l", "quantity": 2 } ], "shipped_at": "2026-10-23T09:12:44.000Z", "estimated_delivery_at": null, "delivered_at": null, "created_at": "2026-10-23T09:12:44.000Z" } ], "tracking_page_url": "https://swaglists.com/track/Zx81kLm2pQ", "packing_slip": { "message": "Thanks for shopping with Company A!", "brand_name": null, "logo_file_id": null, "customer_order_number": "#1042" }, "gift_message": null, "customer_note": null, "metadata": {}, "created_at": "2026-10-21T14:32:05.000Z", "updated_at": "2026-10-23T09:12:44.000Z", "placed_at": "2026-10-21T14:32:05.000Z", "in_production_at": "2026-10-21T14:32:05.000Z", "shipped_at": "2026-10-23T09:12:44.000Z", "delivered_at": null, "canceled_at": null, "cancel_reason": null, "failed_at": null, "failure_reason": null } } } ``` ## Testing Test-mode helpers: add test credits, advance simulated production. ### Add test credits `POST /test/wallet/fund` Test mode only: adds free test credits to the test wallet (orders waiting for funds resume automatically). Requires a full-access test key. **Scope:** full access (`*`) · **Test mode only** · **Idempotency:** send an `Idempotency-Key` header **Request body** (`application/json`, optional) — FundTestWalletRequest | Field | Type | Required | Description | | --- | --- | --- | --- | | `amount` | integer | no | Test credits to add, in cents (default: the platform's test grant, e.g. 100000 = $1,000). Minimum >0. | **Returns** `200` — The test wallet after the grant. [Wallet](https://swaglists.com/docs/objects.md#wallet) | Field | Type | Description | | --- | --- | --- | | `object` | "wallet" | Type of the object: always `wallet`. | | `mode` | string | `live` or `test`. One of: `live`, `test`. | | `livemode` | boolean | `true` in live mode, `false` in test mode. | | `currency` | string | Three-letter currency code, lowercase (`usd`). | | `available` | integer | Spendable credits in cents. May be negative after a payment dispute. | | `held` | integer | Credits reserved for in-flight orders, in cents. | | `total` | integer | available + held, in cents. | | `low_balance_threshold` | integer \| null | Low-balance notification threshold in cents. | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended), [`test_mode_only`](https://swaglists.com/docs/errors.md#test_mode_only) | | 413 | [`request_too_large`](https://swaglists.com/docs/errors.md#request_too_large) | | 415 | [`unsupported_media_type`](https://swaglists.com/docs/errors.md#unsupported_media_type) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl -X POST https://swaglists.com/api/v1/test/wallet/fund \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "amount": 100000 }' ``` **Example response** ```json { "object": "wallet", "mode": "live", "livemode": true, "currency": "usd", "available": 482550, "held": 12480, "total": 495030, "low_balance_threshold": 10000 } ``` ### Advance a test order `POST /test/orders/{id}/advance` Test mode only: moves the simulated production of a test order one step forward (in production → shipped with tracking → delivered), emitting the same events and webhooks as real orders. Call repeatedly to reach `delivered`. With `outcome` it simulates a problem instead: a production failure, a partial shipment, a delivery exception or a return to sender. Later status checks of the simulator agree with every simulated step. Requires scope `orders:write`. **Scope:** `orders:write` · **Test mode only** · **Idempotency:** send an `Idempotency-Key` header **Path parameters** | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | Order id or "ext:" + external_id. 1–300 characters. | **Request body** (`application/json`, optional) — AdvanceTestOrderRequest | Field | Type | Required | Description | | --- | --- | --- | --- | | `outcome` | string | no | What the simulated factory does. `next` (default): the next lifecycle step (`processing` → `in_production` → `shipped` → `delivered`, or resume an `on_hold` order). `fail_production`: production fails before shipping — the items are not produced and their test credits are returned; like a real partner failure, the order goes `on_hold` (`hold_reason: fulfillment_issue`) for our team to follow up. `partial_shipment`: about half of the units ship now (`order.partially_shipped`), the rest on the normal schedule (an order with at least two units). `delivery_exception`: the carrier reports a problem with a package in transit (`shipment.updated`, status `exception`). `return_to_sender`: a package in transit goes back to the sender (`shipment.updated`, status `returned`). An outcome that doesn't fit the order's current state returns 409 `order_not_advanceable`. One of: `next`, `fail_production`, `delivery_exception`, `return_to_sender`, `partial_shipment`. | | `expected_status` | string | no | The order status your client last saw. When the order has moved on since (the simulator advances on its own), nothing happens and the call returns 409 `order_status_changed` with the current status, so a retried or stale call never advances an order twice. One of: `draft`, `on_hold`, `processing`, `in_production`, `partially_shipped`, `shipped`, `delivered`, `canceled`, `failed`. | **Returns** `200` — The order after advancing. [Order](https://swaglists.com/docs/objects.md#order) | Field | Type | Description | | --- | --- | --- | | `object` | "order" | Type of the object: always `order`. | | `id` | string | Unique identifier (starts with `ord_`). | | `number` | integer | Sequential human-friendly order number. | | `external_id` | string \| null | Your order id (unique per mode). Look the order up with `GET /orders/ext:`. | | `livemode` | boolean | `true` in live mode, `false` in test mode. | | `status` | string | draft → processing → in_production → (partially_)shipped → delivered; on_hold (see hold_reason), canceled, failed. One of: `draft`, `on_hold`, `processing`, `in_production`, `partially_shipped`, `shipped`, `delivered`, `canceled`, `failed`. | | `hold_reason` | string \| null | Why the order is on hold; only set while `status` is `on_hold`. One of: `insufficient_funds`, `manual_review`, `artwork_issue`, `address_issue`, `fulfillment_issue`. | | `funds_status` | string | State of the credits for this order: `none` (draft), `awaiting` (on hold for credits), `held` (reserved), `partially_captured`/`captured` (spent), `released` (returned unspent), `partially_refunded`/`refunded`. One of: `none`, `awaiting`, `held`, `partially_captured`, `captured`, `released`, `partially_refunded`, `refunded`. | | `source` | string | Where the order was created. One of: `api`, `dashboard`, `import`, `admin`. | | `recipient` | [Recipient](https://swaglists.com/docs/objects.md#recipient) | Shipping address of the end customer. | | `shipping_method` | string | Shipping speed of the order. One of: `economy`, `standard`, `express`, `priority`. | | `currency` | string | Three-letter currency code, lowercase (`usd`). | | `subtotal` | integer | Items total in cents. | | `shipping` | integer | Shipping price in cents. | | `tax` | integer | Tax in cents (0 unless tax applies to the destination). | | `discount` | integer | Discount in cents. | | `total` | integer | Credits charged for this order (cents). | | `refunded` | integer | Credits refunded to your wallet for this order, in cents. | | `items` | array of [OrderItem](https://swaglists.com/docs/objects.md#order_item) | Line items of the order. | | `shipments` | array of [Shipment](https://swaglists.com/docs/objects.md#shipment) | Parcels shipped so far (an order can ship in several parcels). | | `tracking_page_url` | string \| null | Your branded tracking page for the end customer. null while the order is a draft (the page exists once it is confirmed). | | `packing_slip` | object \| null | Packing slip overrides of this order (null when none were sent). | | `gift_message` | string \| null | Gift message included with the parcel. | | `customer_note` | string \| null | Note from your customer. | | `metadata` | map of string | Your key/value pairs (string values). | | `created_at` | string \| null | When the object was created (ISO-8601, UTC). | | `updated_at` | string \| null | When the object was last changed (ISO-8601, UTC). | | `placed_at` | string \| null | When the order was confirmed (credits reserved, or the order put on hold for funds). | | `in_production_at` | string \| null | When production started. | | `shipped_at` | string \| null | When the order shipped. | | `delivered_at` | string \| null | When every shipment was delivered. | | `canceled_at` | string \| null | When the order was canceled. | | `cancel_reason` | string \| null | Reason given when the order was canceled. | | `failed_at` | string \| null | When the order failed. | | `failure_reason` | string \| null | Why the order failed (reserved credits were released). | **Errors** | Status | Codes | | --- | --- | | 400 | [`parameter_invalid`](https://swaglists.com/docs/errors.md#parameter_invalid), [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing), [`invalid_json`](https://swaglists.com/docs/errors.md#invalid_json), [`idempotency_key_invalid`](https://swaglists.com/docs/errors.md#idempotency_key_invalid) | | 401 | [`missing_api_key`](https://swaglists.com/docs/errors.md#missing_api_key), [`invalid_api_key`](https://swaglists.com/docs/errors.md#invalid_api_key) | | 403 | [`insufficient_scope`](https://swaglists.com/docs/errors.md#insufficient_scope), [`live_mode_disabled`](https://swaglists.com/docs/errors.md#live_mode_disabled), [`ip_not_allowed`](https://swaglists.com/docs/errors.md#ip_not_allowed), [`account_suspended`](https://swaglists.com/docs/errors.md#account_suspended), [`test_mode_only`](https://swaglists.com/docs/errors.md#test_mode_only) | | 404 | [`resource_missing`](https://swaglists.com/docs/errors.md#resource_missing) | | 409 | [`idempotency_key_reused`](https://swaglists.com/docs/errors.md#idempotency_key_reused), [`idempotency_in_progress`](https://swaglists.com/docs/errors.md#idempotency_in_progress), [`order_not_advanceable`](https://swaglists.com/docs/errors.md#order_not_advanceable), [`order_status_changed`](https://swaglists.com/docs/errors.md#order_status_changed) | | 413 | [`request_too_large`](https://swaglists.com/docs/errors.md#request_too_large) | | 415 | [`unsupported_media_type`](https://swaglists.com/docs/errors.md#unsupported_media_type) | | 429 | [`rate_limited`](https://swaglists.com/docs/errors.md#rate_limited) | | 500 | [`internal_error`](https://swaglists.com/docs/errors.md#internal_error) | **Example request** ```bash curl -X POST https://swaglists.com/api/v1/test/orders/ord_01k8x4b2q9w7e3r5t1y8u6i0pa/advance \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "outcome": "next", "expected_status": "processing" }' ``` **Example response** ```json { "object": "order", "id": "ord_01k8x4b2q9w7e3r5t1y8u6i0pa", "number": 1042, "external_id": "1042", "livemode": true, "status": "shipped", "hold_reason": null, "funds_status": "captured", "source": "api", "recipient": { "name": "Jane Doe", "company": null, "address1": "123 Market St", "address2": "Apt 4", "city": "San Francisco", "state_code": "CA", "postal_code": "94107", "country_code": "US", "phone": null, "email": "jane@example.com" }, "shipping_method": "standard", "currency": "usd", "subtotal": 2598, "shipping": 700, "tax": 0, "discount": 0, "total": 3298, "refunded": 0, "items": [ { "object": "order_item", "id": "oi_01k8x4b2qa3s5d7f9g1h3j5k7l", "product_id": "prod_01k8x3z7r1t3y5u7i9o1p3a5s7", "product_variant_id": "pvar_01k8x3z7r4f6g8h0j2k4l6z8x0", "catalog_product_id": "cp_01k8w1a2s3d4f5g6h7j8k9m0n1", "catalog_variant_id": "cv_01k8w1a2s7d9f1g3h5j7k9m1n3", "sku": "CA-TEE-BLK-M", "title": "Company A Logo Tee", "variant_title": "Black / M", "quantity": 2, "shipped_quantity": 2, "unit_price": 1299, "total_price": 2598, "retail_price": 2500, "status": "shipped", "designs": [ { "placement": "front", "layers": [ { "file_id": "file_01k8x3y1q3w5e7r9t1y3u5i7o9", "transform": { "x": 0.1, "y": 0.05, "width": 0.8, "height": 0.6, "rotation": 0 }, "opacity": 1 } ] } ], "mockup_url": null, "external_line_id": "line-1", "metadata": {} } ], "shipments": [ { "object": "shipment", "id": "shp_01k8x9z1m3n5b7v9c1x3z5a7s9", "order_id": "ord_01k8x4b2q9w7e3r5t1y8u6i0pa", "status": "in_transit", "carrier": "usps", "service": "USPS Ground Advantage", "tracking_number": "9400111899223197428490", "tracking_url": "https://tools.usps.com/go/TrackConfirmAction?tLabels=9400111899223197428490", "items": [ { "order_item_id": "oi_01k8x4b2qa3s5d7f9g1h3j5k7l", "quantity": 2 } ], "shipped_at": "2026-10-23T09:12:44.000Z", "estimated_delivery_at": null, "delivered_at": null, "created_at": "2026-10-23T09:12:44.000Z" } ], "tracking_page_url": "https://swaglists.com/track/Zx81kLm2pQ", "packing_slip": { "message": "Thanks for shopping with Company A!", "brand_name": null, "logo_file_id": null, "customer_order_number": "#1042" }, "gift_message": null, "customer_note": null, "metadata": {}, "created_at": "2026-10-21T14:32:05.000Z", "updated_at": "2026-10-23T09:12:44.000Z", "placed_at": "2026-10-21T14:32:05.000Z", "in_production_at": "2026-10-21T14:32:05.000Z", "shipped_at": "2026-10-23T09:12:44.000Z", "delivered_at": null, "canceled_at": null, "cancel_reason": null, "failed_at": null, "failure_reason": null } ```