Fill from context docs

Hand Emboss a form plus one or more supporting documents, prior filings, a profile sheet, anything that holds the values, and it reads your documents and fills what it can match.

The default is filling a form you've already created: you ran detection once, and now you want to fill that same form from context. There's also a convenience path that takes a brand-new flat PDF and extracts and fills it in a single call.

Already have the values as structured data? Use direct fill instead (Fill from your data): it's deterministic and skips the inference step.

Fill an existing form

If you've already created a form (see the Quickstart or POST /forms) and it's ready, fill it from context with POST /forms/{form_id}/with-context. The form is identified by {form_id} in the URL, so the request body carries only context file parts: no file.

curl -X POST https://api.getemboss.ai/forms/6c47f7f5-f921-4698-910f-95dd7d81310b/with-context \
  -H "Authorization: Bearer sk_..." \
  -F "context=@./w9-prior-year.pdf" \
  -F "context=@./company-profile.txt"
{ "job_id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d", "status": "processing" }

This bills a single context fill at 3¢, which is flat to 5 pages, then 2¢ per page, counting the form and its context documents together, with the first 5 each month free. That price includes verifying the rendered document, effective 09-06-2026. The form must be ready and owned by your key: an unready form returns 409, and one you don't own returns 404. Then poll the job below.

Choosing how sure Emboss must be

Both endpoints take an optional policy field alongside context, with two values: safe and strict. safe is the default: Emboss writes any value it reported as high or medium confidence. strict writes only high-confidence values and leaves medium-confidence ones for you to confirm. Either way you get back a response of the same shape: a filled PDF and a report, just with a different line drawn between what's written and what's flagged.

curl -X POST https://api.getemboss.ai/forms/6c47f7f5-f921-4698-910f-95dd7d81310b/with-context \
  -H "Authorization: Bearer sk_..." \
  -F "context=@./w9-prior-year.pdf" \
  -F "context=@./company-profile.txt" \
  -F "policy=strict"

When documents disagree

When two documents give a box different answers, an AI check reads both quotes and the boxes around it. If it is at least 85% sure which reading belongs, the fill writes that one at medium confidence: under safe it goes into the PDF, under strict it waits for you to confirm. If the two readings are the same fact written two ways, it keeps one. The receipt marks such a value with origin tiebreak and a note naming the reading chosen and the one passed over. When the check is not sure, the box is left blank and reported as a conflict. To decide every disagreement yourself, use prepare and commit: there the check only merges readings that are the same fact and puts the others in order, and every real conflict waits for your answer.

Start from a brand-new PDF

If you don't have a form yet, POST /forms/with-context takes the flat PDF and the context in one shot: Emboss detects the form's fields and fills them. The request is multipart/form-data: the file (the flat PDF) plus one or more context file parts.

curl -X POST https://api.getemboss.ai/forms/with-context \
  -H "Authorization: Bearer sk_..." \
  -F "file=@./vendor-onboarding.pdf" \
  -F "context=@./w9-prior-year.pdf" \
  -F "context=@./company-profile.txt"
{ "job_id": "6c47f7f5-f921-4698-910f-95dd7d81310b", "status": "processing" }

Because this both extracts and fills, it bills an extraction plus a context fill. A non-PDF form returns 400.

Either way, limits per request are: up to 5 context files, 10 MB per file, 30 MB total, and 100 pages on the form. Past these you'll get a 413. Going over the free tier with no card on file returns 402. For a fill from documents the free tier's page limit counts the form and its documents together.

Poll for the result

Both endpoints return a job_id you poll the same way:

curl https://api.getemboss.ai/forms/with-context/6c47f7f5-f921-4698-910f-95dd7d81310b \
  -H "Authorization: Bearer sk_..."

While running, status is processing. When it's ready you get a session_id; on failure it's failed with an error message.

