Developers
Errors
Every error code the API sends: what causes it, how to fix it, and whether retrying the same request can help.
On this page
The error body
Every error, on every endpoint, is JSON with an HTTP status of 400 or more and this body. Branch on code: it's stable, while message is written for people and its wording can change. request_id matches the X-Request-Id header; log it and quote it when you contact support. details comes with some codes only.
{
"error": {
"code": "NOT_FOUND",
"message": "No such record, report or path, or one your company can't see (another carrier's record, a draft not yet sent to you).",
"request_id": "6f1c2d3e-4b5a-4c6d-8e7f-9a0b1c2d3e4f"
}
}New codes may be added. Treat a code you don't know by its HTTP status: 4xx means fix the request, 5xx means retry later.
Retry or fix?
- Retryable codes can work if you send the same request again later. Wait
Retry-Afterseconds when the answer has it, else back off (1 s, 2 s, 4 s...). Reuse the sameIdempotency-Key, so a write that did go through isn't made twice. - Not retryable codes give the same answer until something changes: fix the request (and use a new
Idempotency-Keyfor the changed request), or re-read the record and decide.
Every code
- 400
VALIDATION_ERRORNot retryable- Cause
- A field, parameter or header is missing or invalid: a bad date, an unknown status, a limit out of range, a cursor this API didn't return, a malformed Idempotency-Key, disputed_minutes longer than the wait, or an offer at or above the charge. details.fields names each one.
- Fix
- Fix the fields listed in details.fields and send it again with a new Idempotency-Key.
- 400
BAD_REQUESTNot retryable- Cause
- The request can't be done as sent: the body isn't valid JSON, nothing is billable (the wait was within free time), a driver-app record has no photo yet, or the file doesn't match its type.
- Fix
- Read message, fix the request, and send it with a new Idempotency-Key.
- 403
FORBIDDENNot retryable- Cause
- The key lacks the scope, its creator is no longer an admin (writes), the company is inactive, or only the other side can do this (only carriers report, send and attach photos; only fuel buyers approve and dispute; only carriers list drivers).
- Fix
- Give the key the scope, create a new key as a current admin, or use the right side's key. message says which.
- 403
PLAN_LIMITNot retryable- Cause
- The carrier's company isn't on the Pro plan, which the API needs (fuel buyers are free).
- Fix
- Upgrade to Pro under Settings > Plan & Billing, then retry.
- 404
NOT_FOUNDNot retryable- Cause
- No such record, report or path, or one your company can't see (another carrier's record, a draft not yet sent to you).
- Fix
- Check the id (and that it belongs to the key's company); list records to find it.
- 405
METHOD_NOT_ALLOWEDNot retryable- Cause
- The path exists but not with this method (for example DELETE /api/v1/records).
- Fix
- Use one of the methods in the Allow header.
- Headers
Allow
- 409
INVALID_STATUSNot retryable- Cause
- the record's status doesn't allow this (it's paid, closed, cancelled, already approved, or withdrawn from you); details.status says which. Re-read it; don't retry.
- Fix
- GET the record, and act on its current status (see the record lifecycle).
- Headers
Retry-After
- 409
OVERLAPPING_WAITNot retryable- Cause
- the driver already has a wait at these times (or this exact one); details.record_id and details.record_number name it.
- Fix
- Use the existing record, or correct the driver or the times.
- Headers
Retry-After
- 409
CONFLICTNot retryable- Cause
- another state of the record rules it out (nothing billable, the buyer's payment terms, a changed amount or offer). Re-read it and decide.
- Fix
- For payment rules (details.reason payment_rules), send again with confirm_nonconforming: true if you mean to; otherwise GET the record and decide.
- Headers
Retry-After
- 409
RECORD_CHANGEDRetryable- Cause
- another action changed the record first. Wait Retry-After seconds and send the same request again.
- Fix
- Wait Retry-After seconds and send the same request (the same Idempotency-Key is fine).
- Headers
Retry-After
- 409
RECORD_LOCKEDRetryable- Cause
- a payment is processing for this record. Wait Retry-After seconds and try again.
- Fix
- Wait Retry-After seconds and send the same request.
- Headers
Retry-After
- 409
IDEMPOTENCY_IN_PROGRESSRetryable- Cause
- a request with this Idempotency-Key is still running. Wait Retry-After seconds and send it again.
- Fix
- Wait Retry-After seconds and send it again with the same key; you'll get the first request's answer.
- Headers
Retry-After
- 409
DELIVERY_IN_PROGRESSRetryable- Cause
- the webhook delivery you asked to resend is being sent right now. Wait Retry-After seconds, then check the delivery log before resending.
- Fix
- Wait Retry-After seconds, GET the delivery, and resend only if it still failed.
- Headers
Retry-After
- 413
PAYLOAD_TOO_LARGENot retryable- Cause
- The body is too big (a photo over 5 MB, a JSON body over its limit), or a saved report's CSV would have more than 50,000 rows.
- Fix
- Send a smaller photo; narrow the report, pass limit, or use format=json.
- 415
UNSUPPORTED_MEDIA_TYPENot retryable- Cause
- The Content-Type isn't one this endpoint takes: a JSON endpoint got a body that isn't application/json (or +json), or a photo isn't image/jpeg or image/png.
- Fix
- Send Content-Type: application/json with a JSON body (a write with no body needs none), or image/jpeg or image/png for a photo.
- 422
IDEMPOTENCY_KEY_REUSEDNot retryable- Cause
- This Idempotency-Key was already used for a different request (the body must be byte-identical); use a new key for a changed request
- Fix
- Send a changed request with a new key. To retry the first request, resend exactly the same bytes with the same key.
- 429
RATE_LIMITEDRetryable- Cause
- Too many requests this minute: over the key's own limit (60 by default), over the company's 3,000 a minute across all its keys, or over 60 a minute with a missing or invalid key from one IP address.
- Fix
- Wait Retry-After seconds, then retry. Spread requests out (X-RateLimit-Remaining and X-RateLimit-Reset say how many are left until when), or raise the key's limit (up to 1,000) in Settings > API Keys.
- Headers
Retry-After
- 500
INTERNAL_ERRORRetryable- Cause
- Something went wrong on Demurly's side.
- Fix
- Retry with backoff (1 s, 2 s, 4 s...) and the same Idempotency-Key; if it keeps happening, email support with the time and the request.
Each endpoint lists the statuses it can answer with on the reference.
details shapes
details is an object whose shape depends on the code. Ignore keys you don't know; new ones may be added.
Payment rules details
CONFLICT from send: the charge doesn't meet the buyer's payment rules. Send again with confirm_nonconforming: true to send it anyway.
reasonstringpayment_rules
problemsarray of objectproblems[].rulestringmin_free_time- The buyer pays only after more free time than this charge gives
max_rate- The charge's hourly rate is above the buyer's maximum
problems[].scopestringcarrier- The buyer set the rule for your company
company- The buyer's rule for every carrier
problems[].messagestringThe problem in words
problems[].required_minutesintegermin_free_time: the free time the buyer expects
problems[].actual_minutesintegermin_free_time: the free time this charge gives
problems[].max_rate_centsintegermax_rate: the buyer's maximum hourly rate, in cents
problems[].actual_rate_centsintegermax_rate: this charge's hourly rate, in cents
confirm_withstringThe request field that sends it anyway
confirm_nonconforming
{
"reason": "payment_rules",
"problems": [
{
"rule": "max_rate",
"scope": "carrier",
"message": "The buyer's maximum rate is $50.00 an hour; this charge is $100.00.",
"max_rate_cents": 5000,
"actual_rate_cents": 10000
}
],
"confirm_with": "confirm_nonconforming"
}Overlapping wait details
OVERLAPPING_WAIT: the driver's other wait
reasonstringoverlapping_wait
record_idstring (uuid)record_numberstringstart_timestring (date-time)end_timestring (date-time)can be nullstatusstring
{
"reason": "overlapping_wait",
"record_id": "3f6c1d2e-8a4b-4c1e-9f0a-1b2c3d4e5f60",
"record_number": "DMR-00001042",
"start_time": "2026-01-15T14:30:00.000Z",
"end_time": "2026-01-15T17:45:00.000Z",
"status": "sent_to_customer"
}Invalid status details
INVALID_STATUS: the status the record is in
statusstringA record status, or withdrawn for a charge withdrawn from you
{
"status": "customer_approved"
}Validation error details
VALIDATION_ERROR: what's wrong with each field
fieldsobjectField name (dotted for nested fields; "_" for the body as a whole) to its messages
{
"fields": {
"start_time": [
"Required"
],
"end_time": [
"end_time can't be in the future"
]
}
}