Documents API

Form scanning

A photograph of a completed paper form, transcribed into fields.

Contents
POST/forms/scanmultipart
GET/forms/scan/last
GET/forms/field-form/{form_type}

This endpoint takes a file, so it is multipart/form-data, not JSON. Do not set Content-Type yourself; the boundary has to come from the encoder.

curl
curl -X POST "$BASE/forms/scan" \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@breaker-52-1.jpg" \
  --max-time 120
client.ts
const body = new FormData()
body.append('file', file)

const res = await fetch(`${BASE}/forms/scan`, {
  method:  'POST',
  // Authorization only. Setting Content-Type here would omit the
  // multipart boundary and the request would fail to parse.
  headers: { 'Authorization': `Bearer ${token}` },
  body,
  signal:  AbortSignal.timeout(120_000),
})
client.py
with open("breaker-52-1.jpg", "rb") as fh:
    # files= sets the multipart Content-Type for you.
    scan = s.post(f"{BASE}/forms/scan",
                  files={"file": fh},
                  timeout=120).json()

The transcription is returned as fields keyed to the recognised form. GET /forms/field-form/{form_type} returns the blank field contract for a form type (its identifier, version and section structure) which is what you map a scan onto, and what you would render your own capture UI from.

Scanning does not write to the database

A scan returns extracted fields and nothing more. Persisting them is a separate POST /db/equipment/{eid}/records with the values in form_data, which keeps the review step in your control rather than in ours.