Feed APIFeed API

REST API / Orders

Orders

Create and manage orders placed with suppliers. Orders follow a defined status lifecycle and support returns.

Note

Order pricing has two independent amounts. reseller_* fields are what's actually charged/refunded (wholesale + shipping). reseller_reference_* fields are a snapshot of your own selling price, for your records only — never charged or refunded.

On items, reseller_reference_price_source is "computed" (auto markup) or "manual" (overridden at creation). Pass retail_unit_price to set a line's price yourself — pricing below wholesale returns a non-blocking warnings array, and the order still goes through.

Order status lifecycle

pendingOrder received, awaiting supplier confirmation.
confirmedSupplier has confirmed the order.
processingOrder is being picked and packed.
shippedOrder dispatched. Tracking info available.
deliveredDelivery confirmed. Returns now possible.
cancelledOrder cancelled. Stock restocked.
refundedRefund processed after return approval.
partially_cancelledSome items were cancelled and the rest still stand. See the order's cancellations for which ones.
partially_refundedPart of the order's value has been refunded. The order itself is not cancelled.

Retrying safely

Creating an order is the only call that takes a payment, so it is the only one where a network timeout is genuinely ambiguous — the order may or may not exist. Give every attempt an external_ref and that ambiguity goes away.

1

Send a reference you chose

Either external_ref in the body or the Idempotency-Key header — they are the same field. Any string up to 200 characters, unique within your account.

2

If the call times out, just send it again

Byte for byte, same reference. If the first attempt never landed you get a normal 201. If it did, you get 409 — never a second order and never a second charge.

3

Read the order out of the 409

The conflict carries existing_order with the id, order number, status and payment status of the order you already have. Nothing more to look up.

4

Or find it later by reference

GET /v1/orders?external_ref=... returns it at any time, which is the way back if you lost the response entirely.

Warning

Omitting the reference opts out of all of this. Two identical calls without one place two orders and take two payments — the API cannot tell them apart, because nothing in the request says they were meant to be the same order.
GET/v1/orders

List orders

Returns paginated orders with optional filtering by status, supplier, and date range.

Query parameters

pageinteger
optional
Page numberDefault: 1
limitinteger
optional
Results per page (1–100)Default: 100
statusstring
optional
Filter by order status. The two partial states are reached when only some of an order's items are cancelled or refunded — an order can sit in either while the rest of it is still being fulfilled.pendingconfirmedprocessingshippeddeliveredcancelledrefundedpartially_cancelledpartially_refunded
supplier_iduuid
optional
Filter by supplier UUID
from_datestring
optional
ISO 8601 date — orders created on or after
to_datestring
optional
ISO 8601 date — orders created on or before
external_refstring
optional
Find the order you gave this reference to. Exact match, and at most one order can hold a given reference, so this is how you recover an order whose creation call never returned an answer.

Response

200 OK
{
  "data": [
    {
      "id": "ord-001",
      "order_number": 42,
      "status": "pending",
      "currency": "GBP",
      "reseller_total": 48.96,
      "reseller_reference_total": 60.96,
      "ship_name": "John Smith",
      "ship_city": "London",
      "ship_postcode": "SW1A 1AA",
      "created_at": "2025-06-24T09:00:00.000Z",
      "suppliers": {
        "id": "sup-001",
        "company_name": "EcoThreads Ltd"
      }
    }
  ],
  "meta": {
    "page": 1,
    "page_size": 100,
    "total": 1,
    "total_pages": 1,
    "has_next": false,
    "has_prev": false
  }
}
GET/v1/orders/{id}

Get order

Returns full order detail including all line items, shipping address, tracking info, and supplier contact.

Path parameters

iduuid
required
Order UUID

Response

