How it works Capabilities Attribution Pricing Docs Follow on X Get API access

Docs preview · flag spec v1

A static look at the API.

Defeat gives every AI agent a real mailbox and a verified identity card. These snippets describe the surface that is being built to deliver it: mailboxes, signed sends, webhooks, and the flag record that carries the identity.

There is no live API behind this page yet. Nothing here accepts a request. Request access and you get a sandbox key and this document as a contract the first release has to honour.

01

Authentication

Send a bearer token on every request. A key is scoped to one operator and carries that operator into every flag it signs. Rotate from the dashboard without interrupting a running agent, since the old key stays valid for an hour after you replace it.

http header
Authorization: Bearer dft_live_…
  • Two key types. dft_test_ keys run against the sandbox and can only deliver to addresses you have verified. dft_live_ keys deliver to anyone.
  • Keys never sign on their own. The signing key for a flag lives on your domain. The API key only says which operator is asking.

02

Create a mailbox

Mint an address and attach a flag in one call. Set expires_in and the mailbox disappears with the run that owns it. Set public: true on the flag and the attribution page resolves for anyone, with no account.

curl POST /v1/mailboxes
curl -X POST https://api.defeatemail.net/v1/mailboxes \
  -H "Authorization: Bearer $DEFEAT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "address": "triage@acme.defeatemail.net",
       "expires_in": "24h",
       "flag": {
         "agent": "triage",
         "operator": "acme.co",
         "accountable": "jordan@acme.co",
         "public": true
       }
     }'
json 201 Created
{
  "id": "mbx_3kQ7y2",
  "address": "triage@acme.defeatemail.net",
  "flag": {
    "id": "agent_7Kq4x1",
    "state": "published",
    "url": "https://defeatemail.net/f/agent_7Kq4x1"
  },
  "expires_at": "2026-09-23T09:14:00Z"
}

03

Send

Send from the agent address. The recipient sees an ordinary message and can open the flag from the header. Pass mode: "review" to hold the draft for a person to approve, and the flag records who released it.

typescript messages.send
const sent = await defeat.messages.send({
  from:    'triage@acme.defeatemail.net',
  to:      'jordan@acme.co',
  subject: 'Ticket 88213 needs a human',
  text:    'The refund is above my agent limit.',
  flag:    { task: 'run_88213', model: 'claude-opus-5' },
});

console.log(sent.flag.url);   // defeatemail.net/f/agent_7Kq4x1
console.log(sent.thread_id); // thr_4b21
  • Idempotent. Pass Idempotency-Key and a retried send returns the original message instead of a duplicate.
  • Limits apply before delivery. An agent over its rate cap or outside its recipient allowlist gets 429 or 403, and nothing leaves.

04

Webhooks

Subscribe once and route by mailbox or by operator. Agents should not poll. Every delivery is signed with your endpoint secret and retried with backoff for 24 hours.

message.received message.sent message.held message.bounced flag.updated mailbox.expired
typescript webhooks
defeat.webhooks.on('message.received', async (event) => {
  if (event.verdict !== 'verified') {
    return defeat.messages.hold(event.message_id);
  }
  const thread = await defeat.threads.get(event.thread_id);
  return agent.handle(thread);
});

05

Flags

A flag is the identity card for a mailbox. It answers three things for the recipient: who wrote the message, who operates the agent, and whether the address is a throwaway. Required fields are agent name, operator, accountable contact, verification state, and first_seen. Optional: purpose, website, and a contact for disputes.

json GET /v1/flags/agent_7Kq4x1
{
  "id": "agent_7Kq4x1",
  "agent": "triage",
  "operator": "acme.co",
  "accountable": "jordan@acme.co",
  "state": "published",
  "key": "ed25519:9f3c…41ab",
  "key_source": "https://acme.co/.well-known/defeat-keys",
  "first_seen": "2026-03-04",
  "disputes": "abuse@acme.co"
}
  • A flag can sit in draft until the first outbound message. Publishing it is what makes the mailbox attributable.
  • Keys live on your domain, not ours. Rotating a key at the well-known path does not invalidate mail signed under the previous one.
  • The ledger keeps the flag id even when the flag was never published, so an unattributed send is still traceable internally.
  • Address standing is part of the record. first_seen is what tells a recipient the address is not a throwaway minted this morning.

06

Verdicts

Every inbound message carries exactly one verdict, resolved before it reaches your webhook. A verdict is a statement about proof, not about intent. Unsigned means nothing was proven, and it never means the sender is hostile.

VerdictMeansDefault policy
verified Signature checks out against a key the operator domain publishes, and the flag resolves. Deliver
unsigned No flag on the message. Could be a person, could be an agent. Nothing is proven either way. Hold
quarantined A flag was claimed and the signature failed, or the sending domain does not match the operator. Quarantine and log

Override any of these per mailbox with a rule. A recipient can also set a standing policy from their own side: no unsigned agents, no agents at all, or only operators they already know.

07

Errors and limits

Errors return a stable machine-readable code alongside the status. Rate limit state comes back on every response, so an agent can back off without guessing.

StatusCodeWhen
400invalid_addressThe address is malformed or the domain is not one you control.
401invalid_keyMissing, revoked, or wrong-environment bearer token.
403recipient_not_allowedThe recipient is outside the allowlist set on this agent.
409flag_unpublishedSending from a mailbox whose flag is still in draft.
422key_not_resolvableThe signing key is not served at the well-known path on the operator domain.
429rate_limitedOver the per-agent send cap. Retry after the header says so.
http response headers
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 584
X-RateLimit-Reset: 1790069126
Retry-After: 18

Build against this surface.

Request access and you get a sandbox key, three mailboxes, and the flag spec. Tell us what your agents send and we will tell you honestly whether Defeat is ready for it.

Request API access