Merchable APIReferenceGetting startedAuthentication & scopesDesignsPlacing an orderWebhooksPagination, errors & rate limitsVersioning & changelog

Placing an order

An account order is your business buying stock from Merchable at production cost — the same thing as ordering from the Order tab of a design in the web app. The API does not process consumer (storefront) payments.

Request

POST /v1/orders
Authorization: Bearer mchp_…
Content-Type: application/json
Idempotency-Key: po-2026-0042
{
  "external_reference": "PO-2026-0042",
  "customer": { "first_name": "Sam", "last_name": "Lee", "email": "sam@acme.example",
                "phone": "+61 400 000 000", "company": "Acme Climbing" },
  "items": [
    { "design_id": "d8Xk2mQz", "variant_id": "7c9e6679-…", "quantity": 12 },
    { "design_id": "d8Xk2mQz", "colour": "Black", "size": "L", "quantity": 4 },
    { "design_id": "d8Xk2mQz", "colour": "Black", "size": "L", "quantity": 1,
      "personalisation": [ { "zone_id": "4d1c8f2a-…", "text": "SMITH" } ] }
  ],
  "delivery": {
    "type": "delivery",
    "shipping_method": "standard",
    "address": {
      "company": "Acme Climbing",
      "line1": "1 Example St", "line2": null,
      "city": "Melbourne", "state": "VIC", "postcode": "3000", "country": "AU"
    }
  },
  "payment": { "method": "default_card" },
  "notifications": { "suppress_business_emails": true },
  "metadata": { "cost_centre": "events" }
}
Field Notes
customer Optional. Who the order is for: first_name, last_name, email (required), phone, company. Matched by email within your account — an existing customer is reused, otherwise one is created. Returned on reads and in webhook payloads
items[].design_id Public design id from GET /v1/designs
items[].variant_id Variant UUID from GET /v1/designs/{id}; or identify the variant with colour and/or size
items[].quantity Positive integer. Minimum order quantities per product are enforced
items[].personalisation Optional. Text for the design's personalisation zones, one { "zone_id", "text" } per zone — see Personalisation
delivery.type delivery (default, needs address) or pickup
delivery.shipping_method standard (default) or express
payment.method default_card (default and only method) — charges the account's default saved card after any account credit
notifications Per-order email suppression — see Notification suppression
webhook_url Where to POST every lifecycle event for this order — see Webhooks
webhook_secret Optional HMAC secret for those deliveries; omit to sign with the account signing secret
metadata Up to 8 KB of your own JSON, echoed back on reads and in webhooks

Response

201 Created with the order. data.id is the short order reference (A1B2C3D4-E5F6) used everywhere else in the API; data.uuid is the full id.

Quotes

POST /v1/orders/quote accepts the same body and returns the priced lines and totals (products, shipping, payment processing fee, tax) without placing anything. Quotes also list any minimum-order-quantity shortfalls.

Idempotency

POST /v1/orders requires an Idempotency-Key header (1–255 characters, unique per order attempt — a purchase-order number works well). For 24 hours:

Retry safely on network errors and 5xx responses by resending with the same key.

Payment

After placement

Orders start pending and are reviewed by Merchable before production. Follow progress with GET /v1/orders/{id}, GET /v1/orders/{id}/events, and GET /v1/orders/{id}/shipments, or set webhook_url when placing the order to have every event pushed to you — see Webhooks.

POST /v1/orders/{id}/cancel cancels an order that has not yet entered production (pending, pre_order or processing); later cancellations return 409.

Personalisation

Designs with personalisation zones (customer text such as a name on the back) list them under personalisation_zones on GET /v1/designs/{id}. Fill a zone on an order line with personalisation:

{ "design_id": "d8Xk2mQz", "colour": "Black", "size": "L", "quantity": 1,
  "personalisation": [ { "zone_id": "4d1c8f2a-…", "text": "SMITH" } ] }

A personalised line is always its own order line (one line per distinct text), every required zone must be filled, and text must be within the zone's limits; failures are 422s naming the field. A line without personalisation orders the design with its zones empty. Order items echo the text as personalisation. The full rules and error list are in Designs → Personalisation zones.

Notification suppression

By default Merchable emails the account (and any customer) at each milestone. If your integration handles communication, set notifications.suppress_business_emails and/or suppress_customer_emails on the order. Suppression applies to every later milestone of that order (shipped, delivered, completed), not just placement. Merchable's internal operations notifications are never suppressed.

Finding variants, prices and stock

GET /v1/designs/{id} returns everything an order line needs — the variant id to use as variant_id (or the colour/size names), each variant's purchase price and stock status, the design's purchase_breakdown and the product's quantity_tiers. See Designs. Quotes apply quantity tiers to the order's summed quantity for you.

Estimating shipping

POST /v1/shipping/estimate prices shipping for a set of items to a destination exactly as an order would, without creating anything:

{
  "items": [{ "design_id": "d8Xk2mQz", "colour": "Black", "size": "L", "quantity": 12 }],
  "destination": { "country": "AU", "state": "VIC", "postcode": "3000" },
  "shipping_method": "express"
}
{
  "data": {
    "currency": "AUD",
    "origin_country": "AU",
    "destination": { "country": "AU", "state": "VIC", "postcode": "3000", "city": null },
    "international": false,
    "requires_shipping": true,
    "items": [{ "design_id": "d8Xk2mQz", "variant_id": "7c9e…", "quantity": 12, "requires_shipping": true }],
    "methods": [
      { "method": "express",
        "amount_ex_tax": { "amount": "18.18", "currency": "AUD" },
        "tax": { "amount": "1.82", "currency": "AUD" },
        "total": { "amount": "20.00", "currency": "AUD" },
        "delivery_estimate": "approx 4-7 business days" }
    ]
  }
}

Omit shipping_method to get every method available to the destination. Only destination.country is required; include state and postcode when you have them. Items with included shipping or virtual products (gift cards) are priced accordingly.