Orders
Turn a held quote into a job, follow it, and cancel it while that is still possible.
Submit an order
Idempotency-Key is REQUIRED. The same key with the same body replays the original response; with a different body it is refused. Never re-prices: the quote is the price, or QUOTE_EXPIRED.
Parameters
| Parameter | In | Type | Notes |
|---|---|---|---|
| Idempotency-Key required | header | string |
Request body
| Field | Type | Notes |
|---|---|---|
| quoteId required | string | From |
| specialInstructions | string | null | Reaches the studio on the job sheet. A note to a person - not priced, and not interpreted. |
Response
| Field | Type | Notes |
|---|---|---|
| orderId required | string | Use this for reads and to cancel. |
| orderNumber required | string | The studio's own reference, e.g. |
| status required | enum | See the lifecycle below. New values may be added, so keep a default arm. |
| environment required | string | |
| isTest required | boolean | True for orders placed with a test key. Never printed, never collected. |
| quoteId required | string | null | The quote this order came from. |
| currency required | string | |
| lines required | array of object | Positional against the |
| lines[].externalReference required | string | null | |
| lines[].productSlug required | string | |
| lines[].productName required | string | |
| lines[].quantity required | integer | |
| lines[].unitPriceCents required | integer | |
| lines[].amountCents required | integer | |
| subtotalCents required | integer | |
| shippingCents required | integer | |
| discountCents required | integer | |
| totalCents required | integer | What the account was billed. |
| gstCents required | integer | The tax component already contained within |
| promisedReadyDate required | string | null | A studio-local calendar date where a rush tier guarantees one, else null. |
| shipments required | array of object | One entry per parcel - a multi-box order buys a label per box, so this is always an array. Voided labels are omitted. |
| shipments[].carrier required | string | null | |
| shipments[].trackingNumber required | string | |
| shipments[].trackingUrl required | string | null | |
| shipments[].shippedAt required | string | null | |
| createdAt required | string |
Status codes
201 | The order. |
400 | The request was rejected. Branch on |
401 | Missing, malformed, revoked, expired, or belonging to a disabled account - deliberately indistinguishable. |
402 | CREDIT_LIMIT_EXCEEDED. |
403 | The key authenticated but lacks the required scope. |
409 | The quote expired, was already ordered, or the idempotency key was reused with a different body. |
429 | Rate limited. Honour |
curl -s "$LUCENT_API/orders" \
-H "Authorization: Bearer $LUCENT_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d "{\"quoteId\":\"$QUOTE_ID\",\"specialInstructions\":\"Ship flat, do not roll\"}" \
| jq '.data | {orderId, orderNumber, status, totalCents}'Submission reads the price stored on the quote and never re-prices. Quote on Monday, order on Tuesday, and you pay Monday's price - or you get an explicit QUOTE_EXPIRED. Never a surprise.
Idempotency
- Same key, same body replays your original response verbatim. You get your original order back, not a second one.
- Same key, different body is
IDEMPOTENCY_KEY_REUSED. That is an integration bug rather than a retry, and answering it from the stored response would silently drop an order you believe you placed. - Same key, first attempt still running is also
IDEMPOTENCY_KEY_REUSED, withRetry-After, rather than blocking. - A submission that failed releases the key, so a rejected order does not burn it.
The body hash is canonical - keys sorted, undefined dropped - so a client that reorders its JSON between attempts is still recognised as the same request. Keys are scoped to your account and live for 24 hours.
Billing
There is no payment step. An order raises an invoice against your trade account, billed on terms - which is the point of buying on account.
If the account has a credit limit, it is checked before anything is written. Over it, you get 402 with CREDIT_LIMIT_EXCEEDED and enough detail to act on without a support email: outstandingCents, limitCents, availableCents and orderCents. Nothing is created - no project, no invoice - and the quote stays unspent, so you can order again once the balance clears. Outstanding is summed from unpaid invoices, so a payment recorded anywhere frees headroom immediately.
Orders ship white-labelled by default: no Lucent branding in the parcel, no invoice in the box, and no confirmation email from us to your customer.
Order status
received | We have it and it is queued. |
in_production | The studio has started work. |
on_hold | Paused - the studio will normally have been in touch. |
shipped | At least one parcel is on its way. |
completed | Finished. |
cancelled | Cancelled, by you or by the studio. |
A live parcel outranks everything else: once a shipment exists the order reads shipped, because that is the most specific true statement available and it is what your customer is asking about.
New statuses may be added, so do not switch exhaustively on this. See conventions.
List orders
Cursor-paginated. Covers only orders placed through this API.
Parameters
| Parameter | In | Type | Notes |
|---|---|---|---|
| limit | query | integer | |
| cursor | query | string |
Response
data is an array and the envelope carries nextCursor beside it. The fields below describe one item.
| Field | Type | Notes |
|---|---|---|
| orderId required | string | Use this for reads and to cancel. |
| orderNumber required | string | The studio's own reference, e.g. |
| status required | enum | See the lifecycle below. New values may be added, so keep a default arm. |
| environment required | string | |
| isTest required | boolean | True for orders placed with a test key. Never printed, never collected. |
| quoteId required | string | null | The quote this order came from. |
| currency required | string | |
| lines required | array of object | Positional against the |
| lines[].externalReference required | string | null | |
| lines[].productSlug required | string | |
| lines[].productName required | string | |
| lines[].quantity required | integer | |
| lines[].unitPriceCents required | integer | |
| lines[].amountCents required | integer | |
| subtotalCents required | integer | |
| shippingCents required | integer | |
| discountCents required | integer | |
| totalCents required | integer | What the account was billed. |
| gstCents required | integer | The tax component already contained within |
| promisedReadyDate required | string | null | A studio-local calendar date where a rush tier guarantees one, else null. |
| shipments required | array of object | One entry per parcel - a multi-box order buys a label per box, so this is always an array. Voided labels are omitted. |
| shipments[].carrier required | string | null | |
| shipments[].trackingNumber required | string | |
| shipments[].trackingUrl required | string | null | |
| shipments[].shippedAt required | string | null | |
| createdAt required | string |
Status codes
200 | A page of orders. |
400 | The request was rejected. Branch on |
401 | Missing, malformed, revoked, expired, or belonging to a disabled account - deliberately indistinguishable. |
403 | The key authenticated but lacks the required scope. |
429 | Rate limited. Honour |
Newest first, and scoped to orders placed through this API - a trade account's staff-created projects are not enumerable here.
Retrieve an order
Parameters
| Parameter | In | Type | Notes |
|---|---|---|---|
| id required | path | string |
Response
| Field | Type | Notes |
|---|---|---|
| orderId required | string | Use this for reads and to cancel. |
| orderNumber required | string | The studio's own reference, e.g. |
| status required | enum | See the lifecycle below. New values may be added, so keep a default arm. |
| environment required | string | |
| isTest required | boolean | True for orders placed with a test key. Never printed, never collected. |
| quoteId required | string | null | The quote this order came from. |
| currency required | string | |
| lines required | array of object | Positional against the |
| lines[].externalReference required | string | null | |
| lines[].productSlug required | string | |
| lines[].productName required | string | |
| lines[].quantity required | integer | |
| lines[].unitPriceCents required | integer | |
| lines[].amountCents required | integer | |
| subtotalCents required | integer | |
| shippingCents required | integer | |
| discountCents required | integer | |
| totalCents required | integer | What the account was billed. |
| gstCents required | integer | The tax component already contained within |
| promisedReadyDate required | string | null | A studio-local calendar date where a rush tier guarantees one, else null. |
| shipments required | array of object | One entry per parcel - a multi-box order buys a label per box, so this is always an array. Voided labels are omitted. |
| shipments[].carrier required | string | null | |
| shipments[].trackingNumber required | string | |
| shipments[].trackingUrl required | string | null | |
| shipments[].shippedAt required | string | null | |
| createdAt required | string |
Status codes
200 | The order. |
400 | The request was rejected. Branch on |
401 | Missing, malformed, revoked, expired, or belonging to a disabled account - deliberately indistinguishable. |
403 | The key authenticated but lacks the required scope. |
404 | No such order for this account. |
429 | Rate limited. Honour |
Cancel an order
Refused once the studio has done something irreversible - shipped it, printed it, or recorded money against it. The message says which.
Parameters
| Parameter | In | Type | Notes |
|---|---|---|---|
| id required | path | string |
Response
| Field | Type | Notes |
|---|---|---|
| orderId required | string | Use this for reads and to cancel. |
| orderNumber required | string | The studio's own reference, e.g. |
| status required | enum | See the lifecycle below. New values may be added, so keep a default arm. |
| environment required | string | |
| isTest required | boolean | True for orders placed with a test key. Never printed, never collected. |
| quoteId required | string | null | The quote this order came from. |
| currency required | string | |
| lines required | array of object | Positional against the |
| lines[].externalReference required | string | null | |
| lines[].productSlug required | string | |
| lines[].productName required | string | |
| lines[].quantity required | integer | |
| lines[].unitPriceCents required | integer | |
| lines[].amountCents required | integer | |
| subtotalCents required | integer | |
| shippingCents required | integer | |
| discountCents required | integer | |
| totalCents required | integer | What the account was billed. |
| gstCents required | integer | The tax component already contained within |
| promisedReadyDate required | string | null | A studio-local calendar date where a rush tier guarantees one, else null. |
| shipments required | array of object | One entry per parcel - a multi-box order buys a label per box, so this is always an array. Voided labels are omitted. |
| shipments[].carrier required | string | null | |
| shipments[].trackingNumber required | string | |
| shipments[].trackingUrl required | string | null | |
| shipments[].shippedAt required | string | null | |
| createdAt required | string |
Status codes
200 | The cancelled order. |
400 | The request was rejected. Branch on |
401 | Missing, malformed, revoked, expired, or belonging to a disabled account - deliberately indistinguishable. |
403 | The key authenticated but lacks the required scope. |
404 | No such order for this account. |
409 | ORDER_NOT_CANCELLABLE. |
429 | Rate limited. Honour |
curl -s -X POST "https://lucentimaging.com.au/api/print/v1/orders/$ORDER_ID/cancel" \
-H "Authorization: Bearer $LUCENT_KEY"Cancelling voids the invoice and stops the job. Whether it is still possible is judged from what the studio actually did - a parcel that exists, artwork already printed, or money recorded against the invoice - not from where a card sits on a board. Refusals are ORDER_NOT_CANCELLABLE, and the message names which of those happened.