Quickstart
Emboss turns a flat PDF into a filled one. You upload a form, Emboss detects the fields, fills them, and gives you back a filled PDF — in a few HTTP calls. After detection, Emboss also produces a structured contract of the fields it found, so you can inspect exactly what it detected before you rely on the output. It's not a black box.
Before you start
- Create an API key in the dashboard (see Authentication).
- Have
curlandjqinstalled — the polling loop below usesjq. - Save a form to fill as
./w9.pdf, and a supporting document as./vendor-profile.pdf.
The free tier covers 5 form creations, 5 context fills, and 5 standard fills each month — see pricing.
Authentication
Every request is authenticated with a Bearer key. Keep your key out of client-side code and source control — set it as an environment variable:
export EMBOSS_API_KEY="sk_live_..."
Then pass it on every call: -H "Authorization: Bearer $EMBOSS_API_KEY".
Pick your endpoint
| Your goal | Endpoint |
|---|---|
| Detect fields only (no fill) | POST /forms |
| Fill a brand-new flat PDF from context | POST /forms/with-context — this quickstart |
| Fill a form you've already created from context | POST /forms/{form_id}/with-context |
| Fill from your own structured data | Fill from your data |
This quickstart walks the second path: upload a flat PDF plus supporting documents and get a filled PDF back.
1. Upload the form
Send the form PDF to POST /forms/with-context. Add one or more context files —
supporting documents Emboss reads to infer field values. This starts an
asynchronous detection-and-fill job and returns 202 Accepted with a job_id.
curl -X POST https://api.getemboss.ai/forms/with-context \
-H "Authorization: Bearer $EMBOSS_API_KEY" \
-F "file=@./w9.pdf" \
-F "context=@./vendor-profile.pdf"
Expected: 202 Accepted.
{ "job_id": "6c47f7f5-f921-4698-910f-95dd7d81310b", "status": "processing" }
Limits: the form file must be a PDF, ≤ 10 MB and ≤ 100 pages. You may attach
up to 5 context files (PDF, DOCX, XLSX, image, or text), with ≤ 30 MB total
upload size. Past these you'll get a 413.
(Just want detection, no fill? POST /forms with only the file — see the
API reference.)
2. Poll the job
The job runs asynchronously. Poll GET /forms/with-context/{job_id} until
status is ready or failed. Each poll is 200 OK:
processing— keep pollingready— done; the response includes asession_idfailed— the response includes anerrordescribing why
Poll every couple of seconds, and back off if you get a 429:
JOB_ID="6c47f7f5-f921-4698-910f-95dd7d81310b"
while true; do
RESPONSE=$(curl -s "https://api.getemboss.ai/forms/with-context/$JOB_ID" \
-H "Authorization: Bearer $EMBOSS_API_KEY")
STATUS=$(echo "$RESPONSE" | jq -r .status)
if [ "$STATUS" = "ready" ]; then
SESSION_ID=$(echo "$RESPONSE" | jq -r .session_id)
echo "ready: $SESSION_ID"
break
fi
if [ "$STATUS" = "failed" ]; then
echo "$RESPONSE" | jq .
exit 1
fi
sleep 2
done
A ready job looks like:
{ "job_id": "6c47f7f5-f921-4698-910f-95dd7d81310b", "status": "ready", "session_id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d" }
A failed job returns a structured error with a stable code and a human-readable message:
{ "job_id": "6c47f7f5-f921-4698-910f-95dd7d81310b", "status": "failed", "error": { "code": "context_too_large", "message": "context too large: 5000 > 4000 tokens" } }
Branch on error.code for programmatic handling. The codes are context_too_large, unsupported_context_file, context_fill_failed, apply_rejected, form_processing_failed, and job_failed (fallback); error.message carries the detail.
3. Download the filled PDF
Fetch the rendered document from GET /sessions/{sid}/pdf. The response body is
raw PDF bytes, so write it straight to a file with -o:
curl https://api.getemboss.ai/sessions/$SESSION_ID/pdf \
-H "Authorization: Bearer $EMBOSS_API_KEY" \
-o filled.pdf
Verify you got a real PDF:
ls -lh filled.pdf
file filled.pdf # filled.pdf: PDF document, ...
That's the full path: upload → poll → download.
Next steps
- Inspect the detected-fields contract.
- Read more about filling from context documents.
- Prefer JavaScript or Python? Every endpoint in the API reference includes cURL, JavaScript, and Python samples.
Safe retries: pass an Idempotency-Key header — any unique string, like a
UUID — on a create request. If a call times out and you retry with the same key,
Emboss returns the original job instead of starting a new one, so you're never
charged twice for the same submission. Keys are scoped to your account and last
24 hours.