Errors & recovery

Recover from errors without duplicating work.

Never parse a message string to decide what to do. Branch on the HTTP status, error.code and retryable, and keep the request ID, document ID and idempotency key so you can recover or ask for help.

On this page

Find your error code

Select your error.code to jump to what to do. Each row explains its codes under “Code-specific guidance”. Got no response or no code? See the timeout and SDK rows later in the table.

Terminal processing error codes

These codes appear on a document whose status is failed. That status is final: retrying a GET or upload-complete does not restart processing. They are different from the SDK timing out while processing continues on the server.

Code not listed? Use the unknown-code guidance.

What to do for each error

A needs_review result is not an error, and retrying does not change it. When required fields, line-item rules or duplicate checks send a result to review, read its checks and the document’s review policy settings.

What happenedRetry?What to keep or changeDocument and billing
Invalid request fields
  • invalid_request

Not until you fix the rejected fields.

Code-specific guidance
invalid_request HTTP 400
The request body, headers, query parameters or path did not validate.
error.details.issues lists the rejected fields when present. Fix them and send the create again. If the document already exists, keep its original request body and key instead of changing them.The request was rejected, not your file: this does not mean the uploaded file is corrupt. Keep any document ID you already have.
Invalid callback URL
  • invalid_callback_url

Fix the callback URL, or leave it out, and send the create again.

Code-specific guidance
invalid_callback_url HTTP 400
The optional callback URL was rejected. Returned when the callback URL is the only invalid body field; an oversized file or unsupported content type is reported first, and any other invalid field makes the request fail with invalid_request.
Use a public HTTPS destination with no credentials or fragment. If a document already exists for this idempotency key, do not change its request body.Only the callback was rejected; your file was not checked. Uploading the file again does not fix it.
Invalid API key or forbidden operation
  • invalid_api_key
  • forbidden

No. Fix the API key or account access first.

Code-specific guidance
invalid_api_key HTTP 401
The API key was not accepted.
forbidden HTTP 403
This account or key is not allowed to perform this operation. Normal API-key requests do not receive this code.
Do not upload invoice files until the key is accepted.The rejected request created nothing. Documents you created earlier are unaffected.
Billing required or Trial allowance exhausted
  • billing_required
  • usage_limit_exceeded

After you fix billing or upgrade. Retry create with the same body and key, or retry upload-complete for the same document.

Code-specific guidance
billing_required HTTP 402
No active plan or allowance covers processing. A rejected upload-complete can be retried after you fix billing; a document that has already failed with this code cannot.
usage_limit_exceeded
The whole document does not fit in the remaining Trial allowance. Upgrade before trying again. Returned only as a failed document’s error, not as an HTTP error.
After a billing error on upload-complete, do not upload the file again. If a document has already failed with this code, it cannot be resumed; trying again means a new document with a new key.Rejected before processing, so not billed. Keep the document ID. A Trial never processes part of a document to fit the remaining allowance.
File is too large
  • document_too_large

Not with the same file. Send a file of 20 MiB or less.

Code-specific guidance
document_too_large HTTP 413
The declared or uploaded file is larger than 20 MiB.
Declare the exact byte count. If the oversized file was already uploaded, create a new document for the smaller file; an uploaded file cannot be replaced.This is about file size only. It is not a page-limit or Trial-allowance error.
Unsupported or mismatched content type
  • unsupported_content_type

Use a PDF, JPEG, or PNG with the matching content_type.

Code-specific guidance
unsupported_content_type HTTP 415
The declared content type is not supported, or the uploaded file does not match it.
At create, correct content_type and send again. At upload-complete, the uploaded file cannot be replaced, so create a new document.Renaming the file or changing its content type does not turn an unsupported file into a supported one.
Invalid, corrupt, or unsupported file
  • upload_size_mismatch
  • invalid_document
  • corrupt_pdf
  • encrypted_pdf
  • unsupported_document_type
  • multiple_invoices_detected

Not with the same file. Fix the file, or its declared size or type, first.