200 OK
{
  "data": {
    "id": "ord-001",
    "order_number": 42,
    "status": "shipped",
    "currency": "GBP",
    "reseller_subtotal": 44.97,
    "reseller_shipping": 3.99,
    "reseller_total": 48.96,
    "reseller_reference_subtotal": 56.97,
    "reseller_reference_total": 60.96,
    "carrier": "Royal Mail",
    "tracking_number": "AB123456789GB",
    "tracking_url": "https://track.royalmail.com/AB123456789GB",
    "shipped_at": "2025-06-25T14:00:00.000Z",
    "ship_name": "John Smith",
    "ship_line1": "10 Downing Street",
    "ship_city": "London",
    "ship_postcode": "SW1A 2AA",
    "ship_country": "GB",
    "created_at": "2025-06-24T09:00:00.000Z",
    "order_items": [
      {
        "id": "item-001",
        "product_name": "Organic Cotton T-Shirt",
        "variant_name": "Medium / White",
        "sku": "ECO-SHIRT-M-WHT",
        "quantity": 3,
        "reseller_unit_price": 14.99,
        "reseller_subtotal": 44.97,
        "reseller_reference_unit_price": 18.99,
        "reseller_reference_subtotal": 56.97,
        "reseller_reference_list_unit_price": 18.99,
        "reseller_reference_price_source": "computed"
      }
    ]
  }
}
POST/v1/orders

Create order

Places a new order with a supplier. Shipping cost is calculated automatically based on the delivery postcode and order weight. Stock is decremented immediately. Each item may optionally include retail_unit_price to override your own reference/selling price for that line (e.g. a one-off discount to your end customer) — this only affects the informational reseller_reference_* fields and never the wholesale amount actually charged. If any line's retail_unit_price is set below your wholesale cost, the response includes a non-blocking warnings array. This is the one endpoint that takes a payment, so send an `external_ref` (or the equivalent `Idempotency-Key` header) on every call. It makes the request safe to retry: a second attempt carrying a reference you have already used cannot create a second order or take a second payment.

Headers

Idempotency-Keystring
optional
An alias for the external_ref body field — same values, same guarantee, whichever you find more natural. Sending both is fine only if they are identical; a mismatch is rejected rather than one of them quietly ignored.

Body fields

external_refstring
optional
Your own reference for this order, unique within your account. Max 200 characters; letters, numbers and _ . : - only. Reusing one returns 409 rather than placing a second order, so it is what makes a retry safe. Omit it and you get no such protection — two identical calls place two orders.

Request body

application/json
{
  "supplier_id": "5f50e19c-09a0-4b45-8a96-4a9b53a97641",
  "items": [
    {
      "product_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "variant_id": "var-001",
      "quantity": 3,
      "retail_unit_price": 17.99
    }
  ],
  "ship_name": "John Smith",
  "ship_line1": "10 Downing Street",
  "ship_line2": null,
  "ship_city": "London",
  "ship_postcode": "SW1A 2AA",
  "ship_country": "GB",
  "ship_email": "john@example.com",
  "ship_phone": "07911123456",
  "external_ref": "my-shop-order-9001",
  "reseller_note": "Please pack carefully"
}

Response

200 OK
{
  "data": {
    "order_id": "ord-001",
    "order_number": 42,
    "status": "pending",
    "reseller_total": 48.96,
    "reseller_reference_total": 60.96,
    "currency": "GBP",
    "warnings": [
      "One or more items are priced below your wholesale cost."
    ]
  }
}

Error responses

400
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed",
    "status": 400,
    "details": [
      {
        "field": "ship_name",
        "message": "required"
      }
    ]
  }
}
403
{
  "error": {
    "code": "FORBIDDEN",
    "message": "This supplier is not currently accepting orders",
    "status": 403
  }
}
402
{
  "error": {
    "code": "PAYMENT_REQUIRED",
    "message": "No payment card on file. Add a card in your Feed API dashboard (Settings → Payment) before placing orders.",
    "status": 402
  }
}
409
{
  "error": {
    "code": "CONFLICT",
    "message": "An order with this external_ref has already been submitted",
    "status": 409,
    "existing_order": {
      "id": "ord-001",
      "order_number": 42,
      "status": "confirmed",
      "payment_status": "paid",
      "created_at": "2025-06-24T09:00:00.000Z"
    }
  }
}
POST/v1/orders/{id}/cancel

Cancel order

Cancels an order. Only orders with status `pending` or `confirmed` can be cancelled. Stock is restocked automatically.

Path parameters

iduuid
required
Order UUID

Response

200 OK
{
  "data": {
    "order_id": "ord-001",
    "status": "cancelled"
  }
}

Error responses

