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 curl and jq installed — the polling loop below uses jq.
  • 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-contextthis 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 polling
  • ready — done; the response includes a session_id
  • failed — the response includes an error describing 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

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.