Quotes
Send a basket, get a price that holds for 24 hours. The quote is what you will be charged - order submission never re-prices.
Price a basket
Omit shippingMethodId to discover the methods this basket can use: the rejection carries every option with its price. Which methods apply depends on the basket, so there is no static list to publish.
Request body
| Field | Type | Notes |
|---|---|---|
| items required | array of object | One entry per distinct configuration. Quantity lives on the line, so five copies of one print is one item with |
| items[].productSlug required | string | A |
| items[].quantity required | integer | |
| items[].variantSelections required | object (map) | The product's configuration, as a string-to-string map. Dimensions go in as strings. See the table below for which keys each product expects. |
| items[].imageUrl | string | null | The |
| items[].externalReference | string | null | Yours - a SKU or line id. Echoed back on the quote, the order and every webhook. Never priced, never interpreted. |
| shippingMethodId | string | null | Omit deliberately to discover the methods this basket can use - see Shipping discovery below. |
| shippingAddress required | object | |
| shippingAddress.name required | string | |
| shippingAddress.company | string | null | |
| shippingAddress.line1 required | string | |
| shippingAddress.line2 | string | null | |
| shippingAddress.city required | string | |
| shippingAddress.state required | string | |
| shippingAddress.postcode required | string | |
| shippingAddress.country required | string | ISO-2, e.g. |
| shippingAddress.phone | string | null | |
| shippingAddress.email required | string (email) | Your customer's address. Required - it travels to the carrier as the parcel's recipient. |
| rushTier | enum | Leave unset for standard turnaround. Faster tiers carry a fee, returned as |
| whiteLabel | boolean | Defaults to true: no Lucent branding in the parcel. Set false only if you want the studio's own packaging. |
Response
| Field | Type | Notes |
|---|---|---|
| quoteId required | string | Pass this to |
| currency required | string | |
| environment required | string | |
| pricingVersion required | integer | Which revision of the pricing engine produced this quote. Handy in a support conversation; nothing to branch on. |
| expiresAt required | string | 24 hours out. After this the quote can still be read, but not ordered. |
| consumedAt required | string | null | Null until the quote becomes an order. A quote stays consumed even if that order is later cancelled. |
| 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 | |
| shippingMethod required | string | null | |
| discountCents required | integer | |
| discountReason required | string | null | A stable slug. Branch on this if you branch at all. |
| discountLabel required | string | null | The human label for the same discount. Show this. |
| rushFeeCents required | integer | |
| promisedReadyDate required | string | null | A studio-local calendar date where a rush tier guarantees one, else null. |
| totalCents required | integer | What the account is charged if this quote becomes an order. |
| gstCents required | integer | The tax component already contained within |
Status codes
201 | The priced basket. |
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 |
POST https://lucentimaging.com.au/api/print/v1/quotes
{
"items": [
{
"productSlug": "fine-art-printing",
"quantity": 5,
"variantSelections": {
"artworkWidthMm": "420",
"artworkHeightMm": "594",
"mediaId": "0f8c…"
},
"imageUrl": "https://lucentimaging.com.au/api/images/order-images/print-api/…",
"externalReference": "SKU-1187"
}
],
"shippingMethodId": "m1",
"shippingAddress": {
"name": "Jordan Avery",
"line1": "1 Example Street",
"city": "Wagga Wagga",
"state": "NSW",
"postcode": "2650",
"country": "AU",
"email": "[email protected]"
},
"rushTier": "standard",
"whiteLabel": true
}Variant selections
variantSelections is a string-to-string map because the keys differ per product. Every value is a string, including dimensions: "420", not 420.
Unknown keys are ignored rather than rejected, so a misspelled key does not error - it just does not take effect.
What you can order
| Product | Available |
|---|---|
fine-art-printing | Yes |
everyday-art-prints | Yes |
print-and-mat | Yes |
custom-framing | Yes |
canvas-printing | Yes |
multi-window-matboard | No Multi-window matboards are ordered through the storefront - the aperture layout cannot be sent through this API |
gift-card | No Gift cards are not sold through the partner API |
paper-samples | No Paper samples are ordered through the storefront |
pro-batch-upload | No Submit batch work as individual fine-art-printing lines |
photo-restoration | No Photo restoration is quoted manually - contact the studio |
fine-art-printing
| Key | Notes |
|---|---|
artworkWidthMm required | Printed width in whole millimetres, as a string. |
artworkHeightMm required | Printed height in whole millimetres, as a string. |
mediaId required | An |
borderMm | White border around the image. |
borderMode |
|
sleeve | A |
everyday-art-prints
| Key | Notes |
|---|---|
artworkWidthMm required | Printed width in whole millimetres, as a string. |
artworkHeightMm required | Printed height in whole millimetres, as a string. |
mediaId required | An |
sleeve | A |
print-and-mat
| Key | Notes |
|---|---|
artworkWidthMm required | Printed width in whole millimetres, as a string. |
artworkHeightMm required | Printed height in whole millimetres, as a string. |
mediaId required | An |
matColorId required | An |
qualityTierId | Constrains which materials may be combined. From |
matSizeMm | Uniform mat border on all four sides. Use this or the per-side keys, not both. |
matTopMm | Per-side mat border. Send all four when the borders differ - a weighted bottom is the common case. |
matRightMm | Per-side mat border. |
matBottomMm | Per-side mat border. |
matLeftMm | Per-side mat border. |
textWindowWidthMm | Adds a second window below the artwork for a caption. Send with |
textWindowHeightMm | Height of the caption window. |
custom-framing
| Key | Notes |
|---|---|
artworkWidthMm required | Printed width in whole millimetres, as a string. |
artworkHeightMm required | Printed height in whole millimetres, as a string. |
mouldingId required | An |
glazingId required | An |
mediaId required | The stock the artwork is printed on, from |
matColorId | Adds a window mount. From |
backingId | An |
qualityTierId | Constrains which materials may be combined. From |
matSizeMm | Uniform mat border on all four sides. Use this or the per-side keys, not both. |
matTopMm | Per-side mat border. Send all four when the borders differ - a weighted bottom is the common case. |
matRightMm | Per-side mat border. |
matBottomMm | Per-side mat border. |
matLeftMm | Per-side mat border. |
textWindowWidthMm | Adds a second window below the artwork for a caption. Send with |
textWindowHeightMm | Height of the caption window. |
canvas-printing
| Key | Notes |
|---|---|
artworkWidthMm required | Printed width in whole millimetres, as a string. |
artworkHeightMm required | Printed height in whole millimetres, as a string. |
mediaId required | An |
format required |
|
depth | Stretcher bar depth. Required unless |
finish | Surface finish applied after printing. |
mouldingId | Adds a float frame. Must be an |
Discovering delivery methods
Which methods a basket can use depends on its size, its contents and its destination, so there is no static list and none in the catalogue. Price the basket without a shippingMethodId: the rejection carries every option that basket could use, with prices.
{
"data": null,
"error": {
"code": "SHIPPING_UNAVAILABLE",
"message": "The selected delivery method isn't available for your cart.",
"details": {
"shippingOptions": [
{
"id": "m1",
"name": "Parcel Post",
"description": null,
"estimatedDelivery": "3-7 business days",
"isCollection": false,
"priceCents": 2200,
"requiresQuote": false
}
]
}
}
}Retrieve a quote
An expired quote is still readable - you need to see what you were quoted and that it lapsed. Only POST /orders refuses to act on one.
Parameters
| Parameter | In | Type | Notes |
|---|---|---|---|
| id required | path | string |
Response
| Field | Type | Notes |
|---|---|---|
| quoteId required | string | Pass this to |
| currency required | string | |
| environment required | string | |
| pricingVersion required | integer | Which revision of the pricing engine produced this quote. Handy in a support conversation; nothing to branch on. |
| expiresAt required | string | 24 hours out. After this the quote can still be read, but not ordered. |
| consumedAt required | string | null | Null until the quote becomes an order. A quote stays consumed even if that order is later cancelled. |
| 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 | |
| shippingMethod required | string | null | |
| discountCents required | integer | |
| discountReason required | string | null | A stable slug. Branch on this if you branch at all. |
| discountLabel required | string | null | The human label for the same discount. Show this. |
| rushFeeCents required | integer | |
| promisedReadyDate required | string | null | A studio-local calendar date where a rush tier guarantees one, else null. |
| totalCents required | integer | What the account is charged if this quote becomes an order. |
| gstCents required | integer | The tax component already contained within |
Status codes
200 | The quote. |
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 quote for this account. Another partner's id answers 404, not 403. |
429 | Rate limited. Honour |
An expired quote is still readable - you need to be able to see what you were quoted and that it lapsed. Only POST /orders refuses to act on one.