Errors
Errors use HTTP status codes and a JSON body with a stable, machine-readable code, a message for people, and the request's ID.
402 application/json
{
"error": {
"code": "quota_exceeded",
"message": "This organisation has used all 1,000 marks of this month on its plan. Upgrade the plan for more, or wait for the 1st of next month (UTC).",
"request_id": "req_7Hc2kQm0Zt1L"
}
}Branch on code, never on message: codes are part of API v1 and won't change; messages may get clearer. Every response, success or not, carries the same ID in its X-Request-Id header. Quote it when you write to us.
Codes
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 400 | invalid_request | The request is malformed or a field is out of range. | Fix the request; the message names the field. |
| 400 | unknown_field | A field the endpoint doesn't know. | Check the field's spelling against the reference. |
| 400 | option_not_available | An option of a later release. | Leave it out for now; the changelog says when it arrives. |
| 401 | missing_api_key | No bearer key in the Authorization header. | Send Authorization: Bearer sk_…. |
| 401 | invalid_api_key | The key isn't one of ours. | Check the key; create a new one if it's lost. |
| 401 | api_key_revoked | The key was revoked or its project deleted. | Use another key. |
| 402 | quota_exceeded | The month's allowance is used up. | Wait for the 1st of the month (UTC), or upgrade. |
| 403 | insufficient_scope | The key lacks this endpoint's scope. | Use a key with the scope, or create one. |
| 403 | ip_not_allowed | The address isn't on the key's IP allowlist. | Call from an allowed address, or update the allowlist. |
| 403 | key_not_allowed_in_url | A key with scopes beyond tsa was sent in a URL. | Use a tsa-only key, and rotate the one you sent. |
| 404 | not_found | No endpoint at this path. | Check the path and the API version. |
| 404 | upload_not_found | The upload named in "upload" isn't one this key can use: unknown, used, older than an hour, or made by another key. | Make a new upload with this key (POST /v1/uploads). |
| 405 | method_not_allowed | The endpoint doesn't take this method. | See the Allow header. |
| 413 | payload_too_large | The body is over the endpoint's limit. | 4 MB per request: send larger files (up to 25 MB) through POST /v1/uploads. 4 KB for time-stamp queries. |
| 415 | unsupported_media_type | The file or the request's Content-Type isn't accepted. | Send PNG, JPEG or WebP as multipart/form-data. |
| 422 | content_blocked | POST /v1/mark: the safety check blocked the picture; nothing was marked. The body's "safety" says why. | Don't retry the same picture. The checks it ran count; the mark doesn't. |
| 429 | rate_limited | Too many calls this minute for this key. | Wait Retry-After seconds, then retry. |
| 500 | internal_error | Something failed on our side. | Retry with backoff; nothing was charged. |
| 502 | mark_failed | The file couldn't be marked and verified; no file was returned. | Retry once; if it persists, contact support with the request ID. |
| 503 | marker_unavailable | The marking service is briefly unavailable. | Retry with backoff; nothing was charged. |
| 503 | tsa_unavailable | The time-stamp server is briefly unavailable. | Retry with backoff; nothing was charged. |
| 503 | storage_unavailable | Uploads are briefly unavailable. | Retry with backoff; nothing was charged, and the upload is kept. |
Retrying
429: wait the number of seconds inRetry-After.500,502,503: retry with exponential backoff (1 s, 2 s, 4 s…), up to a few times. Failed calls are never counted against your allowance.- Other
4xx: don't retry unchanged; fix the request first.