Read, create, and cancel fulfillment orders. Orders are always created against a campaign, so a campaignId is required on create.
#Endpoints
GET /v1/orders/list— list fulfillment orders on the account.GET /v1/orders/warehouses— list warehouses you can route to.GET /v1/orders/{orderId}— get one order by id.POST /v1/orders/create— create a fulfillment order from a campaign.POST /v1/orders/cancel— cancel a fulfillment order.
#Authentication
Standard Bearer auth — see Authentication and API keys.
#List orders
GET /v1/orders/list
Query parameters:
limit(integer, default20) — page size.offset(integer, default0) — number of records to skip.campaignId(string, optional) — filter to orders for a single campaign.orderStatus(string, optional) —AWAITING_SHIPMENT,SHIPPED,CANCELLED, orRETURNED.
Returns an array of order objects. Each element has the shape documented under Get one order below.
curl -X GET 'https://api.merch.com/v1/orders/list?limit=20&offset=0' \
-H 'Authorization: Bearer <your_api_key>'
#Get one order
GET /v1/orders/{orderId}
Path parameter:
orderId(string, required) — the order's id.
Returns 404 { "message": "Order not found" } if no order exists for the id.
Response shape:
{
"id": "<order_id>",
"orderNumber": "ORD-12345",
"sourceOrderNumber": null,
"status": "AWAITING_SHIPMENT",
"paymentStatus": "PAID",
"allocationStatus": "ALLOCATED",
"orderSource": "MANUAL_ORDER",
"orderDate": "2026-05-01T14:22:00.000Z",
"shipDate": null,
"deliveredAt": null,
"estimatedDelivery": null,
"lastTrackingUpdate": null,
"deliveryLocation": null,
"deliveryDescription": null,
"trackingNumber": null,
"carrierCode": null,
"campaignId": "<campaign_id>",
"warehouse": "<warehouse_alias>",
"recipient": {
"firstName": "Ada",
"lastName": "Lovelace",
"email": "[email protected]",
"phone": null,
"street1": "1 Infinite Loop",
"city": "Cupertino",
"state": "CA",
"postalCode": "95014",
"country": "US"
},
"companyName": null,
"notes": null,
"products": [
{ "sku": "TEE-BLK-M", "title": "Logo Tee", "quantity": 1 }
],
"addressVerificationStatus": "VERIFIED"
}
warehouse is the warehouse alias, not its id.
curl -X GET 'https://api.merch.com/v1/orders/<order_id>' \
-H 'Authorization: Bearer <your_api_key>'
#Create an order
POST /v1/orders/create
Creates a fulfillment order against a campaign and a recipient.
Body:
{
"campaignId": "<campaign_id>",
"shipTo": {
"firstName": "Ada",
"lastName": "Lovelace",
"email": "[email protected]",
"phone": "+1-555-0100",
"street1": "1 Infinite Loop",
"street2": null,
"city": "Cupertino",
"state": "CA",
"zip": "95014"
},
"products": [
{ "sku": "TEE-BLK-M", "quantity": 1 }
],
"warehouseId": "<warehouse_id>",
"createContactRecord": false
}
Field rules (validated server-side):
campaignId— required.shipTo.firstName,shipTo.lastName— required, 1-100 chars.shipTo.email— required, valid email, max 254 chars.shipTo.phone— optional, max 30 chars.shipTo.street1— required, 1-200 chars.shipTo.street2— optional, max 200 chars.shipTo.city,shipTo.state— required, 1-100 chars.shipTo.zip— required, 1-20 chars.products— array of at least one{ sku, quantity }. Theskumust match a SKU returned byGET /v1/products/list.warehouseId— optional. Use one of the ids returned byGET /v1/orders/warehouses. If omitted, routing is decided server-side.createContactRecord— optional, defaultfalse. Settrueto also create a contact on the campaign for this recipient.
Success returns 201:
{
"orderId": "<order_id>",
"status": "AWAITING_SHIPMENT"
}
400 Bad Request if validation fails. The body includes the list of failing fields:
{
"message": "Invalid request body",
"errors": ["Required", "Invalid email"]
}
curl -X POST 'https://api.merch.com/v1/orders/create' \
-H 'Authorization: Bearer <your_api_key>' \
-H 'Content-Type: application/json' \
-d '{
"campaignId": "<campaign_id>",
"shipTo": {
"firstName": "Ada",
"lastName": "Lovelace",
"email": "[email protected]",
"street1": "1 Infinite Loop",
"city": "Cupertino",
"state": "CA",
"zip": "95014"
},
"products": [{ "sku": "TEE-BLK-M", "quantity": 1 }]
}'
#Cancel an order
POST /v1/orders/cancel
Body:
{ "orderId": "<order_id>" }
Returns 201 on success (yes, 201, not 200):
{ "message": "Order cancelled successfully" }
400 Bad Request if the order is already cancelled, shipped, or delivered.
curl -X POST 'https://api.merch.com/v1/orders/cancel' \
-H 'Authorization: Bearer <your_api_key>' \
-H 'Content-Type: application/json' \
-d '{ "orderId": "<order_id>" }'
#List warehouses
GET /v1/orders/warehouses
No parameters. Returns the warehouses your account can route to. Use id from this response as the warehouseId on POST /v1/orders/create.
[
{ "id": "<warehouse_id>", "name": "US East", "alias": "us-east" }
]
curl -X GET 'https://api.merch.com/v1/orders/warehouses' \
-H 'Authorization: Bearer <your_api_key>'
#Status enums
The following enum values appear in order responses. Document them as-is — they are returned verbatim by the API.
#status — order lifecycle
| Value | Meaning |
| --- | --- |
| AWAITING_SHIPMENT | Order accepted, not yet handed to a carrier. |
| SHIPPED | Order has left the warehouse. |
| DELIVERED | Carrier has confirmed delivery. |
| CANCELLED | Order was cancelled before shipment. |
| RETURNED | Carrier reported the package as returned. |
#orderSource — how the order was placed
| Value | Meaning |
| --- | --- |
| REDEEM_PAGE | Recipient redeemed an invite. |
| CSV_IMPORT | Bulk uploaded from a CSV. |
| LANDING_PAGE | Submitted through a campaign landing page. |
| MANUAL_ORDER | Created by hand in the customer portal. |
| STANDALONE_ORDER | One-off order outside a normal campaign flow. |
| SHOPIFY_STORE | Came from a connected Shopify store. |
| EXTERNAL | Created via this API. |
#addressVerificationStatus — recipient address check
VERIFIED | CORRECTED | OVERRIDDEN | NEEDS_REVIEW | INVALID | UNVERIFIED | null
null means the order has not been through address verification yet.
#paymentStatus — billing state
UNPAID | PAID | null
null means the order is not subject to a separate payment record (for example, when billing rolls up to a parent invoice).
#allocationStatus — whether stock has been reserved for the shipment
UNALLOCATED | ALLOCATED | RESTOCKED | null
ALLOCATED means inventory has been reserved against the order. RESTOCKED means a previously-allocated shipment has been returned to stock.
#Errors
400 Bad Request— validation failure on create (Invalid request bodywith anerrorsarray) or attempting to cancel an order that is already cancelled, shipped, or delivered.401 Unauthorized— missing, malformed, or invalid bearer token. See Authentication and API keys.404 Not Found—GET /v1/orders/{orderId}only. Returned when the order does not exist or does not belong to your account.500 Internal Server Error— unexpected error. Body is a{ "message": "..." }string. Retry after a short delay; if the failure persists, contact support.