Download OpenAPI specification:
Send orders to 8Merch for fulfillment, manage the products we hold for you, and follow every order to the doorstep.
Part of the 8Merch API documentation - Services > Fulfillment.
The 8Merch Fulfillment API lets a store, marketplace or artist platform with its own checkout send orders to 8Merch warehouses (US, EU, UK) to be picked, packed and shipped, and follow them through to delivery.
Every endpoint documented here is live at https://api.8merch.com/v1. Build and test against a
sandbox account with a test key first - see Sandbox below.
1. Get a key. Keys are issued by 8Merch - email us and we will create one with the scopes you need. You receive it once; store it on your server (never in a browser or app). Every request sends it:
curl https://api.8merch.com/v1/warehouses \
-H "Authorization: Bearer $EIGHTMERCH_API_KEY"
A partner key (one key, many artist accounts) also says which account each request is for:
add -H "8Merch-Account: acc_..." (list yours with GET /v1/accounts).
2. Create your products, keyed by your SKU. Sending a SKU again updates it, so a catalogue sync can simply send everything:
curl -X POST https://api.8merch.com/v1/products \
-H "Authorization: Bearer $EIGHTMERCH_API_KEY" -H "Content-Type: application/json" \
-d '{"sku":"KM-TEE-BLK-L","title":"Killer Moon T-shirt","variant_title":"Black / L","artist":"96BB",
"hs_code":"6109.10","country_of_origin":"PT","customs_description":"Cotton T-shirt, printed"}'
3. Send us stock and tell us it is coming (POST /v1/inbound-shipments). We count it in on
arrival; GET /v1/stock shows it as incoming, then on_hand.
4. Send each paid order with an Idempotency-Key, so a retry can never create it twice:
curl -X POST https://api.8merch.com/v1/orders \
-H "Authorization: Bearer $EIGHTMERCH_API_KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: order-10045" \
-d '{"external_id":"10045","order_number":"#10045",
"shipping_address":{"name":"Ann Lee","line1":"1 Main St","city":"Austin","region":"TX",
"postal_code":"78701","country_code":"US"},
"items":[{"sku":"KM-TEE-BLK-L","quantity":1,"unit_price":25}]}'
5. Register a webhook (POST /v1/webhook-endpoints) to hear order.shipped with the tracking
number, and the rest of the lifecycle - or poll GET /v1/orders?updated_since=....
Pick whichever fits how you work with your artists. Both use the same endpoints.
A. One account, artists as stores. You are a single 8Merch account. Each artist is a
store inside it (POST /v1/stores), and products and orders name their store. 8Merch bills
you, monthly, for everything; you settle with your artists. Use an account key.
B. Platform partner, one account per artist. Each artist has their own 8Merch account,
with their own billing, payment method and monthly statement, and your partner key can act
for all of them. Send 8Merch-Account: <account id> on every request to say which artist it is
for; GET /v1/accounts lists the accounts linked to your key. New artists are invited with
POST /v1/accounts and finish their own billing set-up from the link we return.
You can mix them: a partner key can act for an account that itself has several stores.
Fulfillment costs are billed monthly to the account an order belongs to, on its statement.
Test the whole integration - products, stock, orders, webhooks - without anything shipping or
being billed. Ask us for a sandbox account and a test key (8m_test_...). Same URL, same
endpoints, same validation; the differences:
403 livemode_mismatch). With a partner test key, POST /v1/accounts creates sandbox accounts
(no invitation email is sent) and GET /v1/accounts lists only those.accepted -> in_warehouse -> shipped, at least 2 minutes per step, so
allow 5-15 minutes; it ships with tracking SANDBOX-<number> and its stock is deducted;"metadata": {"sandbox": "hold"} goes on_hold, to test that path;When you go live, the same code works with a live key against your real account.
Content-Type: application/json. Dates are ISO 8601, in UTC.acc_ account, st_ store, wh_ warehouse, ord_ order, ib_ inbound
shipment, we_ webhook endpoint, evt_ event. Products are addressed by your SKU, orders also by
ext:<your external_id>.limit (1-100, default 50); follow next_cursor while has_more is true.POST /v1/orders and POST /v1/inbound-shipments with an
Idempotency-Key: the same key returns the original object with 200 and
Idempotent-Replayed: true instead of creating another (201). POST /v1/products is an upsert
and safe to repeat anyway.RateLimit-Limit,
RateLimit-Remaining and RateLimit-Reset; over the limit you get 429 with Retry-After.Every error has the same shape:
{ "error": { "type": "invalid_request", "code": "unknown_sku",
"message": "No product with SKU KM-TEE-BLK-L ...", "param": "items[0].sku",
"request_id": "req_..." } }
Branch on type and code; message is for people and may change.
| HTTP | type | means |
|---|---|---|
| 400 / 422 | invalid_request |
Something in the request is wrong - param names the field. |
| 401 | authentication_error |
Missing, invalid or revoked key. |
| 402 | account_on_hold |
The account cannot take new orders for that warehouse right now. |
| 403 | permission_error |
The key lacks a scope, or cannot act for that account. |
| 404 | not_found |
No such object for this account (or no such endpoint). |
| 409 | conflict |
Duplicate, or too late (e.g. the order has shipped). |
| 429 | rate_limited |
Slow down; retry after Retry-After seconds. |
| 5xx | server_error |
Our fault - retry with the same Idempotency-Key. |
| code | HTTP | what to do |
|---|---|---|
missing_api_key, invalid_api_key, api_key_revoked |
401 | Check the Authorization header; ask us for a new key. |
partner_disabled |
401 | Your partner access is paused - contact us. |
missing_scope |
403 | The key lacks the scope named in message; ask us to add it. |
missing_account |
400 | Partner keys must send 8Merch-Account. |
account_not_linked, account_inactive |
403 | The account is not linked to your key, or is closed. |
partner_key_required |
403 | /v1/accounts needs a partner key. |
livemode_mismatch |
403 | Test keys act only for sandbox accounts, live keys only for real ones. |
missing_payment_method, missing_billing_details, payment_hold, account_inactive |
402 | Order refused: the account must add a card, finish billing details or pay a statement. Retry once fixed. |
unknown_sku |
422 | Create the product first; nothing was created. |
duplicate_sku |
422 | Send one line per SKU. |
duplicate_external_id |
409 | You already sent this order - fetch it with GET /v1/orders/ext:<id>. |
order_locked |
409 | The order has shipped (or was cancelled); contact us. |
warehouse_required, warehouse_not_granted, warehouse_store_mismatch, unknown_warehouse |
422 | Say which warehouse (warehouse or store), one this account uses - ids from GET /v1/warehouses. |
unknown_store |
422 | The store id is not one of this account's. |
sku_immutable, warehouse_on_update |
422 | A SKU cannot change; warehouse only applies when a product is created. |
invalid_* (e.g. invalid_country_code, invalid_quantity) |
422 | Fix the field named in param. |
email_in_use |
409 | That artist already has an 8Merch account - ask us to link it. |
too_many_endpoints |
422 | Up to 10 webhook endpoints; remove one first. |
*_not_found, unknown_endpoint |
404 | Check the id or URL. |
rate_limited |
429 | Wait Retry-After seconds. |
Orders
| status | means | cancel / change address? |
|---|---|---|
accepted |
With 8Merch, about to go to the warehouse - or waiting for stock or a pre-order release. | Yes. |
in_warehouse |
With the warehouse to pick and pack. | Yes - we pass it to the warehouse and alert our team, but it may already be packed. |
on_hold |
Stopped by 8Merch for a check; hold_reason says why. We contact the account. |
Yes. |
shipped |
Handed to the carrier; shipment has the tracking. |
No (409 order_locked). |
cancelled |
Cancelled. | Cancelling again returns it unchanged. |
Inbound shipments: announced (on its way) -> received (counted in; received_items has what
arrived) or cancelled.
Accounts: pending (new, finishing billing set-up), active (taking orders), on_hold (orders
refused - hold_reasons says which warehouse and why), inactive (closed).
Each delivery has 8Merch-Signature: t=<unix seconds>,v1=<hex>, where v1 is the HMAC-SHA256 of
"<t>.<raw body>" with your endpoint secret. Verify it against the raw body, before parsing:
// Node 18+
const crypto = require("node:crypto");
function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false;
const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
return parts.v1?.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(parts.v1, "hex"), Buffer.from(expected, "hex"));
}
# Python 3
import hashlib, hmac, time
def verify(raw_body: bytes, header: str, secret: str) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
if abs(time.time() - int(parts["t"])) > 300:
return False
expected = hmac.new(secret.encode(), f"{parts['t']}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts.get("v1", ""))
Then respond 2xx within 10 seconds and do the work afterwards. Use the event id to ignore
repeats.
Do products have to exist before orders? Yes. An order with an unknown SKU is refused whole
(422 unknown_sku) so nothing ships half-complete.
What happens if something is out of stock? The order is accepted and waits in accepted;
it is never refused for stock. When open orders need more than we hold, the product is short:
stock.shortfall_opened is sent, the account is emailed and sees it on its dashboard.
GET /v1/stock?shortfall_only=true lists them.
How do pre-orders work? Mark the product preorder.is_preorder: true. Orders containing it are
held (status accepted, counted as preordered, not short) until the account releases them in the
8Merch portal when the stock is ready.
How do I change the items on an order? Cancel it and send a new one. external_id stays
unique even after a cancel, so give the new order a new id (e.g. 10045-2).
How do I get tracking? order.shipped carries shipment.carrier, service and
tracking_number; GET /v1/orders/{id} shows the same.
What does shipping cost? It is billed on the account's monthly statement (postage by measured weight and destination, plus the per-order and per-item fees agreed with us), visible in the 8Merch portal. Orders do not carry a cost in the API.
Which warehouse ships an order? The one you name, or the store's, or the account's only one.
GET /v1/warehouses lists those the account can use; each has one currency.
Do I need customs data? For parcels crossing a customs border (e.g. UK to EU, anywhere to the
US): hs_code, country_of_origin and customs_description on the product, and unit_price on
order lines.
My server was down - did I miss webhooks? Deliveries are retried for about 3 days. To catch up
regardless, list GET /v1/orders?updated_since=<last time you synced>.
How do I test before going live? Use a sandbox account and a test key (see Sandbox): the real
API, with a simulated warehouse. To build request code before you have a key, run a local mock from
this spec: npx @stoplight/prism-cli mock https://api.8merch.com/docs/fulfillment/openapi.yaml.
Can the rate limit be raised? Yes - tell us what you need.
Partner keys only. An account key gets 403.
| cursor | string The |
| limit | integer [ 1 .. 100 ] Default: 50 |
{- "data": [
- {
- "id": "acc_7Hk2",
- "name": "96BB",
- "external_id": "string",
- "status": "pending",
- "hold_reasons": [
- {
- "warehouse": "string",
- "reason": "missing_payment_method"
}
], - "warehouses": [
- "string"
], - "created_at": "2019-08-24T14:15:22Z"
}
], - "has_more": true,
- "next_cursor": "string"
}Creates the account linked to your partner key and returns an onboarding_url for the artist
to enter their billing details and payment method. Until that is done the account is
pending and orders for it are refused with 402 account_on_hold.
| Idempotency-Key | string <= 255 characters Any unique string up to 255 characters. Repeating a request with the same key returns the first result instead of doing the work again (keys are kept for at least 24 hours; inbound shipment keys are kept for good). A replayed response carries |
| name required | string The artist or label name. |
| email required | string <email> Receives the onboarding link and billing emails. |
| external_id | string Your id for this artist. |
| warehouses required | Array of strings non-empty |
{- "name": "string",
- "external_id": "string",
- "warehouses": [
- "string"
]
}{- "id": "acc_7Hk2",
- "name": "96BB",
- "external_id": "string",
- "status": "pending",
- "hold_reasons": [
- {
- "warehouse": "string",
- "reason": "missing_payment_method"
}
], - "warehouses": [
- "string"
], - "created_at": "2019-08-24T14:15:22Z",
}| id required | string |
{- "id": "acc_7Hk2",
- "name": "96BB",
- "external_id": "string",
- "status": "pending",
- "hold_reasons": [
- {
- "warehouse": "string",
- "reason": "missing_payment_method"
}
], - "warehouses": [
- "string"
], - "created_at": "2019-08-24T14:15:22Z"
}| 8Merch-Account | string Example: acc_7Hk2 Partner keys - the account (artist) this request is for. Required with a partner key; ignored with an account key. |
{- "data": [
- {
- "id": "st_3Fq9",
- "name": "string",
- "warehouse": "string",
- "external_id": "string",
- "created_at": "2019-08-24T14:15:22Z"
}
]
}| 8Merch-Account | string Example: acc_7Hk2 Partner keys - the account (artist) this request is for. Required with a partner key; ignored with an account key. |
| name required | string <= 120 characters |
| warehouse required | string Default warehouse for this store's orders. |
| external_id | string Your id for this artist or storefront. |
{- "name": "96BB official store",
- "warehouse": "string",
- "external_id": "string"
}{- "id": "st_3Fq9",
- "name": "string",
- "warehouse": "string",
- "external_id": "string",
- "created_at": "2019-08-24T14:15:22Z"
}Each warehouse ships in one currency. Orders and products are always placed in a warehouse.
| 8Merch-Account | string Example: acc_7Hk2 Partner keys - the account (artist) this request is for. Required with a partner key; ignored with an account key. |
curl "https://api.8merch.com/v1/warehouses" \ -H "Authorization: Bearer $EIGHTMERCH_API_KEY"
{- "data": [
- {
- "id": "wh_eu",
- "name": "EU warehouse",
- "region": "US",
- "currency": "USD",
- "country_code": "PL"
}
]
}| cursor | string The |
| limit | integer [ 1 .. 100 ] Default: 50 |
| artist | string Only products with this artist. |
| updated_since | string <date-time> |
| 8Merch-Account | string Example: acc_7Hk2 Partner keys - the account (artist) this request is for. Required with a partner key; ignored with an account key. |
{- "data": [
- {
- "sku": "KM-TEE-BLK-L",
- "store": "string",
- "warehouse": "string",
- "title": "Killer Moon T-shirt",
- "variant_title": "Black / L",
- "artist": "96BB",
- "barcode": "string",
- "price": 0,
- "currency": "USD",
- "hs_code": "string",
- "country_of_origin": "string",
- "customs_description": "string",
- "preorder": {
- "is_preorder": true,
- "expected_release_date": "2019-08-24"
}, - "warehouses": [
- "string"
], - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "has_more": true,
- "next_cursor": "string"
}Products are keyed by your SKU, which must be unique within your account. Sending a SKU that
already exists updates that product rather than failing (200 instead of 201), so a catalogue
sync can simply send everything. New products are made available to the warehouse within a few
minutes.
A new product starts in one warehouse: warehouse if you send it, otherwise the store's, otherwise
the account's only warehouse (an account with several must say which). warehouse is ignored when
the SKU already exists - to stock a product in another warehouse, send an inbound shipment there.
Fields you leave out are left as they are; null clears an optional field. Fields we do not know
are ignored.
| 8Merch-Account | string Example: acc_7Hk2 Partner keys - the account (artist) this request is for. Required with a partner key; ignored with an account key. |
| Idempotency-Key | string <= 255 characters Any unique string up to 255 characters. Repeating a request with the same key returns the first result instead of doing the work again (keys are kept for at least 24 hours; inbound shipment keys are kept for good). A replayed response carries |
| sku required | string <= 64 characters |
| store | string or null Model A - the store (artist) this product belongs to (st_...). Optional. |
| warehouse | string Where a NEW product starts (wh_...). See above for the default. Create only. |
| title required | string <= 255 characters |
| variant_title | string <= 255 characters |
| artist | string <= 255 characters The artist or band. Shown on warehouse pick lists and packing slips so the right item is picked. |
| barcode | string EAN/UPC if the item carries one. |
| price | number Retail price, for customs declarations. |
| currency | string Enum: "USD" "EUR" "GBP" |
| image_url | string <uri> Helps the warehouse identify the item. |
| hs_code | string Customs tariff (HS) code, 6-10 digits; dots and spaces are ignored (e.g. 6109.10). Needed for parcels crossing a customs border. |
| country_of_origin | string Where the item was made - ISO 3166-1 alpha-2, e.g. PT, BD. |
| customs_description | string <= 200 characters Plain description for the customs declaration, e.g. Men's cotton T-shirt, printed. |
object A pre-order product holds every order containing it until the release is triggered; its orders count as |
{- "sku": "KM-TEE-BLK-L",
- "store": "string",
- "warehouse": "string",
- "title": "Killer Moon T-shirt",
- "variant_title": "Black / L",
- "artist": "96BB",
- "barcode": "string",
- "price": 0,
- "currency": "USD",
- "hs_code": "string",
- "country_of_origin": "string",
- "customs_description": "string",
- "preorder": {
- "is_preorder": true,
- "expected_release_date": "2019-08-24"
}
}{- "sku": "KM-TEE-BLK-L",
- "store": "string",
- "warehouse": "string",
- "title": "Killer Moon T-shirt",
- "variant_title": "Black / L",
- "artist": "96BB",
- "barcode": "string",
- "price": 0,
- "currency": "USD",
- "hs_code": "string",
- "country_of_origin": "string",
- "customs_description": "string",
- "preorder": {
- "is_preorder": true,
- "expected_release_date": "2019-08-24"
}, - "warehouses": [
- "string"
], - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}| sku required | string Your SKU, URL-encoded. |
| 8Merch-Account | string Example: acc_7Hk2 Partner keys - the account (artist) this request is for. Required with a partner key; ignored with an account key. |
{- "sku": "KM-TEE-BLK-L",
- "store": "string",
- "warehouse": "string",
- "title": "Killer Moon T-shirt",
- "variant_title": "Black / L",
- "artist": "96BB",
- "barcode": "string",
- "price": 0,
- "currency": "USD",
- "hs_code": "string",
- "country_of_origin": "string",
- "customs_description": "string",
- "preorder": {
- "is_preorder": true,
- "expected_release_date": "2019-08-24"
}, - "warehouses": [
- "string"
], - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}Send only the fields to change. The SKU itself cannot be changed - create a new product instead.
| sku required | string Your SKU, URL-encoded. |
| 8Merch-Account | string Example: acc_7Hk2 Partner keys - the account (artist) this request is for. Required with a partner key; ignored with an account key. |
| store | string or null |
| title | string |
| variant_title | string |
| artist | string |
| barcode | string |
| price | number |
| currency | string Enum: "USD" "EUR" "GBP" |
| image_url | string <uri> |
| hs_code | string |
| country_of_origin | string |
| customs_description | string <= 200 characters |
object |
{- "store": "string",
- "title": "string",
- "variant_title": "string",
- "artist": "string",
- "barcode": "string",
- "price": 0,
- "currency": "USD",
- "hs_code": "string",
- "country_of_origin": "string",
- "customs_description": "string",
- "preorder": {
- "is_preorder": true,
- "expected_release_date": "2019-08-24"
}
}{- "sku": "KM-TEE-BLK-L",
- "store": "string",
- "warehouse": "string",
- "title": "Killer Moon T-shirt",
- "variant_title": "Black / L",
- "artist": "96BB",
- "barcode": "string",
- "price": 0,
- "currency": "USD",
- "hs_code": "string",
- "country_of_origin": "string",
- "customs_description": "string",
- "preorder": {
- "is_preorder": true,
- "expected_release_date": "2019-08-24"
}, - "warehouses": [
- "string"
], - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}available = on_hand - reserved, where reserved is stock already promised to open orders.
Stock changes when we receive an inbound shipment, ship an order or correct a count; subscribe to
stock.updated rather than polling.
| cursor | string The |
| limit | integer [ 1 .. 100 ] Default: 50 |
| warehouse | string |
| sku | string One SKU, or several separated by commas. |
| shortfall_only | boolean Only products that are short - open orders need more units than are on hand. |
| 8Merch-Account | string Example: acc_7Hk2 Partner keys - the account (artist) this request is for. Required with a partner key; ignored with an account key. |
curl "https://api.8merch.com/v1/stock?shortfall_only=true" \ -H "Authorization: Bearer $EIGHTMERCH_API_KEY"
{- "data": [
- {
- "sku": "string",
- "warehouse": "string",
- "on_hand": 0,
- "reserved": 0,
- "available": 0,
- "incoming": 0,
- "preordered": 0,
- "shortfall": 0,
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "has_more": true,
- "next_cursor": "string"
}| cursor | string The |
| limit | integer [ 1 .. 100 ] Default: 50 |
| status | string (InboundStatus) Enum: "announced" "received" "cancelled" |
| 8Merch-Account | string Example: acc_7Hk2 Partner keys - the account (artist) this request is for. Required with a partner key; ignored with an account key. |
{- "data": [
- {
- "warehouse": "string",
- "reference": "string",
- "carrier": "string",
- "tracking_number": "string",
- "expected_arrival": "2019-08-24",
- "items": [
- {
- "sku": "string",
- "quantity": 1
}
], - "id": "ib_cm9x2k",
- "status": "announced",
- "received_at": "2019-08-24T14:15:22Z",
- "received_items": [
- {
- "sku": "string",
- "quantity": 0
}
], - "created_at": "2019-08-24T14:15:22Z"
}
], - "has_more": true,
- "next_cursor": "string"
}Announce goods you are sending to a warehouse, so they are expected and counted in quickly.
Quantities you announce show as incoming until the warehouse counts them in; the counted
quantity (which may differ) is what becomes on_hand, and inbound_shipment.received reports it.
Every SKU must already exist (POST /v1/products first), once per shipment, in a warehouse the
account uses. Send an Idempotency-Key so a retried request cannot announce the goods twice.
| 8Merch-Account | string Example: acc_7Hk2 Partner keys - the account (artist) this request is for. Required with a partner key; ignored with an account key. |
| Idempotency-Key | string <= 255 characters Any unique string up to 255 characters. Repeating a request with the same key returns the first result instead of doing the work again (keys are kept for at least 24 hours; inbound shipment keys are kept for good). A replayed response carries |
| warehouse required | string |
| reference | string Your reference, e.g. a purchase-order number. |
| carrier | string |
| tracking_number | string |
| expected_arrival | string <date> |
required | Array of objects non-empty |
{- "warehouse": "string",
- "reference": "string",
- "carrier": "string",
- "tracking_number": "string",
- "expected_arrival": "2019-08-24",
- "items": [
- {
- "sku": "string",
- "quantity": 1
}
]
}{- "warehouse": "string",
- "reference": "string",
- "carrier": "string",
- "tracking_number": "string",
- "expected_arrival": "2019-08-24",
- "items": [
- {
- "sku": "string",
- "quantity": 1
}
], - "id": "ib_cm9x2k",
- "status": "announced",
- "received_at": "2019-08-24T14:15:22Z",
- "received_items": [
- {
- "sku": "string",
- "quantity": 0
}
], - "created_at": "2019-08-24T14:15:22Z"
}| id required | string Example: ib_cm9x2k |
| 8Merch-Account | string Example: acc_7Hk2 Partner keys - the account (artist) this request is for. Required with a partner key; ignored with an account key. |
{- "warehouse": "string",
- "reference": "string",
- "carrier": "string",
- "tracking_number": "string",
- "expected_arrival": "2019-08-24",
- "items": [
- {
- "sku": "string",
- "quantity": 1
}
], - "id": "ib_cm9x2k",
- "status": "announced",
- "received_at": "2019-08-24T14:15:22Z",
- "received_items": [
- {
- "sku": "string",
- "quantity": 0
}
], - "created_at": "2019-08-24T14:15:22Z"
}Orders you sent through the API. Orders from the account's own Shopify or Bandcamp stores are not listed here.
| cursor | string The |
| limit | integer [ 1 .. 100 ] Default: 50 |
| status | string Example: status=accepted,in_warehouse One status, or several separated by commas. |
| updated_since | string <date-time> Only orders changed at or after this time - the efficient way to catch up after downtime. |
| external_id | string |
| 8Merch-Account | string Example: acc_7Hk2 Partner keys - the account (artist) this request is for. Required with a partner key; ignored with an account key. |
{- "data": [
- {
- "external_id": "string",
- "store": "string",
- "order_number": "string",
- "order_date": "2019-08-24T14:15:22Z",
- "warehouse": "string",
- "currency": "USD",
- "shipping_method": "string",
- "shipping_address": {
- "name": "string",
- "company": "string",
- "line1": "string",
- "line2": "string",
- "city": "string",
- "region": "string",
- "postal_code": "string",
- "country_code": "string",
- "phone": "string"
}, - "items": [
- {
- "sku": "string",
- "quantity": 1,
- "unit_price": 0
}
], - "metadata": {
- "property1": "string",
- "property2": "string"
}, - "id": "ord_cm9x2k",
- "status": "accepted",
- "hold_reason": "string",
- "cancel_reason": "string",
- "shipment": {
- "carrier": "UPS",
- "service": "UPS Ground",
- "tracking_number": "string",
- "weight_kg": 0,
- "shipped_at": "2019-08-24T14:15:22Z"
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "has_more": true,
- "next_cursor": "string"
}Send each order once it is paid. Every SKU must already exist as a product in the order's
warehouse; unknown SKUs reject the whole order (422 unknown_sku) so nothing ships half-complete.
Retrying is safe. Send an Idempotency-Key header (your order id works well): repeating the
same request with the same key returns the original order instead of creating a second one.
external_id is also unique per account - a second order with an external_id you have already
used is refused with 409 duplicate_external_id.
Orders for items that are not in stock are accepted and wait in accepted until stock is
received - intake is never paused. When open orders (other than pre-orders) need more units
than we hold, the product is short: we send stock.shortfall_opened, email the account and
show it on their dashboard, so stock can be sent. stock.shortfall_resolved follows when stock
covers the orders again.
If the account is on hold for the order's warehouse (no valid payment method, missing billing
details, or an unpaid statement after three failed charges), new orders are refused with
402 account_on_hold - never silently dropped. error.code says which: missing_payment_method,
missing_billing_details, payment_hold or account_inactive.
Without a store, the order is filed under the account's "API orders" store for that warehouse,
created automatically.
| 8Merch-Account | string Example: acc_7Hk2 Partner keys - the account (artist) this request is for. Required with a partner key; ignored with an account key. |
| Idempotency-Key | string <= 255 characters Any unique string up to 255 characters. Repeating a request with the same key returns the first result instead of doing the work again (keys are kept for at least 24 hours; inbound shipment keys are kept for good). A replayed response carries |
| external_id required | string <= 128 characters Your order id. Unique per account. |
| store | string Model A - the store (artist) the order was placed in (st_...). Optional - see above. |
| order_number | string <= 64 characters What your customer sees, e.g. |
| order_date | string <date-time> Defaults to now. |
| warehouse | string Which warehouse ships it (wh_...). Optional when the store fixes it or the account uses one warehouse. |
| currency | string Enum: "USD" "EUR" "GBP" The checkout currency - informational. |
| shipping_method | string <= 255 characters The shipping option your customer chose at checkout, e.g. |
object The recipient's name is | |
required | object (Address) |
required | Array of objects [ 1 .. 200 ] items One line per SKU. |
object Up to 20 keys of your own, returned unchanged. |
{- "external_id": "string",
- "store": "string",
- "order_number": "string",
- "order_date": "2019-08-24T14:15:22Z",
- "warehouse": "string",
- "currency": "USD",
- "shipping_method": "string",
- "shipping_address": {
- "name": "string",
- "company": "string",
- "line1": "string",
- "line2": "string",
- "city": "string",
- "region": "string",
- "postal_code": "string",
- "country_code": "string",
- "phone": "string"
}, - "items": [
- {
- "sku": "string",
- "quantity": 1,
- "unit_price": 0
}
], - "metadata": {
- "property1": "string",
- "property2": "string"
}
}{- "external_id": "string",
- "store": "string",
- "order_number": "string",
- "order_date": "2019-08-24T14:15:22Z",
- "warehouse": "string",
- "currency": "USD",
- "shipping_method": "string",
- "shipping_address": {
- "name": "string",
- "company": "string",
- "line1": "string",
- "line2": "string",
- "city": "string",
- "region": "string",
- "postal_code": "string",
- "country_code": "string",
- "phone": "string"
}, - "items": [
- {
- "sku": "string",
- "quantity": 1,
- "unit_price": 0
}
], - "metadata": {
- "property1": "string",
- "property2": "string"
}, - "id": "ord_cm9x2k",
- "status": "accepted",
- "hold_reason": "string",
- "cancel_reason": "string",
- "shipment": {
- "carrier": "UPS",
- "service": "UPS Ground",
- "tracking_number": "string",
- "weight_kg": 0,
- "shipped_at": "2019-08-24T14:15:22Z"
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}| id required | string Our order |
| 8Merch-Account | string Example: acc_7Hk2 Partner keys - the account (artist) this request is for. Required with a partner key; ignored with an account key. |
curl "https://api.8merch.com/v1/orders/ext:10045" \ -H "Authorization: Bearer $EIGHTMERCH_API_KEY"
{- "external_id": "string",
- "store": "string",
- "order_number": "string",
- "order_date": "2019-08-24T14:15:22Z",
- "warehouse": "string",
- "currency": "USD",
- "shipping_method": "string",
- "shipping_address": {
- "name": "string",
- "company": "string",
- "line1": "string",
- "line2": "string",
- "city": "string",
- "region": "string",
- "postal_code": "string",
- "country_code": "string",
- "phone": "string"
}, - "items": [
- {
- "sku": "string",
- "quantity": 1,
- "unit_price": 0
}
], - "metadata": {
- "property1": "string",
- "property2": "string"
}, - "id": "ord_cm9x2k",
- "status": "accepted",
- "hold_reason": "string",
- "cancel_reason": "string",
- "shipment": {
- "carrier": "UPS",
- "service": "UPS Ground",
- "tracking_number": "string",
- "weight_kg": 0,
- "shipped_at": "2019-08-24T14:15:22Z"
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}Replaces the whole address. Possible until the order ships; after that 409 order_locked.
If the order is already with the warehouse (in_warehouse) the new address is sent there and our
team is alerted - a label printed before the change is reprinted.
| id required | string Our order |
| 8Merch-Account | string Example: acc_7Hk2 Partner keys - the account (artist) this request is for. Required with a partner key; ignored with an account key. |
| name required | string The recipient. |
| company | string Printed on the label. |
| line1 required | string |
| line2 | string |
| city required | string |
| region | string State, province or county - required for US, CA and AU. |
| postal_code required | string |
| country_code required | string ISO 3166-1 alpha-2, e.g. |
| phone | string Many carriers require it for international parcels. |
{- "name": "string",
- "company": "string",
- "line1": "string",
- "line2": "string",
- "city": "string",
- "region": "string",
- "postal_code": "string",
- "country_code": "string",
- "phone": "string"
}{- "external_id": "string",
- "store": "string",
- "order_number": "string",
- "order_date": "2019-08-24T14:15:22Z",
- "warehouse": "string",
- "currency": "USD",
- "shipping_method": "string",
- "shipping_address": {
- "name": "string",
- "company": "string",
- "line1": "string",
- "line2": "string",
- "city": "string",
- "region": "string",
- "postal_code": "string",
- "country_code": "string",
- "phone": "string"
}, - "items": [
- {
- "sku": "string",
- "quantity": 1,
- "unit_price": 0
}
], - "metadata": {
- "property1": "string",
- "property2": "string"
}, - "id": "ord_cm9x2k",
- "status": "accepted",
- "hold_reason": "string",
- "cancel_reason": "string",
- "shipment": {
- "carrier": "UPS",
- "service": "UPS Ground",
- "tracking_number": "string",
- "weight_kg": 0,
- "shipped_at": "2019-08-24T14:15:22Z"
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}Possible until the order ships; after that 409 order_locked - contact us and we will try to stop it.
An order still accepted is simply cancelled. One already in_warehouse is cancelled at the
warehouse too and our team is alerted, because it may already be packed - if it still goes out,
we will tell you. Cancelling a cancelled order returns it unchanged.
| id required | string Our order |
| 8Merch-Account | string Example: acc_7Hk2 Partner keys - the account (artist) this request is for. Required with a partner key; ignored with an account key. |
| reason | string <= 500 characters |
{- "reason": "string"
}{- "external_id": "string",
- "store": "string",
- "order_number": "string",
- "order_date": "2019-08-24T14:15:22Z",
- "warehouse": "string",
- "currency": "USD",
- "shipping_method": "string",
- "shipping_address": {
- "name": "string",
- "company": "string",
- "line1": "string",
- "line2": "string",
- "city": "string",
- "region": "string",
- "postal_code": "string",
- "country_code": "string",
- "phone": "string"
}, - "items": [
- {
- "sku": "string",
- "quantity": 1,
- "unit_price": 0
}
], - "metadata": {
- "property1": "string",
- "property2": "string"
}, - "id": "ord_cm9x2k",
- "status": "accepted",
- "hold_reason": "string",
- "cancel_reason": "string",
- "shipment": {
- "carrier": "UPS",
- "service": "UPS Ground",
- "tracking_number": "string",
- "weight_kg": 0,
- "shipped_at": "2019-08-24T14:15:22Z"
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}Endpoints belong to whoever owns the key. A partner key's endpoints receive the events of
every account linked to the partner - register once, not once per artist; each event names its
account. An account key's endpoints receive that account's events. The 8Merch-Account
header plays no part here.
{- "data": [
- {
- "id": "string",
- "events": [
- "order.accepted"
], - "status": "active",
- "last_success_at": "2019-08-24T14:15:22Z",
- "last_failure_at": "2019-08-24T14:15:22Z",
- "last_error": "string",
- "created_at": "2019-08-24T14:15:22Z"
}
]
}The signing secret is returned once, in this response only. Store it to verify deliveries.
The URL must be https and publicly reachable; up to 10 endpoints per key owner.
| url required | string <uri> Must be https. |
| events required | Array of strings (EventType) Items Enum: "order.accepted" "order.in_warehouse" "order.shipped" "order.cancelled" "order.on_hold" "stock.updated" "stock.shortfall_opened" "stock.shortfall_resolved" "inbound_shipment.received" "account.hold_changed" |
{- "events": [
- "order.accepted"
]
}{- "id": "string",
- "events": [
- "order.accepted"
], - "status": "active",
- "last_success_at": "2019-08-24T14:15:22Z",
- "last_failure_at": "2019-08-24T14:15:22Z",
- "last_error": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "secret": "whsec_3fX9..."
}