Beta

API errors

Every error code the Koutei PDF API can answer with: what it means, whether a credit was used, and what to do next. The docs_url in an error opens its section on this page.

The shape of an error

An error is always JSON, whatever the request asked for. This is the answer to a request with two mistakes (a missing client name and a date that does not exist):

{
  "error": {
    "code": "validation_failed",
    "message": "2 fields need attention.",
    "details": [
      {
        "field": "fields.client_name",
        "code": "required",
        "message": "client_name is required."
      },
      {
        "field": "fields.date",
        "code": "invalid_date",
        "message": "date must be a real date such as 2026-10-12."
      }
    ],
    "request_id": "req_…",
    "docs_url": "https://kouteisystems.com/docs/api/errors#validation_failed"
  },
  "credit_used": false
}
  • code says what happened. Codes do not change; message texts may, so write your code against the codes.
  • details, when present, lists each problem with its own code and, where it applies, the field it is about, as a path from the top of the body. It holds at most 50 entries.
  • request_id identifies the request. It is also in the Koutei-Request-Id header. Quote it if you write to support@kouteisystems.com.
  • credit_used is on every JSON answer to a document request. false means no credit was used. null means we could not confirm it either way: send the same request again with the same Idempotency-Key and you are charged once at most.
  • New codes may be added. Treat a code you do not know by its HTTP status.

The API reference covers the routes, fields and limits these errors refer to.

400 invalid_request

The request itself is malformed: the body is not valid JSON, a top-level name is unknown or missing, or a header, query value or option has a value the API does not accept.

What to do: Read details: each entry names the part of the request and why it was refused. Fix it and send the request again.

credit_used: false.

Detail codes of invalid_request
Detail codeWhat it means
malformed_jsonThe body is not valid JSON, is not valid UTF-8, or repeats a name inside one object.
wrong_typeA value has the wrong JSON type, such as text where an object is expected. A null for an optional top-level parameter counts too.
unknown_parameterA top-level name the API does not know.
requiredSomething required is missing, null or blank: template, mode or fields at the top level, or a required field.
unsupported_valueA value outside the accepted list for mode, paper, locale or output.
unsupported_versionThe Koutei-Version header names a version the API does not have.
invalid_idempotency_keyThe Idempotency-Key header is empty, too long or has characters outside visible ASCII.
invalid_referenceThe reference label is empty, too long, has characters outside printable ASCII, or starts or ends with a space.
invalid_template_versiontemplate_version is not a major version written as digits, such as "2".
invalid_queryA query value of GET /api/v1/documents is not accepted, or starting_after is not one of your documents.

400 reserved_field

The request uses a name that is held for a later version of the API. It wins over any field problem, so you get this error alone.

What to do: Remove the name. The API reference lists the reserved names.

credit_used: false.

Detail codes of reserved_field
Detail codeWhat it means
reservedThe name is held for a later version.

401 unauthorized

The key is missing, malformed, unknown or revoked. The answer never says whether a key once existed.

What to do: Send "Authorization: Bearer" followed by a key that starts with kt_live_. Create one in Settings. A key that starts with sk_live_ never works; create a new one.

credit_used: false.

Detail codes of unauthorized
Detail codeWhat it means
missing_authorizationThere is no Authorization header.
invalid_keyThe key is not valid.

402 insufficient_credits

The account has no credit left for a final document. The body adds credits_remaining and period_end, the end of the current credit period.

What to do: Wait for the next credit period or change your plan. Previews and validation still work without credits.

credit_used: false.

403 forbidden_scope

The key is valid, but it is not allowed to do this. A Preview only key cannot make a final document.

What to do: Use a key with the scope the route needs, or create a Full access key in Settings.

credit_used: false.

Detail codes of forbidden_scope
Detail codeWhat it means
missing_scopeThe key lacks the scope for this route or mode.

404 not_found

There is no such path under /api/v1. Every path answers this while the API is switched off.

What to do: Check the path against the API reference.

credit_used: false.

404 template_not_found

There is no API template with that name. Templates that exist only in the web app are not offered here.

What to do: GET /api/v1/templates lists the templates you can use.

credit_used: false.

404 document_not_found

There is no such document in your history: the id is wrong, the document belongs to another account, or it is older than the history keeps.

What to do: Check the id. GET /api/v1/documents lists the documents you can read.

credit_used: not stated (this is not a document request).

404 file_not_available

Koutei does not store documents, so this route always answers this.

What to do: The file is only in the response to POST /api/v1/documents. To get it again, repeat that request with the same Idempotency-Key while the key is still remembered.

credit_used: not stated (this is not a document request).

405 method_not_allowed

The path exists, but not for this method. The Allow header lists the methods it takes.

What to do: Use one of the methods in the Allow header.

credit_used: false.

409 template_version_unavailable

The request pins a template major version that is not the current one. The API never renders a different version in its place.

What to do: Check the template’s current version with GET /api/v1/templates, then update the pin and your fields.

credit_used: false.

Detail codes of template_version_unavailable
Detail codeWhat it means
major_mismatchThe pinned major is not the template’s current major.

409 idempotency_in_progress

A request with the same Idempotency-Key is still running.

What to do: Wait for the number of seconds in Retry-After and send the same request again. You get the finished document, or the request runs.

credit_used: false. The answer carries a Retry-After header, in seconds.

409 idempotency_replay_unavailable

The Idempotency-Key was used for a document that can no longer be made byte for byte, because the template changed since. The API never returns different bytes under an old document id.