{
  "job_id": "6c47f7f5-f921-4698-910f-95dd7d81310b",
  "form_id": "0b5a9e7c-3d2f-4e1a-9c8b-7d6e5f4a3b2c",
  "status": "ready",
  "session_id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
  "proposal_id": "3e714663-ff2c-45ac-ae11-3c7015facfef",
  "result": "complete",
  "receipt_url": "https://api.getemboss.ai/proposals/3e714663-ff2c-45ac-ae11-3c7015facfef/receipt",
  "pdf_url": "https://api.getemboss.ai/proposals/3e714663-ff2c-45ac-ae11-3c7015facfef/pdf",
  "report": {
    "filled": [
      { "id": 3, "confidence": "high" },
      { "id": 7, "confidence": "high" },
      { "id": 14, "confidence": "med" }
    ],
    "dropped": [],
    "verification": {
      "result": "complete",
      "checked_at": "2026-09-06T18:33:02.114921+00:00",
      "issues": [],
      "adjustments": [],
      "counts": { "fields": 24, "written": 24, "required_unfilled": 0, "issues_blocking": 0, "issues_review": 0 }
    }
  },
  "error": null
}

A finished fill carries form_id, the form it filled, and four fields beyond the session_id. result is the verification result, one of complete, review_required or incomplete; a job that breaks ends with status failed instead. receipt_url and pdf_url point at the receipt and the filled document. report holds filled, one entry per field that was written, each with the field's integer id and the confidence it was written at (high, med or low), and dropped, alongside verification, the full verification report: its own result, checked_at, issues, adjustments and counts. Nothing was removed from the response, so a caller reading only session_id keeps working.

When nothing was found

A fill can finish ready without writing anything, when the documents don't hold the form's answers or can't be read (a blurry or sideways photo, say). The report then carries no_values_found in warnings, and a message you can show the person as it is:

{
  "job_id": "6c47f7f5-f921-4698-910f-95dd7d81310b",
  "status": "ready",
  "result": "incomplete",
  "report": {
    "filled": [],
    "dropped": [],
    "warnings": ["no_values_found"],
    "message": "<why nothing was filled, to show the person as it is>"
  }
}

Check warnings, not result: on a form with no required fields, a fill that wrote nothing can still verify as complete.

On an account, the fill isn't counted against your plan (making the form fillable still is), and the message says so when that applies. The form stays made, so you can fill it again from a different document with POST /forms/{form_id}/with-context (the job's form_id is the one to use), which bills only the fill.

The same file as the form

A supporting document that is byte-for-byte the form you're filling, with nothing typed, ticked or chosen in it, holds nothing to copy. Emboss refuses the request with 422 and code document_same_as_form before anything is charged:

{
  "detail": {
    "code": "document_same_as_form",
    "message": "The document you added is the same blank form you're filling, so there's nothing to copy from it. Add the document that holds your answers, such as a statement, an ID, or a filled copy from before.",
    "document_index": 0
  }
}

document_index is the refused file's position among the context files, counting from 0. A filled copy of the same form goes through.

A PDF that could compromise the service

A PDF whose form fields are built in a way that could compromise the service is refused with 422 and code pdf_unsafe before any price, quote, charge or stored file:

{
  "detail": {
    "code": "pdf_unsafe",
    "message": "Emboss does not process PDF files that could compromise the service."
  }
}

Replace the form with a different PDF; nothing was charged.

Emboss verifies every context fill against the form's contract as part of the fill, with no extra call: that check is arithmetic and geometry. Separately, a second AI model looks over each written value against its box's label and the boxes around it, and any doubt it raises lands in the receipt's checks block. If you would rather see the proposed answers before anything is written, split this into two calls: see Prepare, commit and verify.

The resulting session is already completed and its PDF is already rendered: use it to download the PDF, not to edit or render it again. (PUT /sessions/{sid}/fields on a completed session returns 409, and so does POST /sessions/{sid}/fill.)

Download the filled PDF

curl https://api.getemboss.ai/sessions/a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d/pdf \
  -H "Authorization: Bearer sk_..." \
  -o filled.pdf

Want to see what Emboss detected before or after the fill? Read the contract shape.

Retention

Every create and with-context call takes an optional retention body field: ephemeral or account_default. Leave it out and the account's own default applies. It applies only when the call creates a form: on POST /forms/{id}/with-context the form already exists and keeps the setting it was created with, so the field changes nothing there. See Ephemeral processing for the window and what a 410 means once a form is swept.

Once a fill is complete, the submission package hands the filled form and its supporting attachments over as one file.