Agent identity & provenance

Give your agents a signed identity so recipients can verify the mail genuinely came from them.

Give an automated sender its own verifiable identity. An agent passport is a portable agt_… identity that signs the email your agents send, so anyone receiving that mail can confirm it genuinely came from your agent — not a spoofer.

This is an optional layer. You don't need a passport to send or receive email; reach for it when you want recipients (or downstream agents) to be able to prove who sent a message. Reads use agents:read; creating and binding use agents:write. Verifying is public — no scope or API key.

Create a passport

curl -X POST https://api.dairo.app/v1/agents \
  -H "Authorization: Bearer $DAIRO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "display": "Support Bot", "description": "Handles inbound support email" }'

You get back the passport, including a portable agentId:

{
  "agent": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "agentId": "agt_7h2k9q4m3xeyrt6bv8wn0pcd",
    "display": "Support Bot",
    "description": "Handles inbound support email",
    "status": "active",
    "createdAt": "2026-06-12T10:00:00Z",
    "updatedAt": "2026-06-12T10:00:00Z"
  }
}

Use the portable agentId (agt_…) — stable for the life of the passport — in anything you publish or share.

Creating a passport isn't idempotent: each call mints a new agentId, so create once and store the id rather than retrying.

List and read

Read a passport by its id or its portable agt_… id. Listing returns an agents array, newest first — there's no pagination or limit, so one call returns every passport in your organization.

curl https://api.dairo.app/v1/agents \
  -H "Authorization: Bearer $DAIRO_API_KEY"

curl https://api.dairo.app/v1/agents/agt_7h2k9q4m3xeyrt6bv8wn0pcd \
  -H "Authorization: Bearer $DAIRO_API_KEY"

A passport supports create, read, bind, and delete — there's no edit. Deleting a passport clears its attribution from your keys, inboxes, and sent mail without touching the messages themselves. Those messages keep their provenance headers, but verifying one afterward returns unknown_agent, since the passport it named is gone.

Bind a key or inbox

A passport on its own is only an identity. Binding connects it to the resources an agent actually sends through — an API key and/or an inbox — so every email those resources produce is signed with the agent's provenance and attributed to it in your send-health view.

Pass at least one of apiKeyId / inboxId — both must be resources you own. Reference the passport by its id or its portable agt_… id.

curl -X POST https://api.dairo.app/v1/agents/agt_7h2k9q4m3xeyrt6bv8wn0pcd/bindings \
  -H "Authorization: Bearer $DAIRO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "inboxId": "7c9e6679-7425-40de-944b-e07fc1f90ae7" }'

The response echoes what was bound:

{
  "agentId": "agt_7h2k9q4m3xeyrt6bv8wn0pcd",
  "apiKeyId": null,
  "inboxId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "bound": true
}

Bind both at once by passing apiKeyId and inboxId together.

You can only bind your own resources to your own passport — there's no way to attach someone else's key or inbox.

After binding, mail from that key or inbox carries the agent's X-Dairo-Provenance signature, and cross-account agent-to-agent hop receipts record the bound agentId. From then on, the agent's reputation and any per-agent send limit gate what it can send.

How provenance works

When a send goes out from a bound key or inbox, Dairo signs a stable summary of the message (the from, to, subject, and timestamp) and stamps two headers onto the outgoing mail:

  • X-Dairo-Provenance — the signature token.
  • X-Dairo-Verify — a verify URL anyone can click.

Signing is best-effort and never blocks a send. A recipient re-derives the same summary from the message they received and checks the signature against the public key Dairo publishes in its JWKS — so they can confirm authenticity without trusting you, or even calling Dairo.

Verify a signed message

Provenance is only useful if anyone can check it. Two public endpoints let them: a verify endpoint that returns a plain yes/no for a given message, and a JWKS that publishes the public signing keys so anyone can check a signature on their own. Neither needs a scope or an API key.

Get a verdict

The simplest path: hand Dairo a message id and get back a verdict, with no crypto on your side. The endpoint always returns 200 with a verdict — a "no" is a result, not an error.

curl "https://api.dairo.app/v1/agents/verify?id=3fa85f64-5717-4562-b3fc-2c963f66afa6"

A verdict carries verified, the matched agent (when known), the keyId, the issuer (dairo.app), and a checkedAt timestamp:

{
  "verified": true,
  "agent": { "agentId": "agt_7h2k9q4m3xeyrt6bv8wn0pcd", "display": "Support Bot", "status": "active" },
  "keyId": "dairo-ed25519-2026-06",
  "issuer": "dairo.app",
  "checkedAt": "2026-06-12T12:00:01Z"
}

A "no" returns the same shape with "verified": false and a reason such as missing_parameters, message_not_found, unknown_kid, or bad_signature.

Because verify never errors, branch on the verified field — not on the HTTP status. A 200 with "verified": false is the expected "no" answer.

Verify a signature yourself

To check a signature without relying on Dairo's lookup — say, from the headers on a message you received — pass the signature (agent + kid + sig) together with the signed fields (from, to, subject, ts):

curl "https://api.dairo.app/v1/agents/verify?agent=agt_7h2k9q4m3xeyrt6bv8wn0pcd&kid=dairo-ed25519-2026-06&sig=…&from=bot@acme.dairo.app&to=user@example.com&subject=Your%20receipt&ts=2026-06-12T12:00:00Z"

Check it offline with the public keys

GET /v1/agents/jwks serves the public signing keys as a standard JSON Web Key Set, so you can verify a signature entirely on your own — no call back to Dairo. It serves active and retired keys, so a kid that signed an old message stays verifiable forever.

curl https://api.dairo.app/v1/agents/jwks
{
  "keys": [
    {
      "kty": "OKP",
      "crv": "Ed25519",
      "alg": "EdDSA",
      "use": "sig",
      "kid": "dairo-ed25519-2026-06",
      "x": "_h5rlaNeTyovkSiWHs2nG3LPyxd3gq3_CrDwknputUM"
    }
  ]
}

Find the key whose kid matches the message's signature, then verify the signed fields against it with any standard EdDSA library.

Next steps

On this page