Code-specific guidance
upload_size_mismatch HTTP 422
The uploaded file size differs from file_size_bytes. Create a new document with the correct file and byte count.
invalid_document
The file’s contents are not a valid PDF, JPEG, or PNG, or do not match the declared content_type. Returned only as a failed document’s error, not as an HTTP error.
corrupt_pdf
The PDF is corrupt. Export a valid copy and submit it as a new document.
encrypted_pdf
The PDF is encrypted. Submit an unencrypted copy you are allowed to process.
unsupported_document_type
The file is not a supported invoice. Changing its content type does not change that.
multiple_invoices_detected
The file contains more than one invoice. Submit each complete invoice separately, even when invoices share a page.
A wrong size or type on an uploaded file needs a new document. Retrying does not fix corrupt or unsupported content, and a failed document stays failed.No usable result. Files rejected before processing are not billed. A corrected file is a new submission with its own idempotency key.
Upload window expired
  • upload_expired

No. An upload_expired response means the upload window is closed, and retrying does not reopen it.

Code-specific guidance
upload_expired HTTP 410
The upload window for this document is closed. This is more than an expired signed URL.
If only the signed upload URL expired and the API has not returned upload_expired, replay create with the same body and key to get a fresh URL. Start a new submission with a new key only after upload_expired. Never change the key just because a request timed out.The old upload URL no longer works, and no replacement document is created. If a create replay returns 200 awaiting_upload, call upload-complete first to check whether the file already arrived.
File not received
  • upload_not_complete

Yes: upload the complete file again while the signed upload URL is still valid.

Code-specific guidance
upload_not_complete HTTP 409
The file is not in storage. You may upload the complete file while the upload URL is still valid.
The API has confirmed the file is not in storage. Send only the headers returned with the upload URL, never your API key.Use the same document and upload path; do not create a second document.
Idempotency conflict
  • idempotency_conflict

Not with a changed body under the same key.

Code-specific guidance
idempotency_conflict HTTP 409
The same key was sent with a different create request body.
Send the original create body again, or use a new key only if this is a genuinely different invoice.A document may already exist for the original request. The conflict itself is not billed.
Operation does not fit the document’s status
  • invalid_document_state

Retrieve the document and choose the operation its current status allows.

Code-specific guidance
invalid_document_state HTTP 409
The operation is not allowed for the document’s current status. Reserved: the API does not currently return this code.
Keep the document ID. This code does not mean the file is missing: do not upload again or create a replacement because of it.Processing may be underway or already finished. Polling a failed document does not restart it.
Rate limit or service temporarily unavailable
  • rate_limit_exceeded
  • service_unavailable

Yes, a limited number of times when retryable is true; treat Retry-After as a minimum delay.

Code-specific guidance
rate_limit_exceeded HTTP 429
Too many requests. Wait at least Retry-After, then retry a limited number of times. Create and upload-complete enforce rate limits today; the other operations reserve this response.
service_unavailable HTTP 503
The service is temporarily unavailable. Retry the same request a limited number of times when retryable is true.
Retry the same request: the same create body and key, or upload-complete for the same document. A retried upload-complete is never a reason to upload the file again.A document may already exist, so keep its ID and key. A 5xx status alone does not mean you may retry; check retryable.
Internal error
  • internal_error

No automatic retry when retryable is false. An HTTP 500 alone does not mean you may retry. Contact support with the request ID if needed.

Code-specific guidance
internal_error HTTP 500
Something failed on our side. An HTTP 500 alone does not mean you may retry; check retryable and keep the request ID.
Keep the document ID and the exact create body and key. A failed response does not prove that nothing happened, so do not replace the document or upload again outside the steps on this page.A document or processing run may already exist. Retry the same request only when retryable is true.
Create timed out or returned no response

Yes: send the exact create body and idempotency key again.

Never change the key just because the response was lost or timed out.The document may already exist; the replay returns it.
File upload outcome unknown

Call upload-complete before uploading again; it tells you whether the file arrived.

Upload again only after upload-complete returns upload_not_complete, and only while the signed upload URL is still valid.Use the same document; the file may already be in storage.
upload-complete outcome unknown

