# Orders > Create, confirm, change and cancel orders; the order lifecycle, statuses, hold reasons, item statuses and how credits move. Source: https://swaglists.com/docs/orders An **order** ships items to one recipient. You create it with the SKUs your customer bought and their address; we price it, reserve the total from your wallet, produce it and ship it. ## Create an order ```bash title="cURL" curl -X POST https://swaglists.com/api/v1/orders \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: store-order-1042" \ -d '{ "external_id": "1042", "shipping_method": "standard", "recipient": { "name": "Jane Doe", "address1": "123 Market St", "address2": "Apt 4", "city": "San Francisco", "state_code": "CA", "postal_code": "94107", "country_code": "US", "phone": "+1 415 555 0100", "email": "jane@example.com" }, "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" }, "metadata": { "channel": "web" } }' ``` ```js title="Node.js" const res = await fetch("https://swaglists.com/api/v1/orders", { method: "POST", headers: { Authorization: `Bearer ${process.env.API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": `store-order-${storeOrder.id}`, // stable per store order }, body: JSON.stringify({ external_id: String(storeOrder.id), shipping_method: "standard", recipient: { name: "Jane Doe", address1: "123 Market St", city: "San Francisco", state_code: "CA", postal_code: "94107", country_code: "US", email: "jane@example.com", }, items: [{ sku: "CA-TEE-BLK-M", quantity: 2, external_line_id: "line-1" }], }), }); const order = await res.json(); if (!res.ok) throw new Error(`${order.error.code}: ${order.error.message}`); console.log(order.id, order.status, order.total); ``` ```python title="Python" res = requests.post( "https://swaglists.com/api/v1/orders", headers={"Authorization": f"Bearer {os.environ['API_KEY']}", "Idempotency-Key": f"store-order-{store_order_id}"}, json={ "external_id": str(store_order_id), "shipping_method": "standard", "recipient": { "name": "Jane Doe", "address1": "123 Market St", "city": "San Francisco", "state_code": "CA", "postal_code": "94107", "country_code": "US", "email": "jane@example.com", }, "items": [{"sku": "CA-TEE-BLK-M", "quantity": 2, "external_line_id": "line-1"}], }, ) order = res.json() res.raise_for_status() print(order["id"], order["status"], order["total"]) ``` ### Items Identify each item with **exactly one** of: | Reference | Use it when | | --- | --- | | `sku` | You sell [products](https://swaglists.com/docs/products.md) you created — the usual case. | | `product_variant_id` | Same, by our variant id (`pvar_…`). | | `catalog_variant_id` + `designs` | The artwork is different for every order — see [Personalized orders](https://swaglists.com/docs/personalized-orders.md). | Plus `quantity` (1–1,000 per line), and optionally `external_line_id` (your line item id), `metadata` and `retail_price` — what your customer paid per unit, in cents. The retail price (default: the product variant's or product's retail price) is what international packing slips show and what is declared for customs; send it so neither shows our price. An order has 1–100 items. ### Item images (`mockup_url`) Every item has a `mockup_url`: an image of the item as it is produced, which you can show in your order history or emails (the link doesn't expire). - We render it in the background from the order's own `designs` — the snapshot taken when the order was created — a few seconds after you create the order. Editing a product later never changes the image of an order that was already placed. - Until the rendering is done, `mockup_url` is the product's mockup (`sku` / `product_variant_id` items) or the catalog photo of the variant (personalized items). The `order.created` webhook is built when the order is created, so it carries this first image; `GET /orders/{id}` returns the rendered one a few seconds later. - Rendering never delays production. ### Recipient `name`, `address1`, `city` and `country_code` (ISO 3166-1 alpha-2) are required. `state_code` (preferably the ISO subdivision code, e.g. `CA`, `NY`, `ON`, `NSW`) is required for the US, Canada and Australia and must be a valid state or province for the US and Canada. Full names such as `British Columbia` or `New South Wales` are converted to the code for those three countries; elsewhere the region is kept as sent. `postal_code` is required unless the country has none (e.g. HK, AE). `email` is used for [shipment notifications](https://swaglists.com/docs/shipping.md#customer-emails) if you enable them; `phone` helps carriers. ### Other fields | Field | Notes | | --- | --- | | `external_id` | Your order id (up to 128 printable ASCII characters). **Unique per mode** — a second order with the same id fails with `409 duplicate_external_id` (with `existing_id`). Fetch with `GET /orders/ext:`. | | `shipping_method` | `economy`, `standard` (default), `express` or `priority`. See [Shipping](https://swaglists.com/docs/shipping.md). | | `packing_slip` | `message`, `brand_name`, `logo_file_id`, `customer_order_number` — override your account branding for this order. | | `gift_message`, `customer_note` | Free text (500 / 1,000 characters). | | `metadata` | Up to 50 string key/value pairs for your own references. | | `confirm` | `true`: reserve credits and start production now. `false`: create a draft. Default: your account's auto-confirm setting (on by default). | The response is the [order](https://swaglists.com/docs/objects.md#order) (`201`). Always send an `Idempotency-Key` — see [Idempotency](https://swaglists.com/docs/idempotency.md). ## Lifecycle ```text POST /orders POST /orders (confirm: false) (confirm: true — the default) │ │ ▼ ▼ ┌─────────┐ POST …/confirm ┌──────────────────────┐ │ draft │ ──────────────────► │ enough credits? │ └─────────┘ └──────────────────────┘ yes │ │ no (or held for review) ▼ ▼ ┌────────────┐ ┌───────────┐ │ processing │◄─│ on_hold │ hold resolved (e.g. credits added) └────────────┘ └───────────┘ │ ▼ ┌───────────────┐ │ in_production │ ← from here on: no cancellation └───────────────┘ │ ▼ ┌───────────────────┐ │ partially_shipped │ (only when parcels ship separately) └───────────────────┘ │ ▼ ┌──────────┐ ┌───────────┐ │ shipped │ ────► │ delivered │ └──────────┘ └───────────┘ canceled ◄── POST /orders/{id}/cancel while draft, on_hold or processing failed ◄── the order could not be produced (reserved credits are released) ``` `delivered`, `canceled` and `failed` are final. Every change sends a [webhook](https://swaglists.com/docs/webhooks.md) (`order.processing`, `order.in_production`, `order.shipped`, …) and adds an entry to the order timeline (`GET /orders/{id}/events`). ## Statuses | `status` | Meaning | | --- | --- | | `draft` | Created with `confirm: false` (or your account does not auto-confirm). Nothing is reserved; edit with `PATCH /orders/{id}`, then `POST /orders/{id}/confirm`. | | `on_hold` | Waiting — see `hold_reason`. Held orders resume automatically when the reason is resolved (e.g. credits arrive). | | `processing` | Confirmed: the total is reserved from your wallet and the order is being sent to production. Still cancelable. | | `in_production` | Being produced. Can no longer be canceled. | | `partially_shipped` | Some parcels shipped, others are still in production. | | `shipped` | Every item shipped. Tracking is in `shipments`. | | `delivered` | Every shipment was delivered. Final. | | `canceled` | Canceled before production; reserved credits released and spent credits refunded. Final. | | `failed` | Could not be produced; reserved credits released. Final. | ## Hold reasons An order is `on_hold` when it cannot continue yet. `hold_reason` says why: | `hold_reason` | What it means | How to resolve | | --- | --- | --- | | `insufficient_funds` | Your available credits did not cover the order total when it was confirmed. | Add credits (top-up or auto-recharge). Held orders resume automatically, oldest first. In test mode: `POST /test/wallet/fund`. | | `manual_review` | The order is being reviewed by our team before production (for example while your account is new). | No action needed; it continues automatically after review. Contact support if it takes longer than a business day. | | `artwork_issue` | A print file could not be produced from the artwork. | Our team is notified. Cancel the order and re-create it with corrected artwork, or contact support. | | `address_issue` | The shipping address could not be validated or is undeliverable. | Contact support with the corrected address, or cancel and re-create the order. | | `fulfillment_issue` | A production problem occurred (for example an item became unavailable). We are working on it. | Usually no action needed — the order continues or failed items are refunded to your wallet. Contact support if it stays on hold. | You receive `order.on_hold` when an order is held and `order.processing` when it continues. Orders on hold can be canceled. ## Credits and `funds_status` Confirming an order **reserves** its `total` from your wallet (it moves from `available` to `held`). The reserved credits are **spent** (captured) once the order is accepted for production, and **returned** if it is canceled or fails. See [Credits & billing](https://swaglists.com/docs/billing.md). | `funds_status` | Meaning | | --- | --- | | `none` | Nothing reserved (drafts). | | `awaiting` | On hold until enough credits are available. | | `held` | The order total is reserved (counted in your wallet's `held`). | | `partially_captured` | Part of the reserved amount was spent (some items accepted for production). | | `captured` | The order total was spent. | | `released` | Reserved credits were returned to `available` (canceled or failed before being spent). | | `partially_refunded` | Part of the spent amount was refunded to your wallet. | | `refunded` | Everything spent on the order was refunded to your wallet. | Not enough credits? By default the order is held (`on_hold` / `insufficient_funds`) and continues automatically — oldest first — as soon as credits arrive (top-up, auto-recharge, refund). With *hold and release manually*, held orders wait until you release them (dashboard **Release**, single or bulk, or `POST /orders/{id}/confirm`). If you set **Settings → Orders → When credits run out** to *reject*, `POST /orders` fails with `402 insufficient_funds` instead and nothing is created; after adding credits, send the order again with a **new** `Idempotency-Key` ([why](https://swaglists.com/docs/error-handling.md#retries)). ## Item statuses Each `items[]` entry has its own `status` and `shipped_quantity` — useful for orders that ship in several parcels: | Item `status` | Meaning | | --- | --- | | `draft` | The order is a draft. | | `pending` | Waiting to go into production. | | `in_production` | Being produced. | | `shipped` | Every unit shipped (`shipped_quantity` = `quantity`). | | `delivered` | Every unit was delivered. | | `canceled` | Canceled (its credits were returned). | | `failed` | Could not be produced (its credits were returned). | ## Drafts and confirmation Create an order with `"confirm": false` (or turn off auto-confirm in Settings → Orders) to get a `draft`. Drafts reserve nothing and can be changed: ```bash title="Edit a draft, then confirm it" curl -X PATCH https://swaglists.com/api/v1/orders/ord_01k8x4b2q9w7e3r5t1y8u6i0pa \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "shipping_method": "express", "items": [{ "sku": "CA-TEE-BLK-L", "quantity": 1 }] }' curl -X POST https://swaglists.com/api/v1/orders/ord_01k8x4b2q9w7e3r5t1y8u6i0pa/confirm \ -H "Authorization: Bearer $API_KEY" \ -H "Idempotency-Key: confirm-ord_01k8x4b2q9w7e3r5t1y8u6i0pa" ``` `PATCH` accepts `external_id`, `recipient`, `shipping_method`, `items` (replaces all items), `packing_slip`, `gift_message`, `customer_note` and `metadata`, and returns `409 order_not_editable` once the order is confirmed. Confirming reserves credits exactly like creating with `confirm: true`. > **Tip** Use drafts when a human reviews orders before production, or to show your customer the final price: `POST /orders/estimate` gives the same totals without creating anything. ## Estimate an order `POST /orders/estimate` takes the same body as `POST /orders` and returns an [order estimate](https://swaglists.com/docs/objects.md#order_estimate): item prices, shipping, tax, `total`, every available shipping method with its price, the delivery estimate and whether your wallet covers it. Nothing is created and nothing is reserved. The estimate is exactly what the order will cost — see [Pricing](https://swaglists.com/docs/pricing.md). It runs the same checks as `POST /orders` (items, designs, files, packing-slip logo) except that `url` artwork is not downloaded and `external_id` is not checked for duplicates, so those can still fail when you place the order. ## Cancel an order ```bash title="cURL" curl -X POST https://swaglists.com/api/v1/orders/ord_01k8x4b2q9w7e3r5t1y8u6i0pa/cancel \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "reason": "Customer changed their mind" }' ``` - You can cancel orders that are `draft`, `on_hold` or `processing` — as long as production has not started. - Once an order is `in_production` (or shipped) it cannot be canceled: `409 order_not_cancelable`. The same code, with a "try again in a minute" message, is returned while the order is being sent to production — retry shortly. - Reserved credits are released and any spent credits refunded to your wallet immediately; you receive `order.canceled`. - Canceling an order that is already canceled returns it unchanged (safe to retry). ## Retrieve and list | Request | Notes | | --- | --- | | `GET /orders/{id}` | By id, or by your id: `GET /orders/ext:1042`. | | `GET /orders` | Newest first. Filters: `status` (comma-separated), `external_id`, `q` (order number, external id, recipient name or email), `created[gte]`, `created[lte]` (Unix seconds or ISO-8601). | | `GET /orders/{id}/events` | The order timeline, oldest first. | ## After shipping `shipments[]` lists each parcel with carrier, tracking number and tracking URL, and `tracking_page_url` is your branded tracking page — see [Shipping & tracking](https://swaglists.com/docs/shipping.md). Problems after delivery (damaged or misprinted items)? Contact support with the order id; refunds are credited to your wallet (`order.refunded`).