# Use Emboss from agent frameworks (A2A)

Emboss also speaks A2A (Agent2Agent), a protocol for one agent to discover
and delegate tasks to another. A2A is complementary to
[MCP](/glossary/model-context-protocol): MCP connects Emboss to a chat
client or IDE, and A2A lets an agent orchestrator, such as Google's ADK,
LangGraph, or an enterprise agent stack, discover Emboss by semantic search
and delegate a form-filling task to it directly. See the [MCP tools
reference](/docs/mcp-tools) for the MCP connection.

## Connect

Emboss publishes a signed agent card at
`https://api.getemboss.ai/.well-known/agent-card.json`. A compliant A2A
client reads the card to learn the server's URL, its skills, and how to
authenticate, then sends it tasks at `https://api.getemboss.ai/a2a`.

Here's a Python client using the `a2a-sdk`
that resolves the card from Emboss's base URL and completes a `fill_form`
task. The SDK's message types are protobuf, so structured arguments go
through `json_format.ParseDict`:

```python
import asyncio, uuid, httpx
from google.protobuf import json_format
from a2a.client import create_client, ClientConfig
from a2a.types import Message, Part, Role, SendMessageRequest

API_KEY = "sk_..."

async def main():
    async with httpx.AsyncClient(
        headers={"Authorization": f"Bearer {API_KEY}"}
    ) as http:
        client = await create_client(
            "https://api.getemboss.ai",
            client_config=ClientConfig(httpx_client=http),
        )

        message = Message(message_id=str(uuid.uuid4()), role=Role.ROLE_USER)
        message.parts.append(Part(data=json_format.ParseDict(
            {"form_id": "your-form-id", "values": {"Full name": "Jordan Lee"}},
            Part().data,
        )))
        json_format.ParseDict({"skillId": "fill_form"}, message.metadata)

        request = SendMessageRequest(message=message)
        async for update in client.send_message(request):
            print(update)

asyncio.run(main())
```

## Auth

Emboss's card declares two security schemes: an HTTP Bearer scheme using an
Emboss API key (see [Authentication](/docs/authentication)), and OAuth 2.1
for clients that support it. Either way, the connection is scoped to the same
owner as the rest of the Emboss API: a task can only read and write the forms
that key or token already has access to. Callers with no Emboss account can
pay per job instead; see [Pay per job with x402](/docs/pay-per-call/x402).
A request whose `Authorization: Bearer` token matches no account (a mistyped,
revoked or turned-off key, or an expired sign-in) is refused with `401`; it
never falls back to paying per job. Leave the header out to pay per job.
`send_fax` is also available that way: an anonymous caller pays per
transmitted page and the task stays `working` until delivery.

Free skills need no payment, only tokens: an anonymous caller sends the `artifact_token` for each source instead of paying.

The key that signs the agent card also signs every entry in Emboss's discovery catalogue, and the same public key is published as a DID document. [Trust and verification](/docs/reference/trust) describes the framework and how to check a signature yourself.

## Plain-language requests

Signed-in callers (an API key or an OAuth sign-in) can describe the job in words instead of
naming a skill: leave `metadata.skillId` out and send a text part, with any files as file parts.
Emboss works out which skill you mean and runs it with the same billing and permissions as
naming it yourself.

- When the request is unclear, could mean two different paid jobs, or is missing something, the
  task pauses in `input-required` with a question. Answer it with a message on the same task.
  Emboss asks at most three questions, and a request that gets no answer for 24 hours ends as
  failed.
- While a question waits, Emboss keeps the request's words and any attached files for up to 24
  hours, then deletes them. They are deleted as soon as the task ends, and a waiting task can be
  canceled.
- Before sending a fax, Emboss names the document and the full number it will fax to, and waits
  for a yes.
- A request that is not about PDF forms is declined with a list of what Emboss can do.
- Every plain-language task ends with one readable sentence alongside the usual result. When the
  job is a page tool (compose, merge, extract, delete, reorder or rotate pages), the sentence
  carries a download link anyone holding it can open, with no API key, for about an hour, as
  long as Emboss keeps that file.