409
{
  "error": {
    "code": "CONFLICT",
    "message": "Order cannot be cancelled in status: shipped",
    "status": 409
  }
}
GET/v1/orders/{id}/returns

List returns

Returns all return requests for an order.

Path parameters

iduuid
required
Order UUID

Response

200 OK
{
  "data": [
    {
      "id": "ret-001",
      "status": "requested",
      "reseller_note": "Item arrived damaged",
      "created_at": "2025-06-26T12:00:00.000Z",
      "order_return_items": [
        {
          "id": "ritem-001",
          "order_item_id": "item-001",
          "quantity": 1,
          "reason": "damaged_in_shipping"
        }
      ]
    }
  ]
}
POST/v1/orders/{id}/returns

Request return

Submits a return request for a delivered order. Only one active return per order is allowed.

Path parameters

iduuid
required
Order UUID

Request body

application/json
{
  "items": [
    {
      "order_item_id": "item-001",
      "quantity": 1,
      "reason": "damaged_in_shipping",
      "reason_note": "Box was crushed on arrival",
      "restock": false
    }
  ],
  "reseller_note": "Customer reported damage immediately on delivery."
}

Response

200 OK
{
  "data": {
    "return_id": "ret-001",
    "order_id": "ord-001",
    "status": "requested"
  }
}

Error responses

409
{
  "error": {
    "code": "CONFLICT",
    "message": "Returns can only be requested for delivered orders",
    "status": 409
  }
}
GET/v1/orders/{id}/status-history

Status history

Returns the full chronological status change log for an order.

Path parameters

iduuid
required
Order UUID

Response

200 OK
{
  "data": [
    {
      "id": "log-001",
      "from_status": null,
      "to_status": "pending",
      "note": "Order created",
      "created_at": "2025-06-24T09:00:00.000Z"
    },
    {
      "id": "log-002",
      "from_status": "pending",
      "to_status": "confirmed",
      "note": null,
      "created_at": "2025-06-24T11:00:00.000Z"
    }
  ]
}
GET/v1/orders/{id}/shipments

List shipments

Returns every shipment for an order. An order can have more than one shipment — the flat `carrier`/`tracking_number` fields on the order itself only ever reflect a single shipment, so use this endpoint whenever an order might be split across multiple parcels.

Path parameters

iduuid
required
Order UUID

Response

200 OK
{
  "data": [
    {
      "id": "ship-001",
      "carrier": "Royal Mail",
      "tracking_number": "AB123456789GB",
      "tracking_url": "https://track.royalmail.com/AB123456789GB",
      "status": "delivered",
      "shipped_at": "2025-06-25T14:00:00.000Z",
      "delivered_at": "2025-06-27T10:00:00.000Z",
      "created_at": "2025-06-25T13:00:00.000Z",
      "order_shipment_items": [
        {
          "id": "shitem-001",
          "order_item_id": "item-001",
          "quantity": 2
        }
      ]
    },
    {
      "id": "ship-002",
      "carrier": "DPD",
      "tracking_number": "DPD98765",
      "tracking_url": "https://track.dpd.co.uk/DPD98765",
      "status": "in_transit",
      "shipped_at": "2025-06-26T09:00:00.000Z",
      "delivered_at": null,
      "created_at": "2025-06-26T08:30:00.000Z",
      "order_shipment_items": [
        {
          "id": "shitem-002",
          "order_item_id": "item-002",
          "quantity": 1
        }
      ]
    }
  ]
}
GET/v1/orders/{id}/cancellations

List item cancellations

Individual items cancelled from an order without cancelling the order itself — the detail behind a `partially_cancelled` status and behind the `order.items_cancelled` webhook. Only approved cancellations are returned; a pending or rejected request is not something your catalogue should act on. Ordered oldest first, and a plain array rather than a paginated list.

Path parameters

iduuid
required
Order UUID

Response

200 OK
{
  "data": [
    {
      "id": "oic-001",
      "order_item_id": "item-001",
      "quantity": 2,
      "reason": "Out of stock at the supplier",
      "status": "approved",
      "initiated_by": "supplier_initiated",
      "created_at": "2025-06-25T11:20:00.000Z"
    }
  ]
}

Error responses

404
{
  "error": {
    "code": "NOT_FOUND",
    "message": "Order not found",
    "status": 404
  }
}