Errors
The shape
Section titled “The shape”Errors use application/problem+json:
{ "type": "https://docs.luxorr.io/errors#invalid_request", "title": "Invalid request", "status": 400, "code": "invalid_request", "detail": "recipient.phone is required", "errors": [ { "field": "recipient.phone", "code": "required", "message": "recipient.phone is required" } ]}| Field | Meaning |
|---|---|
code |
Stable, snake_case. Use it in your logic. New codes can be added; existing codes do not change. |
status |
HTTP status. |
title |
Short label for the code. |
detail |
Description of this occurrence. Log it; do not parse it. |
type |
Link to the code on this page. |
errors |
Validation errors: one entry per field, each with a code. |
Some errors add fields: currentStatus on not_editable and not_cancellable, orderId on external_order_id_conflict.
Validation errors are never 5xx. On a 5xx, retry; for a POST, reuse the Idempotency-Key.
invalid_request
Section titled “invalid_request”400. The request is malformed: missing required field, invalid JSON, wrong value type, unreadable ID in the query or body, limit outside 1–100, unknown cursor, or a timestamp with an unencoded +. errors[] lists each field. Fix the request and send it with a new Idempotency-Key.
A delivery correction is validated after merging, so errors[] can name a recipient.* field you did not send, such as a missing stored recipient.address.postalCode. Send that field.
A malformed ID in the path answers 404 not_found, for example GET /orders/not-a-uuid.
payload_too_large
Section titled “payload_too_large”413. The request body is larger than 10 MB. Nothing runs. A personal-link batch of 1,000 recipients fits well under it; split anything larger.
idempotency_key_required
Section titled “idempotency_key_required”400. A POST without an Idempotency-Key header, or with a blank one. See idempotency.
idempotency_key_invalid
Section titled “idempotency_key_invalid”400. The Idempotency-Key header is longer than 255 characters. Nothing runs. Send a shorter key, such as a UUID. See idempotency.
unsupported_media_type
Section titled “unsupported_media_type”415. The request body is not sent as application/json, for example as text/plain or a form. Nothing runs. Send JSON with Content-Type: application/json.
not_acceptable
Section titled “not_acceptable”406. The Accept header rules out application/json. Nothing runs. Send Accept: application/json, or no Accept header. Catalog images are exempt.
invalid_api_key
Section titled “invalid_api_key”401. The key is missing, malformed, unknown or revoked, API access is switched off, or the key is for the other environment. Do not retry.
insufficient_scope
Section titled “insufficient_scope”403. The key lacks the scope this endpoint needs: CATALOG, ORDERS or PERSONAL_LINKS. detail names it. See keys.
not_found
Section titled “not_found”404. No record visible to this key. Records of another tenant or outside the key’s brands, and path IDs that are not UUIDs, answer the same way.
method_not_allowed
Section titled “method_not_allowed”405. The path exists, but not with this HTTP method.
rate_limited
Section titled “rate_limited”429. More than 300 requests in a minute from this key, or 600 image requests from one IP. Wait for the Retry-After header’s seconds. See rate limits.
idempotency_key_reused
Section titled “idempotency_key_reused”422. The Idempotency-Key was used before with a different request. Use a new key for a new request.
idempotency_request_in_progress
Section titled “idempotency_request_in_progress”409. A request with this Idempotency-Key is still running. Nothing runs a second time. Retry with the same key and body after a few seconds: you get the first request’s answer once it is stored. See idempotency.
brand_required
Section titled “brand_required”422. An order with no campaignId must name a brandId.
brand_not_found
Section titled “brand_not_found”422. The brand does not exist, belongs to another tenant, or is outside the key’s brands.
brand_campaign_mismatch
Section titled “brand_campaign_mismatch”422. An order names both campaignId and a brandId that is not that campaign’s brand. Leave brandId out, or send the campaign’s brand. errors[] names brandId.
campaign_not_found
Section titled “campaign_not_found”422. The campaign does not exist, belongs to another tenant, or is outside the key’s brands.
campaign_not_active
Section titled “campaign_not_active”422. The campaign is not active: it is still being prepared, or it has completed.
product_not_in_campaign
Section titled “product_not_in_campaign”422. The campaign does not offer this gift.
product_not_available
Section titled “product_not_available”422. The gift cannot be ordered or offered: it is not published, or it is internal.
product_not_found
Section titled “product_not_found”422. A personal-link batch names a product that is not in the catalog.
not_deliverable_to_country
Section titled “not_deliverable_to_country”422. The gift cannot be delivered to the recipient’s country. Check available in the catalog for that country.
invalid_variations
Section titled “invalid_variations”422. The variations are not one valid value for every dimension of the gift.
invalid_custom_fields
Section titled “invalid_custom_fields”422. A required custom field of your tenant has no answer, or an answer does not fit its field, such as a dropdown value that is not one of its options. detail and errors[] say which. An answer whose fieldId names no field of your tenant is ignored, not refused. GET /me lists your fields in tenant.customFields, with each one’s type, options and whether it is required.
manager_not_found
Section titled “manager_not_found”422. managerEmail on an order names no active member of your team. In a personal-link batch the same code rejects only that recipient, as a field code on managerEmail.
country_change_not_allowed
Section titled “country_change_not_allowed”422. A delivery correction changes address.country. The country cannot change; cancel and place a new order, or message Luxorr.
no_products
Section titled “no_products”422. A personal-link batch sent brandId with an empty productIds.
no_recipients
Section titled “no_recipients”422. A personal-link batch has no recipients.
too_many_recipients
Section titled “too_many_recipients”422. A personal-link batch has more than 1,000 recipients. Split it.
out_of_stock
Section titled “out_of_stock”409. The campaign has no stock left for these variations. Offer the player another gift.
external_order_id_conflict
Section titled “external_order_id_conflict”409. Your tenant already has an order with this externalOrderId. orderId names it when the key can see it. If you meant to retry, use the original Idempotency-Key.
not_editable
Section titled “not_editable”409. Delivery details can change only while the order is PROCESSING. currentStatus says where it is now. Message Luxorr instead.
not_cancellable
Section titled “not_cancellable”409. The order or link can no longer be cancelled. currentStatus says where it is now. For an order already SENT, message Luxorr. Cancelling something already CANCELLED is not an error: it answers 200 with the record as it is.
version_conflict
Section titled “version_conflict”409. The record changed since you read it. Read it again and retry with the new version.
internal_error
Section titled “internal_error”500. Server error. Retry; for a POST, reuse the Idempotency-Key. If it continues, contact Luxorr with the time and request.
Field codes
Section titled “Field codes”Inside errors[], each entry has its own code:
| Code | Meaning |
|---|---|
required |
The field is missing or blank, such as recipient.address.postalCode for a country that uses postal codes. |
invalid |
The value is malformed or not allowed. |
too_long |
The value is longer than the field allows. |
duplicate |
The same email appears earlier in the same personal-link batch. |
not_enabled |
The locale is not enabled for your tenant. |
manager_not_found |
A personal-link recipient’s managerEmail names no active member of your team. |
not_allowed_with_catalog_selection |
A personal-link batch sent campaignId together with brandId or productIds. |