Error format
Errors are returned as application/problem+json (RFC 9457):
{
"type": "https://www.promogator.com/on-demand/docs/errors#error-validation-failed",
"title": "The order cannot be priced as sent",
"status": 422,
"detail": "SKU ST-WILD-SPT-PNK-L is not on your product list.",
"instance": "/api/on-demand/v1/orders",
"code": "validation_failed",
"request_id": "req_8fK2mQ0aB1cD3eF4",
"errors": [ { "detail": "SKU ST-WILD-SPT-PNK-L is not on your product list." } ]
}
Write your code against code: it never changes. title and detail are written for people and may be reworded. Quote request_id when you contact us.
Error codes
| Status | Code | What to do |
|---|---|---|
| 400 | credentials_in_url |
Move credentials to the Authorization header and roll the key |
| 400 | idempotency_key_required |
Add an Idempotency-Key header |
| 401 | unauthorized |
Send Authorization: Bearer <token> |
| 401 | invalid_token |
Get a new token |
| 401 | token_expired |
Get a new token and retry |
| 402 | card_declined |
Fix the card; nothing was ordered |
| 402 | authentication_required |
The bank wants approval; contact us |
| 402 | payment_method_required |
Add a card on the Billing tab |
| 402 | payment_failed |
Retry later, or contact us |
| 403 | insufficient_scope |
Use a key with the scope in required_scope |
| 403 | ip_not_allowed |
Call from an allowed address |
| 403 | api_not_enabled |
Live access is not on yet: use your test key |
| 403 | sandbox_not_enabled |
Ask us to switch test mode on |
| 403 | partner_suspended |
Your account is paused; contact us |
| 404 | not_found |
Check the id and the mode (test or live) |
| 409 | idempotency_conflict |
Use a new key for a different order |
| 409 | duplicate_external_id |
Fetch the existing order |
| 409 | not_cancellable |
Too late to cancel; contact us |
| 409 | account_incomplete |
Contact us |
| 415 | unsupported_media_type |
Send Content-Type: application/json |
| 422 | validation_failed |
Fix what errors[] describes |
| 422 | limit_exceeded |
A new live key's probation limit, or too many webhook endpoints |
| 429 | rate_limited |
Wait Retry-After seconds |
| 500 | internal_error |
Retry with the same Idempotency-Key |
| 503 | api_unavailable |
Try again later |
| 503 | read_only |
Reads work; retry writes later |
credentials_in_url
A token, key or secret was in the URL. URLs end up in logs, so the request is refused. Send credentials only in the Authorization header, and roll the key: its secret may already be in a log.
idempotency_key_required
POST /orders needs an Idempotency-Key header of up to 255 characters.
unauthorized
No Authorization: Bearer … header. Get a token from POST /oauth/token.
invalid_token
The token is unknown, or its key was revoked or rolled. Get a new token.
token_expired
The token is older than 60 minutes. Get a new token and send the request again.
card_declined
Your card was declined. decline_code has the bank's reason. No order was created and nothing was charged. Update the card on the Billing tab and send the order again (a new request, so use a new Idempotency-Key).
authentication_required
Your bank asked for extra approval of the charge. No order was created. Contact us.
payment_method_required
Your account bills a card but none is saved with permission for automatic charges. Add one on the Billing tab.
payment_failed
The payment could not be completed. No order was created. Try again later or contact us.
insufficient_scope
The token does not have the scope this call needs; required_scope names it. Use a key with that scope.
ip_not_allowed
The key is limited to certain IP addresses and this call came from another one.
api_not_enabled
A live key was used before live access was switched on for your account. Use your test key, or ask us for live access.
sandbox_not_enabled
Test mode is switched off for your account. Ask us to switch it on.
partner_suspended
Your partner account is paused. Reads keep working; new orders are refused. Contact us.
not_found
No such object in your account, or it belongs to the other mode: test keys only see test objects and live keys only live ones.
idempotency_conflict
The Idempotency-Key was already used with a different request body. Each order needs its own key.
duplicate_external_id
An order with this external_id already exists. Fetch it with GET /orders/by-external-id/{external_id} instead of sending it again.
not_cancellable
The order can no longer be cancelled: the 24-hour window has closed, production has started, or it is already cancelled. detail says which. Contact us if you still need a change.
account_incomplete
Your partner account is missing something we need to place orders. Contact us.
unsupported_media_type
Send JSON with Content-Type: application/json.
validation_failed
The request cannot be accepted as sent. Each problem is in errors[] (with a pointer for field errors). Common causes: a missing required field, an unknown field, a SKU that is not on your product list, a quantity under the product's minimum, an address outside the US, a product that ships by freight, or an order over your maximum order value or orders-per-day limit.
limit_exceeded
A new live key is on probation for its first 24 hours and can place up to 3 orders or $500.00 in that time; ask us to end probation early. Also returned when you try to add a sixth webhook endpoint in one mode.
rate_limited
Too many requests. Wait the number of seconds in the Retry-After header, then retry.
internal_error
Something went wrong on our side. Nothing was charged. Retry with the same Idempotency-Key, and contact us with the request_id if it keeps happening.
api_unavailable
The API is switched off for maintenance. Nothing was charged. Try again later.
read_only
The API is read-only for a while: reads work, new orders and quotes are paused. Retry later.
Rate limits
| What | Limit |
|---|---|
Reads (GET) |
300 requests a minute per key |
Writes (POST, PATCH, DELETE) |
60 requests a minute per key |
POST /oauth/token |
20 requests a minute per key |
Over the limit you get 429 with a Retry-After header (seconds).
Order limits
Each account has a maximum order value and a maximum number of orders per day, shown in GET /account under limits. An order over a limit is refused with 422 validation_failed and a message naming the limit. A new live key is also on probation for its first 24 hours: up to 3 orders or $500.00. Ask us to raise a limit or end probation early.
Idempotency
Networks fail. An Idempotency-Key makes it safe to retry POST /orders:
- Send a unique
Idempotency-Keywith every new order (your store's order id works well). - If you do not get a response, send the same request with the same key. If we already placed the order, you get it back (
200withIdempotent-Replayed: true) instead of a second order. - The same key with a different body is refused with
409 idempotency_conflict. external_idis a second safety net: an order number can only be used once in your account.
After a 402 payment error no order exists, so fix the card and send the order with a new key.