Retry upload-complete for the same document.

Do not upload the file again and do not create a replacement document.Processing may already be queued or finished.
SDK cancelled or stopped waiting

The SDK stops waiting, but server-side work is not cancelled: processing continues.

Resume with an authenticated GET using the document ID, or recover it with the same idempotency key.The document may still finish, and is billed normally if it does.
Result expired or document not found
  • document_not_found
  • document_expired

No. Do not treat either response as a successful DELETE or a completed result.

Code-specific guidance
document_not_found HTTP 404
The document does not exist in this account or was deleted. Never treat this as a successful DELETE.
document_expired HTTP 410
The document passed its deadline: its retained result expired, or its upload window closed without a confirmed upload. It cannot be retrieved again.
Check the document ID and the account. Save results before result_expires_at; an expired result cannot be recovered. A 404 is final.No result was returned, and no new document was created.
Usage period not available
  • usage_period_not_found

Choose a closed period that still exists, or omit periods_ago for current usage.

Code-specific guidance
usage_period_not_found HTTP 404
The requested closed billing period does not exist for this account.
This is a usage-query error; do not resubmit or delete an invoice.The period does not exist for this account. It does not mean a document was deleted or that usage was zero.
Processing failed or timed out
  • document_processing_failed
  • processing_timeout
  • ocr_failed
  • semantic_extraction_failed

No. The document has reached its final failed status, and polling does not restart it. Check retryable, and contact support with the document ID if needed.

Code-specific guidance
document_processing_failed
Processing ended without a usable result.
processing_timeout
Processing took longer than its server-side time limit.
ocr_failed
Reading the document’s text and layout failed. No usable result was produced.
semantic_extraction_failed
Extracting structured invoice data failed. No usable result was produced.
Do not automatically change the key or upload again. To try again, submit a new document on purpose, with a new idempotency key.No usable result, and genuine processing failures are not billed. processing_timeout is a server-side time limit, different from the SDK giving up on polling.
Page, complexity, or result-size limit
  • document_page_limit_exceeded
  • document_complexity_limit_exceeded
  • result_too_large

Not with the same file. Check the limit and send a supported version of the complete invoice, or ask for help.

Code-specific guidance
document_page_limit_exceeded
The file has more than 20 pages.
document_complexity_limit_exceeded
The file or extracted invoice exceeds a safe processing limit, for example an oversized image, an overly complex or malformed PDF, or more than 500 line items or 500 tax components.
result_too_large
The extracted result is larger than the supported size. Changing the content type or plan does not help.
The failed document is final. Do not split one invoice into parts or remove content to fit a limit. A suitable replacement is a new submission.No usable result; limit failures are not billed. Overage or a larger plan does not raise these limits.

Rejected fields

When the API rejects request input, error.details.issues lists each rejected input, at most 20. Fix every listed input before you send the request again.

locationstring

Where the input is: body, query, header, or path.

pathstring

A JSON Pointer to the input, such as /policy/line_items.

codestring

A stable code to branch on. See the request issue codes.

messagestring

An explanation for people. Never branch on it.

Issue codeMeaning
required

A required field or value is missing.

invalid_type

The value has the wrong JSON type.

invalid_value

The value is not one of the allowed values.

invalid_format

The value does not have the required format.

too_large

The value is longer, larger or has more items than allowed.

too_small

The value is shorter, smaller or has fewer items than allowed.

unknown_field

The field is not accepted here.

malformed

The body or path could not be read, such as JSON that does not parse.

invalid

The value breaks another rule, which message describes.

Codes you do not recognize

New codes may be added over time. Keep an unknown code for logging and display, then fall back on fields you already handle. For an API error, use the HTTP status and retryable. For a check, use its status, severity, paths and validation.review_required. A document that failed with an unknown code is still failed for good.

Return to the error-code lookup

SDK errors versus failed documents

The SDK’s wait and process return a failed document normally; they do not throw for it. They throw when you cancel, when polling times out, when a response is invalid, or when the API returns an error. A polling timeout does not stop processing on the server: resume with a GET using the document ID.

