Order states & errors
The order-state vocabulary per product, the create-time reject codes, and the failureReason value set.
Every product’s orders share ONE partner-facing lifecycle vocabulary (status, the
UnifiedOrderStatus enum) — but which of those values a given product’s orders can actually
reach, and what each value means for that product specifically, differs. This page lists Scent’s
own applicable subset, plus the create-time states that stop an order from ever reaching a live
status at all. A future product line documents its own applicable subset in its own section below,
rather than this page being rewritten around it — some values will carry over unchanged, others
won’t apply, and a new product may reach values in an order Scent never does.
Scent order states
Section titled “Scent order states”status on every order response (POST /api/v1/scent/orders’s response, GET /api/v1/scent/orders,
GET /api/v1/scent/orders/{orderId}) is one of:
status |
Meaning for a Scent order |
|---|---|
Processing |
Charged and accepted — fulfilment is under way (being picked, packed, and shipped). This is the value you’ll see immediately after a successful create. |
Completed |
Every fulfilment group on the order has been delivered. |
Cancelled |
The order was cancelled before it was ever charged. No money moved. |
PartiallyDelivered |
At least one, but not every, fulfilment group has been delivered — some parcels have arrived, others are still in transit. |
PartiallyReturned |
At least one line has been returned (refunded, and any commission clawed back) but the order isn’t fully returned. |
Returned |
Every line across the whole order has been returned and refunded. |
Failed |
The order could not be created/charged at all — see failureReason below for why. This is the ONLY value a create call itself can ever hand you directly; every other value is something you observe later via GET/tracking/webhooks. |
PartiallyDelivered and a return state (PartiallyReturned/Returned) are not mutually
exclusive underneath — if both would apply, the returns state takes display precedence, since
“some of this order has been sent back” is more actionable to show a partner than “some of it has
arrived.”
failureReason — why a Failed order failed
Section titled “failureReason — why a Failed order failed”failureReason is present on the order response only when status is Failed, and is
additive alongside status — it never replaces it, and it’s omitted from the wire entirely
(not merely null) for every other status.
The value is a sanitized, partner-safe reason — never a raw internal/operational code. The rule:
- A genuine, partner-actionable business-rule rejection (any code prefixed
BUSINESS_, e.g.BUSINESS_PRICE_NOT_AVAILABLE,BUSINESS_INSUFFICIENT_FUNDS,BUSINESS_EMPTY_CART) passes through verbatim — you can branch on it the same way you’d branch on any otherstatecode in this API. - Anything else — an internal/ops/recovery signal that means nothing actionable to you (e.g. a
crashed or stuck saga, a recharge-required dead-letter) — collapses to one generic code,
ORDER_PROCESSING_FAILED. You will never see a raw internal code on this field.
{ "id": null, "status": "Failed", "failureReason": "BUSINESS_INSUFFICIENT_FUNDS", "...": "..." }A Failed row with no downstream order ever created (a pre-create rejection — the most common
shape) still carries its own id: null and failureReason — this is the one case where
failureReason matters most, since there’s no other field on the row to explain why it failed.
Create-time reject states (never reach a live status at all)
Section titled “Create-time reject states (never reach a live status at all)”These aren’t values of status — they’re the state code on the ERROR response of
POST /api/v1/scent/orders itself, for a request that never even reaches a Processing order.
See the Errors guide for the full HTTP-status-to-shape mapping.
state |
HTTP | Meaning |
|---|---|---|
CONFLICT_ORDER_DUPLICATE_REFERENCE |
409 | This externalReference already succeeded once. details.orderId names the existing order — fetch it, don’t retry. See Idempotency. |
CONFLICT_ORDER_IN_PROGRESS |
409 | A prior attempt with this externalReference is still being processed. Retry again shortly. |
CONFLICT_ORDER_REQUIRES_INTERVENTION |
409 | A prior attempt with this externalReference hit an unrecoverable state (details.status names it) and needs operator intervention before it can be retried at all. Contact your account manager rather than retrying. |
CONFLICT_PRICE_LOCK_ALREADY_USED |
409 | The lockId you passed was already used to create an order (a price lock is single-use). details.orderId names that order. See Cart preview & price locks. |
VALIDATION_PRICE_LOCK_EXPIRED |
400 | The lockId’s TTL passed before you redeemed it. Re-preview and take a new lock. |
VALIDATION_PRICE_LOCK_INVALID |
400 | The lockId is unknown, not yours, or its cart has mutated since the lock was taken. Re-preview and take a new lock. |
A future product’s own section
Section titled “A future product’s own section”A second product line gets its own subsection here, listing its OWN applicable status values
with their OWN product-specific meanings (some will read identically to Scent’s — Processing and
Completed are likely universal — others may not apply, or a new product may introduce a
state Scent never reaches), plus its own create-time reject states if it has any beyond the
generic CONFLICT_ORDER_* family above (those three are spine-level and shared by every product).