What to do: To make the document again, send the request with a new Idempotency-Key. That is a new document and uses a credit.

credit_used: false.

Detail codes of idempotency_replay_unavailable
Detail codeWhat it means
template_version_changedThe template has a newer version than the one the document was made with.
output_changedMaking the document again no longer gives the recorded bytes.

413 payload_too_large

The request body is larger than the API accepts.

What to do: Send a smaller body. The API reference lists the size limit.

credit_used: false.

413 response_too_large

The PDF came out larger than the API can send back. Nothing was charged.

What to do: Make the document smaller, or ask for the file itself instead of JSON: the file form has the larger limit.

credit_used: false.

415 unsupported_media_type

The body is not sent as JSON.

What to do: Send "Content-Type: application/json", in UTF-8.

credit_used: false.

422 validation_failed

One or more fields were refused. Every problem is listed at once, not only the first.

What to do: Read details: each entry gives the field, a code and a message. Fix them all and send the request again.

credit_used: false.

Detail codes of validation_failed
Detail codeWhat it means
wrong_typeA value has the wrong JSON type, such as text where an object is expected. A null for an optional top-level parameter counts too.
requiredSomething required is missing, null or blank: template, mode or fields at the top level, or a required field.
unknown_fieldThe template has no field with that name. A misspelt name is refused, never dropped.
too_longThe value has more characters than its type allows.
line_break_not_allowedA one-line value contains a line break.
invalid_charactersThe value contains control characters or other characters the API refuses.
invalid_dateNot a real calendar date written as YYYY-MM-DD.
not_one_ofNot one of the values the field lists. The match is exact and case-sensitive.
not_a_numberNot a number the API can read.
too_many_digitsThe number has more digits than the API accepts.
too_many_decimalsThe amount has more decimal places than its currency has.
out_of_rangeThe number is below or above what the field accepts, such as a negative amount or a percentage that is too high.
must_be_positiveThe amount must be more than 0.
unsupported_currencyNot one of the currency codes the API accepts: three capital letters, no symbol.
no_itemsThe list of line items is empty.
too_many_itemsThere are more line items than the API accepts.
items_or_amountA quote needs line items or a fixed amount: exactly one of the two.
requires_fieldThe field only makes sense with another one that is missing: tax_label needs tax_rate.
conflicting_fieldsA field and its older name were both sent. Send one.
discount_too_largeThe discount is more than the subtotal.
amount_paid_too_largeThe amount paid is more than the total.
negative_totalThe line items add up to less than 0.
total_too_largeThe subtotal is too large to print.
too_many_fieldsfields has more names than the API accepts.
invalid_urlNot a plain https:// web address: another scheme such as http:, spaces, characters outside ASCII, a user name or password, or a host name that is not written plainly. The message says which.

422 idempotency_key_reused

The Idempotency-Key was already used for a different request. A changed reference counts as a different request.

What to do: Send the original request again unchanged, or use a new key for the new request.

credit_used: false.

422 render_rejected

The template refused input that validation had accepted. That is a fault on our side, and it is logged.

What to do: Nothing was charged. Tell us the request_id so we can find it.

credit_used: false.

429 rate_limited

A limit was reached. details names which one.

What to do: Wait for the number of seconds in Retry-After, then try again. The RateLimit headers show how much of your limit is left.

credit_used: false. The answer carries a Retry-After header, in seconds.

Detail codes of rate_limited
Detail codeWhat it means
final_key_limitThis key made too many new final documents in the current minute.
request_key_limitThis key sent too many requests in the current minute.
preview_user_limitThe account made too many previews this hour or today, across every key and the web app.
preview_key_limitThis key made too many previews this hour or today.
auth_failure_limitToo many requests with a missing or wrong key came from this network. A valid key is never refused for this.
replay_limitThis key, or its account, replayed stored documents too often in this window: a replay renders the document again. Nothing was charged; the Idempotency-Key still replays after Retry-After.

500 commit_status_unknown

The document was made, but we could not confirm whether the credit was taken, so credit_used is null.

What to do: Wait 35 seconds and send the same request with the same Idempotency-Key. If the credit was taken, you get the document without another one; if not, it is charged once.

credit_used: null (unknown: retry with the same Idempotency-Key).

500 internal_error

Something failed on our side. credit_used is false unless the charge had already started, in which case it is null.

What to do: Try again with the same Idempotency-Key. If it keeps happening, tell us the request_id.

credit_used: false, or null (unknown: retry with the same Idempotency-Key).

502 engine_unavailable

The service that makes the PDF could not be reached. Nothing was charged.

What to do: Try again shortly with the same Idempotency-Key.

credit_used: false.

503 engine_busy

The service that makes the PDF is at capacity. Nothing was charged.

What to do: Wait for the number of seconds in Retry-After, then try again.

credit_used: false. The answer carries a Retry-After header, in seconds.

503 service_busy

A shared limit was reached, or a part of the service that the request needs could not be reached. The request was not processed and nothing was charged.

What to do: Wait for the number of seconds in Retry-After, then try again.

credit_used: false. The answer carries a Retry-After header, in seconds.

Detail codes of service_busy
Detail codeWhat it means
preview_global_limitToo many previews are being made by everyone together.
limiter_unavailableThe rate limiter could not be reached, so the request was not processed.

504 render_timeout

The document took too long to make. Nothing was charged.

What to do: Try again. If the same document keeps timing out, make it smaller.

credit_used: false.