Callbacks

A callback tells you a document has finished. It is a notification, not the result: always fetch the document to see what happened.

  1. Receive document.finished.
  2. Read its event ID and document ID. Use them only to decide which document to fetch.
  3. Fetch that document with an authenticated GET.
  4. Check that the fetched callback.event_id matches the event ID you received, then act on the fetched document.

Callbacks are not signed, and you set the callback URL on each document; there is no webhook endpoint to register. Fetch the document promptly and store only what your workflow needs.

Keep secrets and personal data out of callback URLs, because the platform logs of Vercel, our hosting provider, may retain them. Workflow resume URLs, such as n8n’s, can be secrets themselves; poll instead if that is a problem. See the retention limits.

Callback body

idstring

The event's ID. The fetched document's callback.event_id matches it.

objectstring

The resource type.

Valueevent

typestring

The event type.

Valuedocument.finished

created_atdate-time

When the event was created.

dataobject

Which document finished.

3 child fields

document_idstring

The document to fetch.

external_idstring · nullable

Your own reference from create document, or null.

Length
1–255 characters

accounting_entity_idstring · nullable

Your accounting entity from create document, or null.

Length
1–255 characters

Callback delivery errors

When a delivery attempt fails, the document’s callback.last_error_code says why. Temlavo retries temporary failures, making up to 8 attempts within 24 hours of the event, and keeps the delivery pending meanwhile; callback.next_attempt_at shows the next one. A permanent failure, or running out of attempts or time, makes it failed. After a 429 or 503, a reasonable Retry-After sets the minimum wait, but never extends the window. A failed callback never changes the document: fetch it whenever you need its result.

last_error_codeMeaningTemlavo retries
dns_error

The callback hostname could not be resolved. Fix: Publish public DNS records for the callback hostname.

Yes
unsafe_destination

The callback URL is not a valid destination, or its hostname resolves to no address or to a loopback, private, reserved or other non-public address. Fix: Use a hostname whose DNS answers are all public addresses, and give later documents the corrected callback_url.

No
connection_error

The connection or TLS handshake failed or was reset, or the response could not be read, for example an invalid status line. Fix: Accept HTTPS connections on port 443 and answer with a valid HTTP response.

Yes
timeout

No response status arrived within the attempt’s time budget, which covers DNS, connection, TLS and the response. Fix: Answer with a 2xx as soon as the event arrives, and do slow work afterwards.

Yes
tls_error

The endpoint’s certificate failed verification, for example because it is self-signed, expired or not yet valid, missing intermediate certificates, or issued for another hostname. Fix: Serve a currently valid certificate for the callback hostname from a publicly trusted authority, with its full intermediate chain.

No
http_error

The endpoint answered with a status other than 2xx, which callback.last_http_status holds. Redirects are not followed. Fix: Answer at the exact callback URL with a 2xx once the event is received.

For 408, 425, 429, 5xx
response_too_large

The endpoint’s response headers exceeded the size limit. Fix: Keep response headers small; delivery reads only the status and Retry-After.

Yes

Result retention and deletion

Temlavo is not a long-term invoice archive. Results are kept for 7 days by default, and processing.result_expires_at gives the exact deadline. After it, retrieving the document returns 410 document_expired; that is expected, not a fault.

DELETE ends API access to a document and clears its stored result and fields. Storage deletion is attempted immediately and retried if needed. Some records remain after a document is deleted: your account’s discovery index of accounting-entity IDs (the accounting_entity_id values you have used, kept while the account is open), required financial and security records, and the platform logs of Vercel, our hosting provider. Deleting a document does not close your account. See the Privacy Notice's retention and account-closure details.

Your own database, callback handler, CLI output, CI logs, and n8n execution history are outside Temlavo retention and deletion control.

Support and debugging

When you ask for help, include the X-Request-Id, document ID and idempotency key. Do not send your API key, a signed upload URL, the invoice file, the full result, or provider details in your first message.

Contact support with the safe identifiers above and a short description of the issue.