Skip to content
Lucent ImagingLucent Imaging icon
API reference

Orders

Turn a held quote into a job, follow it, and cancel it while that is still possible.

Submit an order

POST
/orders
orders:write
30/min

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

ParameterInTypeNotes
Idempotency-Key
required
headerstringmax 255 characters

Request body

FieldTypeNotes
quoteId
required
string

From POST /quotes. Single-use, and must have been priced by a key in this environment.

1-64 characters
specialInstructionsstring | null

Reaches the studio on the job sheet. A note to a person - not priced, and not interpreted.

max 2000 characters

Response

FieldTypeNotes
orderId
required
string

Use this for reads and to cancel.

orderNumber
required
string

The studio's own reference, e.g. "#0042". What to quote in an email.

status
required
enum

See the lifecycle below. New values may be added, so keep a default arm.

"received" | "in_production" | "on_hold" | "shipped" | "completed" | "cancelled"
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 items on the quote.

lines[].externalReference
required
string | null
lines[].productSlug
required
string
lines[].productName
required
string
lines[].quantity
required
integer
-9007199254740991-9007199254740991
lines[].unitPriceCents
required
integer
-9007199254740991-9007199254740991
lines[].amountCents
required
integer
-9007199254740991-9007199254740991
subtotalCents
required
integer
-9007199254740991-9007199254740991
shippingCents
required
integer
-9007199254740991-9007199254740991
discountCents
required
integer
-9007199254740991-9007199254740991
totalCents
required
integer

What the account was billed.

-9007199254740991-9007199254740991
gstCents
required
integer

The tax component already contained within totalCents, for your bookkeeping.

-9007199254740991-9007199254740991
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 error.code.

401

Missing, malformed, revoked, expired, or belonging to a disabled account - deliberately indistinguishable.

402

CREDIT_LIMIT_EXCEEDED. details carries the outstanding balance, the limit and the headroom left.

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 Retry-After.

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, with Retry-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

GET
/orders
orders:read
120/min

Cursor-paginated. Covers only orders placed through this API.

Parameters

ParameterInTypeNotes
limitqueryinteger1-100 · default 25
cursorquerystring

Response

data is an array and the envelope carries nextCursor beside it. The fields below describe one item.

FieldTypeNotes
orderId
required
string

Use this for reads and to cancel.

orderNumber
required
string

The studio's own reference, e.g. "#0042". What to quote in an email.

status
required
enum

See the lifecycle below. New values may be added, so keep a default arm.

"received" | "in_production" | "on_hold" | "shipped" | "completed" | "cancelled"
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 items on the quote.

lines[].externalReference
required
string | null
lines[].productSlug
required
string
lines[].productName
required
string
lines[].quantity
required
integer
-9007199254740991-9007199254740991
lines[].unitPriceCents
required
integer
-9007199254740991-9007199254740991
lines[].amountCents
required
integer
-9007199254740991-9007199254740991
subtotalCents
required
integer
-9007199254740991-9007199254740991
shippingCents
required
integer
-9007199254740991-9007199254740991
discountCents
required
integer
-9007199254740991-9007199254740991
totalCents
required
integer

What the account was billed.

-9007199254740991-9007199254740991
gstCents
required
integer

The tax component already contained within totalCents, for your bookkeeping.

-9007199254740991-9007199254740991
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 error.code.

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 Retry-After.

Newest first, and scoped to orders placed through this API - a trade account's staff-created projects are not enumerable here.

Retrieve an order

GET
/orders/{id}
orders:read
120/min

Parameters

ParameterInTypeNotes
id
required
pathstring

Response

FieldTypeNotes
orderId
required
string

Use this for reads and to cancel.

orderNumber
required
string

The studio's own reference, e.g. "#0042". What to quote in an email.

status
required
enum

See the lifecycle below. New values may be added, so keep a default arm.

"received" | "in_production" | "on_hold" | "shipped" | "completed" | "cancelled"
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 items on the quote.

lines[].externalReference
required
string | null
lines[].productSlug
required
string
lines[].productName
required
string
lines[].quantity
required
integer
-9007199254740991-9007199254740991
lines[].unitPriceCents
required
integer
-9007199254740991-9007199254740991
lines[].amountCents
required
integer
-9007199254740991-9007199254740991
subtotalCents
required
integer
-9007199254740991-9007199254740991
shippingCents
required
integer
-9007199254740991-9007199254740991
discountCents
required
integer
-9007199254740991-9007199254740991
totalCents
required
integer

What the account was billed.

-9007199254740991-9007199254740991
gstCents
required
integer

The tax component already contained within totalCents, for your bookkeeping.

-9007199254740991-9007199254740991
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 error.code.

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 Retry-After.

Cancel an order

POST
/orders/{id}/cancel
orders:write
30/min

Refused once the studio has done something irreversible - shipped it, printed it, or recorded money against it. The message says which.

Parameters

ParameterInTypeNotes
id
required
pathstring

Response

FieldTypeNotes
orderId
required
string

Use this for reads and to cancel.

orderNumber
required
string

The studio's own reference, e.g. "#0042". What to quote in an email.

status
required
enum

See the lifecycle below. New values may be added, so keep a default arm.

"received" | "in_production" | "on_hold" | "shipped" | "completed" | "cancelled"
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 items on the quote.

lines[].externalReference
required
string | null
lines[].productSlug
required
string
lines[].productName
required
string
lines[].quantity
required
integer
-9007199254740991-9007199254740991
lines[].unitPriceCents
required
integer
-9007199254740991-9007199254740991
lines[].amountCents
required
integer
-9007199254740991-9007199254740991
subtotalCents
required
integer
-9007199254740991-9007199254740991
shippingCents
required
integer
-9007199254740991-9007199254740991
discountCents
required
integer
-9007199254740991-9007199254740991
totalCents
required
integer

What the account was billed.

-9007199254740991-9007199254740991
gstCents
required
integer

The tax component already contained within totalCents, for your bookkeeping.

-9007199254740991-9007199254740991
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 error.code.

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 Retry-After.

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.