- Each message Emboss reads, a request or your answer to its question, counts once toward the
  same per-account rate limit as a request that names a paid skill (see
  [Rate limit](/docs/authentication#rate-limit)). The job it runs does not count again, and a yes
  to a fax is not counted.

A caller can also ask whether a fax went through, for example "did my fax go through?". Emboss
answers from the most recent fax sent in that conversation, or else the caller's most recent fax
from the last 7 days, sent from any of Emboss's surfaces, with the masked number and whether it
was delivered, is still sending, or did not go through. Checking is free.

Requests that name a skill work exactly as before. Callers without an account, who pay per job
with x402, still name a skill.

To add Emboss to Gemini Enterprise, see [Use Emboss in Gemini Enterprise](/docs/gemini-enterprise).

### Several jobs in one request

A plain-language request can ask for up to five jobs in a row, such as "fill the W-9 from these
notes and fax it to 555 201 0142." Emboss answers with the jobs it will run, one numbered line
each, and an estimated total, and waits in `input-required`. Reply yes to start; any other reply
plans again. Nothing runs before you reply yes, even when every job is free. A request that reads
as several jobs but can only plan as one is confirmed the same way, so you see what is not
included before anything runs.

- The estimated total uses the same prices as your bill and counts your free jobs first. It says
  "about" when a price depends on a document Emboss has not read yet.
- Billing does not change: each job is billed as it runs, exactly as if you had asked for it on
  its own. If a job fails, the run stops there: the jobs before it stay done and billed, and the
  jobs after it do not run.
- The task shows which job is running. A reading or checking job, such as a read back, a check of
  a filled form, or a look at a form's fields, sends its result as the run goes, not only at the
  end; a check's summary names the missing or problem fields. The task ends with one sentence per
  job and the download links. When the last job is a fax, the task completes when the fax is
  delivered.
- At most five jobs, run in the order you asked for them. A fax can only be the last job, and
  replying yes to the plan is also your yes to send that fax; no second fax question follows. A
  job Emboss cannot run as asked, such as a review in the middle of a chain, faxing every copy of
  a batch, or a fax before another job, is explained or asked about, never skipped or changed.
- A plan is refused up front when it could not finish: a connection without write access for a job
  that writes, or an account without a card for a fax or past its free allowance.
- Like any plain-language message, the request counts once toward the rate limit; your yes and
  the jobs it runs do not count again.
- The request's words and any attached files are kept until the last job has run, then deleted;
  up to 24 hours while a question or the plan waits for your answer.
- A later job can use what an earlier one made: a form made fillable can be filled; a filled form
  or a new PDF can be faxed, merged, split or read back; values read back can fill a new form.

## Skills

Every task names a `skillId` in the message metadata; a task without one, or
with an id Emboss doesn't recognize, is rejected. There is no intent
inference: the client picks the skill.

| Skill | What it does | Input | Output |
| --- | --- | --- | --- |
| `make_fillable` | Detects fields on a flat PDF and makes it fillable. | A `FilePart` PDF. | A `form_id` and the detected field inventory. |
| `fill_form` | Fills a ready form with values. | A form reference (`form_id` or a PDF `FilePart`) and a `values` `DataPart`. | The `form_id`, a `download_url`, the `unmatched` values, and the filled PDF's `artifact_id`. |
| `fill_from_context` | Fills a form using answers pulled from context documents or notes. | A form reference (a `form_id`, a PDF `FilePart`, or a `library` slug) plus one or more context `FileParts` and/or `context_text`/`context_urls`. | The filled PDF as a `FilePart`, plus the `form_id`, the `filled` and `dropped` counts, any `warnings`, and the `artifact_id`. |
| `prepare` | Prepares a form instead of filling it: nothing is written into the PDF until a later `commit`. | A form reference (a `form_id`, a PDF `FilePart`, or a `library` slug) plus context `FileParts` and/or text, and an optional `policy` (`safe` or `strict`). | A `proposal_id` and the proposal: every field's proposed answer with the document it came from, the questions still open, the values awaiting confirmation, and the signatures and attachments a person still has to supply. |
| `commit` | Commits a proposal from `prepare`: writes the remaining values, renders the PDF with text that fits, checks it, and returns a receipt. | A `proposal_id` `DataPart`, plus an optional `confirm` list of field ids, any values still needed (`field_id`, `value`, and an optional `note`), an optional `policy`, and an optional `package`. | The verification result, a receipt link, the filled PDF, and the submission package when one was asked for. |
| `verify` | Checks a filled PDF against a form's contract: required fields, allowed options, consistent choices, text that fits, empty signature boxes. | A `form_id` and the filled PDF (a `FilePart` or `pdf_url`). | `complete`, `review required` or `incomplete`, plus the list of issues found. |
| `fill_batch` | Fills the form once per row of a spreadsheet. | A `form_id` (required) plus a CSV `FilePart` or `csv_text`, and an optional `mapping`. | Per-row results and a `zip_url` once the batch finishes. A batch over 50 rows keeps running after the answer: check the task with `tasks/get` for the finished zip. |
| `suggest_mapping` | Proposes which spreadsheet column fills which form field. | A `form_id` (required) plus a CSV `FilePart`, `csv_text`, or a `columns` `DataPart`. | A `mapping` of column to field id. |
| `find_forms` | Searches the forms already in the library. | A `query`, `state`, and `limit` `DataPart`. | Matching forms, each with its `id`, `title`, `state`, `pages` and `field_count`. |
| `find_form` | Finds a blank US federal form in the Emboss library, by name, number or alias. | A `query` `DataPart`, such as `W-9`, `i9` or `taxpayer identification`. | Each matching form's `slug`, `title`, `agency`, `revision` and `page_count`; pass a `slug` as `library` on `make_fillable`, `fill_from_context` or `prepare` to start from that form. |
| `get_form` | Reads one form's status and field inventory. | A `form_id` `DataPart`. | The form's status and, once ready, its fields. |
| `read_form` | Reads a filled PDF's values back out, labelled, without storing the file. | The filled PDF (a `FilePart` or `pdf_url`) and an optional `form_id` `DataPart`. | `recognised`, `fields`, `unmatched`, `counts`, and `complete`. |
| `send_fax` | Sends a PDF to a fax number and tracks delivery. The task stays `working` until the fax is delivered or fails; poll `tasks/get`. Signed-in callers need a payment method on file; without one the task fails before anything is sent. | A `to` `DataPart` (E.164) with a `job_id`, `form_id`, or `artifact_id`, or a `sources` list (each entry an `artifact_id`, an `artifact_token` for anonymous callers, and optional `pages`), or one or more PDF `FilePart`s. Anonymous x402 callers send `FilePart`s or an `artifact_id` with its `artifact_token`. | A receipt: `job_id`, `status`, `pages`, `price_cents`, `destination_masked`, `artifact_id`, and `source_artifact_ids`. |
| `attach` | Attaches a supporting document to a proposal before commit. | A `proposal_id` `DataPart`, a file part, and an optional `for` in the data part naming a required attachment. | The attachment's `n`, `filename`, `bytes`, and `sha256`. |
| `quote_job` | Prices a job before any paid work runs. | The target skill (`make_fillable`, `fill_form`, `fill_from_context`, `suggest_mapping`, `fill_batch`, or `send_fax`) and that skill's own input, exactly as a direct call would take. | A `quote_id`, the price and its expiry. With no account the price is fixed; for an account the job is billed like a direct call, so the free allowance and the documents' measured size apply. |
| `execute_quote` | Runs the job priced by an earlier `quote_job`, from its staged inputs, with no re-upload. | A `quote_id` `DataPart`. | The same result the quoted skill's direct call returns: a filled PDF, a fillable form, or a batch of filled copies. |
| `compose_pdf` | Free. Builds one PDF from several artifacts, each with an optional page selection and rotation. | A `sources` `DataPart`: a list of `{artifact_id, pages, rotate}`, plus an `artifact_token` per entry for anonymous callers. | The new `artifact_id` and, for anonymous callers, its `artifact_token`. |
| `merge_pdf` | Free. Joins whole PDFs in order. | A `sources` `DataPart`: a list of `{artifact_id}`, plus an `artifact_token` per entry for anonymous callers. | The new `artifact_id` and, for anonymous callers, its `artifact_token`. |
| `extract_pages` | Free. Keeps only the named pages of one artifact. | An `artifact_id`, `pages`, and an `artifact_token` for anonymous callers. | The new `artifact_id` and, for anonymous callers, its `artifact_token`. |
| `delete_pages` | Free. Removes the named pages of one artifact. | An `artifact_id`, `pages`, and an `artifact_token` for anonymous callers. | The new `artifact_id` and, for anonymous callers, its `artifact_token`. |
| `reorder_pages` | Free. Puts one artifact's pages in a new order. | An `artifact_id`, `order`, and an `artifact_token` for anonymous callers. | The new `artifact_id` and, for anonymous callers, its `artifact_token`. |
| `rotate_pages` | Free. Rotates named pages of one artifact. | An `artifact_id`, `rotations` (a list of `{pages, degrees}`), and an `artifact_token` for anonymous callers. | The new `artifact_id` and, for anonymous callers, its `artifact_token`. |
| `inspect_pdf` | Free. Reports structural facts about one artifact: no new file is produced. | An `artifact_id` and an `artifact_token` for anonymous callers. | Page count, page sizes and rotations, and whether the PDF is encrypted, has form fields, annotations, outlines, embedded files or JavaScript. |

`FilePart`s carry PDFs and CSVs as bytes or a URI; `DataPart`s carry
structured arguments. A task that works on a form returns its `form_id` in a
`DataPart`, and a task that produced a file returns that file's `artifact_id`,
so a client can chain skills, such as `make_fillable` then `fill_form`, by id
without downloading anything in between. The free PDF tools, `send_fax`,
`find_form`, `verify`, `read_form`, `attach` and `quote_job` return no
`form_id`. See [Artifacts and lineage](/docs/artifacts). Filled PDFs and batch zips come
back as `FileParts` pointing at the same signed download link the REST API
serves.

`prepare`, `commit` and `verify` are the two-call flow: see
[Prepare, commit and verify](/docs/prepare-commit-verify) for the proposal
shape, the three results, and the receipt. `read_form` is the reverse of that
flow, see [Read a filled form back](/docs/read-filled-form); `attach` and
`commit`'s `package` field hand over a finished submission as one file, see
[The submission package](/docs/submission-package).

Skills excluded from A2A on purpose: deleting a form stays on MCP and REST,
where a client's own confirmation rules gate it, and usage lookups stay on
the [dashboard](/dashboard).

## Task lifecycle and streaming

A task moves from `submitted` to `working` to `completed` or `failed`. A
request Emboss cannot run, such as an unknown skill, a missing form reference
or values that match no field, ends as a `rejected` task with the reason. A
paid skill called with no account waits in `input-required` until it is paid.
A 402 billing error, such as the free tier being used up, completes the task as
`failed` with the message and billing link. A connection that signed in with
read access only is rejected for any skill that changes something; reconnect
to allow changes.

Emboss supports streaming: a client that sends a streaming message or
subscribes to a task receives status updates as the work happens, including
one update per row for a batch fill, rather than only a single response at
the end. Cancellation is honored before a task starts running, and while a
paid task still waits for its payment: cancelling it withdraws the payment
request, and nothing is charged. Once Emboss has begun the underlying job, it
runs to completion.

## Slower skills and checking a task

A skill whose job takes a while, such as making a new flat form fillable or
filling a form from documents, answers within about 4 seconds either way:

- If the job finishes in that time, the answer carries the result as usual.
- If not, the answer is the task in state `working`, with the message "Still
  running. Check this task in a few seconds for the result." The job keeps
  running. Check the task with `tasks/get` (GetTask) every few seconds until
  it ends (`completed`, `failed` or `rejected`).
- A client holding a live stream gets a `working` update with the message
  "Still working." every 3 seconds, and the result arrives on the same stream.

Skills that answer at once, such as reading a filled form, suggesting a
mapping and the free PDF utilities, answer with their result as before.

Checking a task returns one of:

- `working`: the job is still running;
- `completed`, with the result the answer would have carried, such as the
  form id, the fields and a download link for a new fillable form. Two echoes
  of your request are not kept, so a check leaves them out: the values
  `fill_form` could not match, and the mapping `fill_batch` used. The link
  stays the same however many times you check that day (UTC); a check on a
  later day gets a new one;
- `failed`, with the reason in the status message;
- `rejected`, with the reason, when the request could not be done, for
  example when none of the values sent to `fill_form` matched a field.

For an account, ListTasks (A2A 1.0) with `includeArtifacts: true` lists its
own tasks with each task's result.

A job's files are kept for its retention period: about an hour with
ephemeral processing, which every x402 job uses, or longer when an account
keeps them. Once they are deleted, a completed task carries no result, and
its status message reads "This result has expired: its files are deleted
about an hour after the job."

Send a new message on a task only to answer it, for example to pay for it. A
message on a task that is running or finished is refused with one of: "This
task is still running; check it in a few seconds for the result.", "This task
is finished; check it for the result.", or, for a task you paid for, "This task
is paid; check it for the result." To get a result back, check the task: a new
task is a new job, with a new price.

If we update Emboss while your job is running, the cut-off task is noticed
within about half an hour: after 15 minutes with no sign of life, on a check
that runs every 10 minutes. Then a job for an account starts again on its
own. This covers only these: making a form fillable (`make_fillable`),
filling from documents (`fill_from_context`) and preparing a form
(`prepare`). Each runs at most three times in all. Any other job cut off by
an update ends `failed` with a message that ends "Contact
contact@getemboss.ai with your task id.", and so does one of these cut off on
its third run. A job that had already finished when the update came is not
affected: its task shows how the job ended.

A fax or a batch is never sent or run again. A fax already with the carrier
is still delivered. A batch of more than 50 rows fills in the background
after its task has answered; if an update cuts it off, it is marked `failed` with the code
`interrupted` six hours after it started; send it again.

A job paid for with x402 never starts again. What its task says depends on
the payment:

- If no payment could have been taken, the task ends `failed` with
  "Interrupted by maintenance; not charged. Send the request again."
- If the payment was recorded and the job had run, the task carries its
  result and receipt as usual.
- Otherwise a payment may have been taken: the task ends `failed` with a
  message that ends "Contact contact@getemboss.ai with your task id." Write to
  that address with the task id rather than paying again on a new task.

## Retention

`make_fillable`, `fill_form`, `fill_from_context` and `prepare` take an
optional `retention` `DataPart` field: `ephemeral` or `account_default`. Leave
it out and the account's own default applies. It applies only when the call
creates the form; an existing form keeps the setting it was created with.
`fill_batch` also accepts the field, but a batch always fills an existing form,
so there it changes nothing.
See [Ephemeral processing](/docs/ephemeral-processing) for the window and
what a 410 means once a form is swept.

## Limits

- A form PDF: up to 10 MB and 100 pages.
- Supporting documents for `fill_from_context` and `prepare`: up to 5 in all,
  counting `context_text` as one; `context_text` up to 200,000 characters; each
  linked or attached file up to 10 MB.
- `fill_batch`: up to 1,000 rows.
- A proposal's attachments: up to 20 files and 20 MB in all.

## Billing and privacy

Free tier: The first 5 form creations, 5 context fills, 5 standard fills, 5 verifications, 5 reads, and 5 packages each month are free when the job is 5 pages or fewer (a context fill counts the form and its documents together); a longer job is charged and does not use a free one. `suggest_mapping` is
billed as one context fill. See [Pricing](/pricing) for current rates. Only
the arguments a task needs are sent to Emboss. If you connected Emboss with
OAuth, disconnect at any time from **Dashboard**, then **Account**, then
**Connected apps**.

## See also

- [Fill PDFs from your own data](https://getemboss.ai/use-cases/fill-pdfs-from-your-data)
- [MCP server](https://getemboss.ai/glossary/mcp-server)
- [MCP tools reference](https://getemboss.ai/docs/mcp-tools)
- [Use Emboss in Antigravity](https://getemboss.ai/docs/antigravity)
- [Authentication](https://getemboss.ai/docs/authentication)
- [Pay per call](https://getemboss.ai/docs/pay-per-call)
- [Pay per call with MPP](https://getemboss.ai/docs/pay-per-call/mpp)
- [Pay per job with x402](https://getemboss.ai/docs/pay-per-call/x402)
- [Use Emboss in Gemini Enterprise](https://getemboss.ai/docs/gemini-enterprise)
- [Trust and verification](https://getemboss.ai/docs/reference/trust)
- [Connect to AI](https://getemboss.ai/connect)
