Skip to content
Guides

Guides

UniAI has one endpoint. Everything below is the same request with a different type in the path or a different flag in the form.

curl -X POST https://cloud.unidoc.io/api/uniai/extract/{type} \
  -H "X-API-KEY: $UNIDOC_LICENSE_API_KEY" \
  -F "[email protected]"

New to UniAI? Getting started covers creating a key and making the first call.

The request

PartWhereNotes
API keyX-API-KEY headerRequired. Not an Authorization header.
{type}Pathinvoice or resume.
fileForm fieldRequired. A PDF, three pages or fewer.
is_scannedForm fieldtrue renders the pages as images as well.
debug_promptForm fieldtrue prefixes the response with the prompt, which makes the body non-JSON. Debugging only.

The body is multipart/form-data. Anything other than invoice or resume in the path is rejected before the file is read.

The response

A success is HTTP 200 with a JSON object in the body, assuming the default request. Two things about it will catch out a client written against the obvious assumptions.

The Content-Type is text/plain; charset=utf-8, not application/json, even though the body is JSON. Parse the body and ignore the header.

The body is streamed as the model produces it, and the 200 is sent before generation starts. A failure partway through cannot change the status code, so a truncated body is possible on a response that looked successful. Decoding the JSON is what tells you the response is complete; a decode error on a 200 means you got a partial answer.

Retrying that is reasonable, and it is billable. Credits are committed before generation, so the truncated attempt was charged and each retry charges the pages again. Cap the attempts.

debug_prompt=true breaks this contract on purpose: it writes the prompt text ahead of the model output, so the body is no longer a standalone JSON object and the decode test above will always fail. Use it while debugging by eye, never in a client that parses the response.

Errors are a JSON envelope instead:

{"success":false,"message":"file is required","errors":null}

Where to look

GuideCovers
Extract an InvoiceThe invoice schema field by field, and what sparse output looks like.
Extract a ResumeThe resume schema, and why the arrays are the useful part.
Scanned DocumentsTelling a scan from a text PDF, and the is_scanned flag.

Fields are best-effort

This applies to both types, so it goes here once rather than on both pages. The response contains what the model found and nothing else. Keys are omitted rather than set to null, and that includes fields the schema marks required. Any client that indexes straight into the response will panic on a document that happened to be missing a total.

Check before reading, and treat a missing field as “not found in this document” rather than as an error. Why is a field missing? goes into what tends to cause it.

Last updated on