2257 packet API

Processing version 9 · result field reference · machine-readable spec: /openapi.json · interactive reference: /docs

POST the files of one movie's 2257 records packet. The API combines them into one PDF (the page numbers in every answer refer to it), has a local vision model extract every performer, cuts and checks each ID copy, and serves the result and the PDF back. Extraction takes minutes, so the API is asynchronous: you POST, then poll.

This service is not a data store. A finished job, its result and its PDF are deleted 3 hours after it finishes. Fetch and keep what you need; the combined PDF you download is the canonical copy.

Quick start

# 1. submit the packet: files in page order, plus any metadata you like
curl -s -F "files=@release.pdf" -F "files=@ID front.heic" -F "files=@cast list.xlsx" \
     -F "title=Example Movie 5" -F "scene=1" -F "scene=3" \
     http://127.0.0.1:8257/extractions
# -> 202 {"id": "9f2c…", "status": "queued", ...}   Location: /extractions/9f2c…

# 2. poll every Retry-After seconds until status is done
curl -s http://127.0.0.1:8257/extractions/9f2c…

# 3. fetch the combined PDF
curl -s -o packet.pdf http://127.0.0.1:8257/extractions/9f2c…/pdf

When the server runs with a token, send Authorization: Bearer <token> on every call. This page, /docs, /redoc, /openapi.json and /healthz are readable without it.

Endpoints

EndpointDoes
POST /extractionsSubmit a packet. 202 with the job id and a Location header.
GET /extractions/{id}Job status while queued or running; the full result when done; the error when failed. Field reference.
GET /extractions/{id}/pdfThe combined PDF (application/pdf).
GET /healthzLiveness, the current processing version and the queue depth.
GET /This page.

Job lifecycle and polling

queued → running → done or failed. One job runs at a time (one GPU); the rest wait in arrival order. A typical packet takes 3 to 10 minutes once it starts.

StateGET /extractions/{id} returns
queued200 {"id", "status", "version", "created", "queue_position"} and Retry-After: 30. queue_position counts from 1 and excludes the running job: 1 means "next after the one running now".
running200 {"id", "status", "version", "created", "started"} and Retry-After: 30.
done200 with the result and an Expires-At header.
failed500 Extraction Failed (problem+json) with the reason in detail.

Poll at the Retry-After interval. Timestamps are ISO 8601 UTC: created, started once running, finished and expires_at once done or failed. Derive queue time and run time from them.

The request

POST /extractions with multipart/form-data.

Files: parts named files

Metadata: every other field

The result

A done job returns one JSON document. Keep it: it is self-contained (the ID crop images are inside it) except for the PDF. Every field of it, with a complete example, is explained here.

FieldMeaning
status, version"done", and the processing version that produced it.
created, started, finished, expires_atTimestamps; expires_at repeats the Expires-At header.
packet_sha256SHA-256 of the combined PDF.
pagesPage count of the combined PDF.
page_mapOne entry per uploaded file: {"file", "pages"}, plus duplicate_of for a file identical to an earlier one, render_notes when a file's content isn't the type its name says or an office file could not be rendered as intended, and excluded (with "pages": []) when the file was left out because it couldn't be read.
metadataYour metadata, as sent.
answerWhat the model found: the page inventory, performers, unassigned items (see below).
id_cropsEvery ID copy cut from the PDF: {"performer", "copy", "page", "status", "note", "jpeg_base64"}. performer and copy count from 1 in answer order; page is where the crop was verified to be.
pdfPath of the combined PDF: /extractions/{id}/pdf.

answer

Dates

Every date is reported twice: as printed (for example date_of_birth) and parsed (date_of_birth_parsed, ISO YYYY-MM-DD, or null when it can't be read). Numeric dates are read month-first, U.S. style (11/02/1986 is November 2, 05/04/19 is May 4), unless that is impossible (21/11/1986 has no month 21, so it is November 21); two-digit years pivot at 50 (69 is 1969, 30 is 2030), a birth date is never in the future, a production date listing several shoot days gives the earliest, and a date printed without a day rounds the cautious way: a birth date to the last day of its month, an expiration or production date to the first. Examples.

id_crops status

verifiedChecked on its own: an ID, showing the copy's recorded date of birth.
repairedThe first crop wasn't; a neighbouring page or a photo file was, and the crop was taken from there.
failedNo crop could be vouched for; note says what the check saw. Advisory: the extraction stands.

Identity and caching

Errors

Every error is RFC 9457 application/problem+json: {"type", "title", "status", "detail", "instance"}, plus extension members where noted.

StatusTitleWhen / what to do
401UnauthorizedMissing or wrong bearer token.
404Not FoundUnknown id, or the job expired. Re-submit if you still need it.
413Content Too LargeOver the size or file-count limit.
422Unsupported FileNone of the files is usable (each is no accepted type or can't be read), or there are no files; detail gives each file's reason. A packet with at least one usable file is accepted, with the others marked excluded in page_map.
422Invalid MetadataA file under a part name other than files, too many keys, or an oversized key or value.
422Validation ErrorThe request isn't usable, for example no files at all.
500Extraction FailedThe job failed; detail says why, with id and the timestamps. Re-submit the same inputs to retry.
500Internal Server ErrorA bug on our side: the API was about to send a response its own schema doesn't describe, and sent this instead. Report it with the time and the request.
503Service UnavailableThe queue is full; retry after Retry-After seconds.
What counts as a failure: only a system or code failure, such as the model being unreachable, a crash, a timeout, an unreadable model reply, or a packet too large for the model's context (pages would have been dropped). Pages go to the model at 150 dpi; a packet that doesn't fit at 150 is sent once more at 120 dpi (about 120 scanned pages fit at 150, about 180 at 120), and only if it still doesn't fit does the job fail. ID crops are always cut at 300 dpi. What the documents contain is never a failure: a packet in which the model finds no performers is a successful, empty result.

Processing version

version is one integer for the whole of the processing: assembly, model, prompt, crop checks, date parsing and response shape. It is raised whenever any of that changes what you get back. Each job reports the version that processed it; /healthz reports the current one. The current version is 9.

Limits

Request size500 MB
Files per request200
Jobs waiting32 (then 503)
Metadata50 keys, 100-character keys, 2000-character values
Retention3 hours after a job finishes
Polling intervalRetry-After: 30 seconds