API reference
One REST lifecycle, five operations.
The Temlavo HTTP API is small on purpose: create document, confirm upload, retrieve document, delete document, and retrieve usage. The file itself goes straight to storage. This page covers the rules every operation shares. Operation details live in the generated reference, which is rendered from the same executable contracts as the OpenAPI artifact.
On this page
Base URL
The API uses an unversioned root with versioned route paths. HTTPS is enforced; clients must not rely on redirects to another hostname.
https://api.temlavo.comAuthentication
Every request carries a bearer key. Keys are server-side credentials: never embed them in browser or mobile code.
Authorization: Bearer inv_live_...Every response includes X-Request-Id: req_01…; errors repeat it as error.request_id so support can find the exact request without parsing message text.
Idempotency
Send an Idempotency-Key header on create, one per invoice, and send the same request body on every retry. A request that timed out may still have created the document, so a retry with the same key and body returns that document instead of creating a second one. Changing the normalized request under the same key returns idempotency_conflict. Normalized means formatting does not count: reordering fields or spelling out a default value is not a change.
A replay can return a fresh signed upload URL while the document is still waiting for its file. If a replay returns 200 awaiting_upload, call /upload-complete before uploading again: the file may already have arrived.
Direct upload
Invoice files never pass through the API itself. The create response includes a signed upload URL with a method and headers: send the file using exactly that method, URL and headers, and add nothing else. Never send your API key to the upload URL, and do not follow redirects automatically.
Uploading alone does not start processing. Call POST …/upload-complete to check the uploaded file and queue the document. Supported files are PDF, JPEG, and PNG up to 20 MiB and 20 pages, with the correct declared size and content type.
Rate limits and polling
Throttled requests return 429 with a Retry-After header. Treat Retry-After as a minimum delay everywhere - it is also the polling hint on queued or processing documents. Retry other errors only when retryable is true, with the same idempotency semantics; an HTTP 5xx status alone is not a reason to retry. A request that timed out or got no response follows the recovery steps instead.
Statuses
statusstring
Where the document is in processing.
awaiting_upload- Waiting for the file. Processing has not been admitted yet.
queued- The file passed admission; processing is waiting to begin.
processing- Processing is underway.
completed- A usable result with no blocking check. Warnings may remain.
needs_review- A usable result with at least one blocking check.
failed- No usable result was produced. This status is final.
completed and needs_review documents include processing.result_expires_at: When the retained result expires. After that, fetching the document returns 410 document_expired.
Errors
Every synchronous error uses one typed envelope:
errorobject
The error.
7 child fields
typestring
The error's broad category.
codestring
A stable code to branch on, with the HTTP status. See the error catalogue.
messagestring
An explanation for people. Never branch on it.
request_idstring
The request's ID, also sent as X-Request-Id. Give it to support.
retryableboolean
Whether the same request may succeed later. Retry only when it is true, with backoff, waiting at least as long as Retry-After when the response sends it.
docs_urlURLOptional
The code's entry in the error reference. Show it to developers; never branch on it.
detailsJSON valueOptional
Machine-readable details, when the code has them. For rejected inputs, details.issues lists each rejected field.
{
"error": {
"type": "resource_gone",
"code": "document_expired",
"message": "The document result is no longer available.",
"request_id": "req_c81e728d",
"retryable": false,
"docs_url": "https://temlavo.com/docs/errors-recovery#error-document_expired"
}
}Preserve unknown future codes and handle them through the stable fields above.
The full error catalogue and recovery playbook