Errors & recovery
Recover the resource, not just the request.
Never parse a message string for control flow. Preserve the HTTP status,error.code, retryable, request ID, and any safe SDK recovery context such as document ID or idempotency key.
On this page
Find your error code
Select the exact error.code to jump to its recovery row. Expand that row’s code-specific guidance for its meaning. No response or code? Use the transport and SDK scenarios below.
Terminal processing error codes
These codes arrive on a failed document. The document is already terminal; retrying a GET or confirmation does not restart it. They are distinct from a local SDK timeout while work continues.
Recovery boundaries
A needs_review result is not a transport failure to retry. When required fields, line-item acceptance or duplicate checks cause review, inspect the returned findings and the document’s review policy settings.
| What happened | Retry? | Identity and bytes | Resource / billing |
|---|---|---|---|
Invalid request fields
| Correct the rejected fields before retrying; no blind retry. Code-specific guidance
| Inspect error.details.issues when present. A rejected create may be corrected; if a document already exists, recover its original identity instead of changing the body behind its key. | This is request validation, not proof that uploaded bytes are corrupt. Preserve any known document ID. |
Invalid callback URL
| Correct or omit the optional callback URL before a valid create. Code-specific guidance
| Use an allowed public HTTPS destination without credentials or a fragment. Do not mutate a create body already associated with an existing document and idempotency key. | The callback was rejected; this does not diagnose the source file. Callback configuration cannot be repaired by re-uploading bytes. |
Invalid API key or forbidden operation
| No automatic retry. Code-specific guidance
| Fix the credential or account authorization. Do not send invoice bytes. | The rejected request creates no usable resource; an earlier known document may still exist. |
Billing required or Trial allowance exhausted
| Recover entitlement first. Create retries use the exact body/key; upload-complete retries the same document. Code-specific guidance
| Never re-PUT after upload-complete billing recovery. A terminal async rejection cannot be resumed; any new submission is a deliberate new document with a new stable key. | Pre-provider rejection is non-billable. Preserve the document ID; Trial never partially processes a document to fit its allowance. |
Source exceeds the size limit
| Provide a supported source no larger than 20 MiB; do not retry unchanged oversized bytes. Code-specific guidance
| Declare the exact byte count. If an oversized object is already stored at an immutable upload path, use a new document for the corrected source; never overwrite it. | A size rejection is not a page-limit or remaining-Trial-allowance decision. |
Unsupported or mismatched content type
| Use PDF, JPEG, or PNG with the matching MIME type. Code-specific guidance
| At create, correct the rejected declaration. At upload-complete, a wrong-MIME object already at the immutable path requires a new document, not an overwrite or a changed declaration. | Changing a filename or MIME label does not convert unsupported bytes into a supported document. |
Invalid, unsupported, corrupt, or immutable wrong-metadata input
| Do not retry unchanged invalid bytes. Correct the source or immutable metadata mismatch first. Code-specific guidance
| Wrong size or MIME at the immutable upload path needs a new document. Corrupt or unsupported content cannot be repaired by retry. A terminal failed document remains failed. | No usable result; documented pre-provider rejection is non-billable. New corrected bytes need their own logical submission and stable key. |
Upload capability expired
| Reject the stale signed capability. An API upload_expired response must not be retried as if its reservation can be refreshed. Code-specific guidance
| If only the signed URL expired while the reservation is still valid, replay create with the exact body/key. Only an authoritative expiry permits a deliberate new logical submission; never rotate keys just because a request timed out. | The old capability is unusable; no replacement resource is implied. A 200 awaiting_upload create replay must probe upload-complete before any PUT. |
Upload reported not complete
| A complete PUT may be retried only while the signed capability is valid. Code-specific guidance
| The authoritative response says bytes are absent. Send only returned upload headers; never API credentials. | Reuse the same document and upload path; no second create. |
Idempotency conflict
| Do not retry a changed body behind the same key. Code-specific guidance
| Restore the original create body, or use a new key only for a genuinely new logical invoice submission. | The original identity may already own a resource; conflict itself is not billable. |
Operation does not fit the document state
| Retrieve the same document and choose the operation allowed by its current status. Code-specific guidance
| Preserve the document ID. Do not infer that the source is absent, re-PUT, or create a replacement from this code alone. | Processing or a terminal result may already exist. A failed document does not restart when polled. |
Rate limit or temporary service unavailability
| Retry the same operation finitely when retryable; treat Retry-After as a minimum delay. Code-specific guidance
| Keep the same create body/key or confirmation document. Never turn a confirmation retry into a PUT. | A resource may already exist; preserve recovery context. A 5xx alone does not authorize retry when retryable is false. |
Internal request failure
| No automatic retry when retryable is false. Do not infer retry permission from HTTP 500; contact support with the request ID if needed. Code-specific guidance
| Preserve the document ID and exact create body/key. A failed response does not prove that no work occurred; never replace the document or re-PUT without the documented recovery step. | An earlier resource or processing run may still exist. Follow documented same-resource recovery only when retryable permits it. |
| Ambiguous create transport outcome | Retry the exact create body and idempotency key. | Never rotate the key merely because the response was lost or timed out. | The logical document may already exist. |
| Ambiguous signed PUT outcome | Probe upload-complete before any second PUT. | Re-PUT only after authoritative upload-not-complete and only with a still-valid capability. | Reuse the same document; uploaded bytes may already be present. |
| Ambiguous upload-complete outcome | Retry or probe only the same document confirmation. | Do not re-PUT and do not create a replacement document. | Processing may already be queued or terminal. |
| SDK cancellation or polling timeout | The SDK stops waiting; server-side work is not cancelled by assumption. | Use safe document/idempotency recovery context to resume authenticated GET or the documented operation. | The known server document may still finish and be billable normally. |
Expired result or authoritative not found
| Do not reinterpret either response as a successful DELETE or completed result. Code-specific guidance
| Check the document ID and account. Persist results before result_expires_at; expired content cannot be recovered by retry. A real 404 remains authoritative. | No accessible retained document result was returned; no new resource is implied. |
Requested usage period is unavailable
| Choose an existing retained closed period, or omit periods_ago for current usage. Code-specific guidance
| Keep the account context. This is a usage-query error; do not resubmit or delete an invoice. | The requested historical period does not exist for this account. It does not mean a document was deleted or usage was zero. |
Terminal processing failure or timeout
| The document is already terminal failed; polling does not restart it. Follow retryable and documented recovery, and contact support with safe identifiers if needed. Code-specific guidance
| Do not automatically rotate the key or re-PUT. If a new attempt is appropriate, submit it deliberately as a new logical document with a new stable key. | No usable result; genuine processing failures are non-billable. A processing_timeout is different from a local SDK polling timeout. |
Page, complexity, or result-size limit
| Do not blindly repeat the same source. Check the applicable limit and use a supported representation of one complete invoice, or seek help. Code-specific guidance
| The failed document is terminal. Do not split one invoice into fragments or omit invoice content to fit a limit. Any suitable replacement is a deliberate new submission. | No usable result; product limit failures are non-billable. Paid overage or a larger plan does not remove document limits. |
Unknown future diagnostic codes
Keep the unknown non-empty code for display and diagnostics. For a synchronous API error, fall back to HTTP status, retryable, and generic documented recovery. For validation checks, fall back to check status/severity, paths, and validation.review_required. An unknown async error still leaves the document terminal failed.
Thrown error versus terminal failed
A terminal failed document is returned normally by wait and process. SDK-local cancellation, timeout, invalid response, or a synchronous API error is thrown. A polling timeout leaves server-side work running; callers can resume GET with the known document ID.
Callbacks are untrusted wakeup hints
- Receive
document.finished. - Parse its event and document IDs only as hints.
- Fetch the document with an authenticated GET.
- Require fetched
callback.event_idto equal the received event ID, then act on the fetched document.
MVP callbacks are unsigned and have no persistent webhook endpoint management. A receiver should fetch promptly and persist only the downstream representation it needs.
Avoid secrets or personal data in callback URLs: Vercel may retain destinations in platform logs. Resume URLs can themselves be secret; use polling if that retention is unsuitable. See the retention limits.
Result retention and deletion
Temlavo is not a long-term invoice archive. Terminal structured results are retained 7 days by default; processing.result_expires_at is authoritative. After expiry, 410 document_expired is an expected lifecycle outcome. Explicit DELETE ends document API access and clears stored results and document fields. Storage deletion is attempted immediately and retried if needed. The separate account-lifetime discovery index of raw accounting-entity IDs remains, as do required financial/security records. Document DELETE does not close an account or delete Vercel platform logs. 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
Preserve the safe X-Request-Id, document ID, and idempotency key when asking for help. Never send the API key, signed upload capability, source invoice, full result, or provider details in an initial support report.
Contact support with the safe identifiers above and a short description of the issue.