Overview
Base URL examples:
URL: https://api.luminaprint.io/v1
Supported Endpoints
| Method | Endpoint | Purpose |
|---|---|---|
| POST | /auth/login | Get access token. |
| GET | /catalog/products | List catalog products with available stock. |
| POST | /orders/create | Create a new order. |
| GET | /orders/my | List your own orders. |
| GET | /orders/my/{order_code_or_ref_id} | Get order detail by order code or reference id. |
| POST | /orders/{order_code}/cancel | Cancel an eligible order. |
| POST | /webhooks | Create webhook subscription. |
| GET | /webhooks | List webhook subscriptions. |
| GET | /webhooks/{webhook_id} | Get webhook subscription. |
| PATCH | /webhooks/{webhook_id} | Update webhook subscription. |
| DELETE | /webhooks/{webhook_id} | Delete webhook subscription. |
| POST | /webhooks/{webhook_id}/test | Send a test delivery. |
| GET | /webhook-deliveries | List webhook delivery attempts. |
Authentication Header
Every endpoint except /auth/login requires a Bearer token.
Authorization: Bearer <access_token>
Content-Type: application/json
Auth
/auth/loginAuthenticates a user and returns an access token. Use the returned token in the Authorization header for all other requests.
Body Parameters
| Field | Type | Required | Description |
|---|---|---|---|
username | string | Yes | Username |
password | string | Yes | Password |
Request Example
{
"username": "clientTest",
"password": "your-password"
}
Response Example
{
"access_token": "eyJhbGciOi...",
"token_type": "Bearer",
"expires_in": 1800
}
Rate Limits
Rate limits protect the API from accidental spikes and repeated retries. Build integrations with retry backoff and avoid sending the same request in tight loops.
15 requests per second sustained, 150 request burst capacity. Login is handled separately so authentication remains available during normal client API throttling.
The bucket holds up to 150 tokens and refills at 15 tokens per second. A short burst of up to 150 requests is accepted instantly; sustained traffic above 15 RPS gets 429 responses once the bucket empties.
| Scope | Sustained | Burst | Notes |
|---|---|---|---|
/orders/** |
15 RPS | 150 requests | Applies to create, cancel, list, and detail order endpoints. Repeated order creation should use a unique reference_id per order. |
/catalog/**, /webhooks/**, /webhook-deliveries |
15 RPS | 150 requests | Applies to public catalog and webhook management endpoints. Keep polling intervals reasonable. Use webhooks for order status changes instead of frequent polling. |
When a Limit Is Exceeded
The API returns 429 Too Many Requests. Wait before retrying. Use exponential backoff with jitter, for example 1s, 2s, 4s, then cap retries.
{
"code": "rate-limit.exceeded",
"message": "Too many requests. Please retry after a short delay.",
"timestamp": "2026-05-25T20:15:30Z"
}
Recommended Client Behavior
- Retry
429responses with exponential backoff and jitter. - Do not retry validation errors such as
400or422without changing the request. - For bulk order import, queue requests on your side and send them steadily instead of firing every order at once.
- Use webhooks for order status changes instead of polling order detail repeatedly.
Catalog
/catalog/products?page=0&size=20Lists catalog products. Each product includes available_stock. Use the returned sku_code when creating orders.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Zero-based page number. Default is 0. Negative values are clamped to 0. |
size | integer | No | Number of products per page. Default 20. Maximum 1000 — values above the cap are silently clamped, values ≤ 0 collapse to the default. The catalog endpoint is exempt from the usual 100-row cap so storefronts can pull the full assigned product set in one request. |
search | string | No | Search by product name, SKU, color, size, or other visible catalog text. |
Response Fields
| Field | Description |
|---|---|
content[].sku_code | Catalog SKU to send in order_items[].sku. |
content[].reference_sku_code | Your specific SKU, if one was configured by Lumina Print. May be null. |
content[].brand | Product brand, if available. |
content[].model | Product model or product line name, if available. |
content[].color | Product color. |
content[].size | Product size. |
content[].available_stock | Available stock quantity currently known by Lumina Print. |
Response Example
{
"content": [
{
"sku_code": "101085001200134",
"reference_sku_code": "CLIENT-SKU-BLACK-L",
"brand": "Gildan",
"model": "5000",
"color": "Black",
"size": "L",
"available_stock": 42
}
],
"page": 0,
"size": 20,
"total_elements": 1,
"total_pages": 1
}
Orders
/orders/createCreates a new print-on-demand order.
The response returns order_code. Store this value for future tracking and cancellation.
Request Body
See the full field-by-field schema in Create Order Body.
Response Example
{
"order_code": "ORD-RBYSTKKRB27Q",
"reference_id": "client-order-10001",
"status": "APPROVED",
"created_at": "2026-05-25T20:15:30Z"
}
/orders/my?page=0&size=20&status=APPROVEDLists orders belonging to the authenticated client.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Zero-based page number. Default is 0. |
size | integer | No | Number of orders per page. Recommended range: 10 to 100. |
status | string | No | Filter by status: APPROVED, IN_PRODUCTION, SHIPPED, or CANCELLED. |
search | string | No | Search by order_code or reference_id. |
Response Example
{
"content": [
{
"order_code": "ORD-RBYSTKKRB27Q",
"reference_id": "client-order-10001",
"status": "IN_PRODUCTION",
"created_at": "2026-05-25T20:15:30Z"
}
],
"page": 0,
"size": 20,
"total_elements": 1,
"total_pages": 1
}
/orders/my/{order_code_or_ref_id}Returns one order owned by the authenticated client. The path value can be either Lumina's order_code or your own reference_id.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
order_code_or_ref_id | string | Yes | Use ORD-... returned by create order, or your original reference_id. |
Response Example
{
"order_code": "ORD-RBYSTKKRB27Q",
"reference_id": "client-order-10001",
"status": "IN_PRODUCTION",
"recipient": {
"name": "Jane Customer",
"city": "Austin",
"state": "TX",
"country": "US",
"zip": "78701"
},
"order_items": [
{
"sku": "101085001200134",
"quantity": 1,
"name": "Black Large Shirt",
"placements": [
{
"placement": "front",
"technique": "DTG"
}
]
}
],
"created_at": "2026-05-25T20:15:30Z",
"updated_at": "2026-05-25T20:20:12Z"
}
/orders/{order_code}/cancelRequests cancellation for an eligible order. Lumina Print first asks the production provider to cancel. If the provider does not confirm cancellation, Lumina Print will not cancel the local order.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
order_code | string | Yes | Lumina order code returned by /orders/create. |
Body Parameters
| Field | Type | Required | Description |
|---|---|---|---|
reason | string | Yes | Short reason for cancellation, such as duplicate order or customer request. |
Request Example
{
"reason": "Customer requested cancellation"
}
Response Fields
| Field | Type | Description |
|---|---|---|
order_code | string | Lumina order code (echoed from the path parameter). |
reference_id | string | The reference_id the client supplied at order creation. |
status | string | Public order status projection. On a successful cancel this is cancelled. |
can_cancel | boolean | Whether another cancel attempt would succeed. Always false on a successful cancel response — the order is now terminal. |
why_blocked | string | Optional. Partner-safe reason if the order is in a blocked or failed state. Omitted from the JSON when not applicable. |
Response Example
{
"order_code": "ORD-RBYSTKKRB27Q",
"reference_id": "client-order-10001",
"status": "cancelled",
"can_cancel": false
}
Create Order Body
This is the body for POST /orders/create. DTG and DTF order placement only.
Top-Level Fields
| Field | Type | Required | Description |
|---|---|---|---|
reference_id | string | No | Your unique order identifier. Use a stable value so duplicate submissions can be detected. Allowed characters: alphanumerics, dashes, and underscores. |
shipping_url | string | No | Shipping label url. |
recipient | object | Yes | Recipient name, address, email, and phone. |
order_items | array | Yes | One or more products to print and ship. |
recipient
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Full recipient name. |
company | string | No | Company name, if shipping to a business. |
street1 | string | Yes | Street address line 1. |
street2 | string | No | Apartment, suite, unit, floor, or other secondary address detail. |
city | string | Yes | City. |
state | string | Yes | State, province, or region. Use common region codes where applicable, such as TX. |
country | string | Yes | Two-letter ISO country code, such as US, CA, or GB. |
zip | string | Yes | Postal or ZIP code. |
email | string | No | Recipient email. Recommended for shipment communication. |
phone | string | No | Recipient phone number. Recommended for carrier delivery issues. Must be in E.164 format with country code (e.g. +17531378536) when supplied. |
taxnumber | string | Conditionally | Tax identifier when required by destination country. |
order_items[]
| Field | Type | Required | Description |
|---|---|---|---|
sku | string | Yes | Catalog sku_code returned by /catalog/products. |
quantity | integer | Yes | Number of units for this line item. Must be greater than 0. |
placements | array | Yes | Print placements for this product, such as front or back. |
order_items[].placements[]
| Field | Type | Required | Description |
|---|---|---|---|
placement | string | Yes | Print location. Common values: front, back, left_sleeve, right_sleeve. |
technique | string | Yes | Print technique. DTG and DTF only. |
print_area_type | string | No | Defaults to simple. |
layers | array | Yes | Design files or text layers to print on this placement. |
order_items[].placements[].layers[]
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Layer type. Use default file. |
url | string | Yes | Publicly reachable HTTPS URL for the artwork file. |
mockup_url | string | Yes | Publicly reachable HTTPS URL for the mockup/preview image. |
width |
number | No |
Optional. Print width in inches (1–14). If provided, height must also be provided.
|
height |
number | No |
Optional. Print height in inches (1–16). If provided, width must also be provided.
|
Request Example
{
"reference_id": "client-order-10001",
"shipping_url": "https://cdn.example.com/shipping/shipping-label.pdf",
"recipient": {
"name": "Jane Customer",
"company": "Jane's Store",
"street1": "100 Congress Ave",
"street2": "Suite 200",
"city": "Austin",
"state": "TX",
"country": "US",
"zip": "78701",
"email": "jane@example.com",
"phone": "+15125550100"
},
"order_items": [
{
"sku": "123456",
"quantity": 1,
"placements": [
{
"placement": "front",
"technique": "DTG",
"print_area_type": "simple",
"layers": [
{
"type": "file",
"url": "https://cdn.example.com/artwork/front.png",
"mockup_url": "https://cdn.example.com/mockup/front.png",
"width": 10,
"height": 12
}
]
},
{
"placement": "back",
"technique": "DTF",
"print_area_type": "simple",
"layers": [
{
"type": "file",
"url": "https://cdn.example.com/artwork/back.png",
"mockup_url": "https://cdn.example.com/mockup/back.png"
}
]
}
]
}
]
}
Client-Visible Statuses
Client APIs expose a small, stable status set. Internal workflow statuses are not part of this public contract.
| Status | Meaning |
|---|---|
APPROVED | Order was accepted and is waiting to enter production. |
IN_PRODUCTION | Order is being processed or produced. |
SHIPPED | Order has shipped or has carrier tracking activity. |
CANCELLED | Order was cancelled. |
Webhooks
Webhooks notify your system when important order events happen. Manage subscriptions through the API. Webhook management is not handled in the client portal.
order.created, order.status_updated.
/webhooksCreates a webhook subscription for the authenticated client. The secret is returned only once on creation; store it securely.
Body Parameters
| Field | Type | Required | Description |
|---|---|---|---|
endpoint_url | string | Yes | HTTPS URL that will receive webhook POST requests. Production URLs must not point to localhost or private network addresses. |
event_types | array of strings | Yes | Events to send to this endpoint. Allowed values: order.created, order.status_updated. |
Request Example
{
"endpoint_url": "https://your-system.example.com/lumina/webhooks",
"event_types": ["order.created", "order.status_updated"]
}
Response Example
{
"id": "7e56d82d-2112-4f98-b6f8-6e6fa5c4b313",
"endpoint_url": "https://your-system.example.com/lumina/webhooks",
"event_types": ["order.created", "order.status_updated"],
"active": true,
"secret": "whsec_...",
"created_at": "2026-05-25T20:15:30Z",
"updated_at": "2026-05-25T20:15:30Z",
"message": "Store the secret now — it is only returned on creation and rotate-secret."
}
/webhooksLists all webhook subscriptions owned by the authenticated client. The response is a flat JSON array — there is no pagination wrapper. Subscription counts per client are bounded by tenant policy, so the full list is returned in one response.
Response Example
[
{
"id": "7e56d82d-2112-4f98-b6f8-6e6fa5c4b313",
"endpoint_url": "https://your-system.example.com/lumina/webhooks",
"event_types": ["order.created", "order.status_updated"],
"active": true,
"created_at": "2026-05-25T20:15:30Z",
"updated_at": "2026-05-25T20:15:30Z"
}
]
/webhooks/{webhook_id}Returns one webhook subscription owned by the authenticated client.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
webhook_id | UUID | Yes | Webhook subscription id returned by POST /webhooks. |
/webhooks/{webhook_id}Updates a webhook subscription. Send only fields that should change.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
webhook_id | UUID | Yes | Webhook subscription id. |
Body Parameters
| Field | Type | Required | Description |
|---|---|---|---|
endpoint_url | string | No | New HTTPS destination URL. |
event_types | array of strings | No | Replacement event list. Allowed values: order.created, order.status_updated. |
active | boolean | No | Set false to pause deliveries without deleting the subscription. |
Request Example
{
"active": false
}
/webhooks/{webhook_id}Deletes a webhook subscription. Future matching events will no longer be delivered to this endpoint.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
webhook_id | UUID | Yes | Webhook subscription id. |
/webhooks/{webhook_id}/testSends a test webhook to the subscription URL. Test deliveries are for connectivity verification and should not create or update real orders in your system.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
webhook_id | UUID | Yes | Webhook subscription id to test. |
Response Example
{
"delivered": true,
"status_code": 200,
"message": "Test webhook delivered"
}
Webhook Signature
Every webhook delivery includes HMAC signature headers. Verify the signature before trusting the payload.
| Header | Description |
|---|---|
X-Lumina-Event-Id | Unique event id. Use this for deduplication. |
X-Lumina-Event-Type | Event type, such as order.created. |
X-Lumina-Timestamp | ISO-8601 UTC timestamp used in the signature payload (for example 2026-05-25T20:20:00Z). Pass this exact header value into the HMAC computation — do not re-format or convert to epoch. |
X-Lumina-Signature | HMAC-SHA256 signature of {timestamp}.{raw_body} using your webhook secret. |
Webhook Deliveries
/webhook-deliveries?subscription_id={subscription_id}&page=0&size=20Lists webhook delivery attempts for the authenticated client. Use this endpoint to debug failed or retried webhook deliveries.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
subscription_id | UUID | No | Filter attempts for one webhook subscription. Cross-tenant ids surface as an empty result, not 403. |
event_type | string | No | Filter by event type, such as order.created or order.status_updated. |
status | string | No | Filter by delivery status. Allowed values: PENDING, DELIVERING, SUCCEEDED, FAILED, RETRYING, EXHAUSTED, CANCELLED. |
page | integer | No | Zero-based page number. Default 0. Must be >= 0 — out of range responds 400. |
size | integer | No | Page size. Default 20, allowed range 1..100 — out of range responds 400. |
Response Example
{
"content": [
{
"id": "d63156a3-6a09-4fe6-bbe9-88c427a1e5ed",
"subscription_id": "7e56d82d-2112-4f98-b6f8-6e6fa5c4b313",
"event_id": "evt_01HY...",
"event_type": "order.status_updated",
"status": "SUCCEEDED",
"http_status": 200,
"attempt_count": 1,
"next_retry_at": null,
"last_error": null,
"created_at": "2026-05-25T20:20:00Z",
"completed_at": "2026-05-25T20:20:01Z"
}
],
"page": 0,
"size": 20,
"total_elements": 1,
"total_pages": 1
}
Field notes:
http_status— HTTP response status from your endpoint on the last attempt.nulluntil the first dispatch is attempted.next_retry_at— present only while the row is inRETRYING. Cleared on terminal status.last_error— last failure detail (connection error, non-2xx body excerpt). Useful for diagnosing your endpoint without enabling delivery payload logging.completed_at— set when the row reaches a terminal status (SUCCEEDED,FAILED,EXHAUSTED,CANCELLED).
Errors
Errors use a consistent JSON shape. Some validation errors may include field-level details.
{
"code": "order.not-found",
"message": "Order was not found.",
"timestamp": "2026-05-25T20:15:30Z"
}
| HTTP Status | Meaning | Typical Cause |
|---|---|---|
400 | Bad request | Malformed JSON, missing required field, invalid enum value, or invalid file URL. |
401 | Unauthorized | Missing, expired, or invalid token. |
403 | Forbidden | Token is valid but not allowed to use the requested resource. |
404 | Not found | Order, product, webhook, or delivery does not exist for this client. |
409 | Conflict | Duplicate referance id, order cannot be cancelled |
429 | Too many requests | Rate limit exceeded. Retry later with exponential backoff. |
422 | Validation failed | Field value is syntactically valid but not acceptable for processing. |
503 | Service unavailable | Service is temporarily unavailable. |