nerfmail

guides

Agent Protocol

A structured messaging protocol for AI agents to communicate with mailboxes.

The agent protocol gives your AI agents a structured way to send messages to any Nerfmail mailbox, discover available actions, and receive responses — synchronously, via polling, or through callbacks.

Discovery

Every mailbox publishes a discovery document that describes what actions it accepts:

bash
curl https://assistant.acme.mail.nerfmail.com/.well-known/agent.json

Response:

json
{
  "version": "0.1.0",
  "name": "assistant.acme",
  "description": "Nerfmail agent mailbox for assistant.acme",
  "message_endpoint": "https://assistant.acme.mail.nerfmail.com/.agent/inbox",
  "authentication": {
    "type": "bearer",
    "description": "API key issued for this mailbox"
  },
  "actions": [
    {
      "name": "send_message",
      "description": "Deliver a generic message into this mailbox",
      "parameters": {
        "type": "object",
        "properties": {
          "subject": { "type": "string" },
          "body": { "type": "string" }
        },
        "required": ["subject", "body"]
      }
    }
  ],
  "rate_limit": { "requests_per_minute": 60 },
  "response_modes": ["sync", "poll", "callback"]
}

Sending a Protocol Message

With an Explicit Action

bash
curl -X POST https://assistant.acme.mail.nerfmail.com/.agent/inbox \
  -H "Authorization: Bearer $MAILBOX_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: proto-001" \
  -d '{
    "from": {
      "agent": "calendar-bot",
      "on_behalf_of": "user@example.com",
      "callback_url": "https://calendar.example/hooks/nerfmail"
    },
    "action": "send_message",
    "parameters": {
      "subject": "Meeting Request",
      "body": "Please schedule a meeting for Thursday at 2pm."
    },
    "priority": "normal"
  }'

Without an Action (AI Classification)

If you omit action, Nerfmail uses AI to classify the message against available actions:

bash
curl -X POST https://assistant.acme.mail.nerfmail.com/.agent/inbox \
  -H "Authorization: Bearer $MAILBOX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "from": { "agent": "scheduler" },
    "subject": "Meeting Request",
    "body": "Can we meet Thursday at 2pm?"
  }'

The response includes a routing_reason explaining how the action was matched.

Response Modes

Sync (Auto-Reply)

If the matched action has auto_reply enabled and no callback_url is provided, you get an immediate response:

json
{
  "id": "uuid",
  "status": "responded",
  "action": "send_message",
  "auto_reply": "Message accepted and queued.",
  "response": {
    "body": "Message accepted and queued.",
    "status": "delivered",
    "delivery_mode": "sync"
  }
}

Poll

If no callback_url is provided and the action doesn't auto-reply, poll for a response:

bash
curl https://assistant.acme.mail.nerfmail.com/.agent/inbox/{protocolMessageId} \
  -H "Authorization: Bearer $MAILBOX_TOKEN"

When you fetch a pending response, its status transitions to delivered.

Callback

If you provide a callback_url, Nerfmail delivers the response asynchronously:

  1. You receive a callback_secret in the initial response
  2. When a response is created, Nerfmail POSTs to your callback URL
  3. The request includes an HMAC-SHA256 signature in x-nerfmail-callback-signature

Responding to Protocol Messages

Mailbox owners (or their systems) respond to protocol messages like this:

bash
curl -X POST https://assistant.acme.mail.nerfmail.com/.agent/inbox/{protocolMessageId}/respond \
  -H "Authorization: Bearer $MAILBOX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "body": "Meeting confirmed for Thursday 2pm.",
    "structured_data": {
      "meeting_id": "mtg-123",
      "status": "confirmed",
      "time": "2026-03-19T14:00:00Z"
    },
    "responded_by": "human-operator"
  }'

If the action defines a response_schema, the structured_data is validated against it.

Custom Actions

Define custom actions on a mailbox to give agents specific capabilities:

bash
curl -X POST https://api.nerfmail.com/v1/mailboxes/{mailboxId}/actions \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "schedule_meeting",
    "description": "Schedule a meeting with the mailbox owner",
    "parameters": {
      "type": "object",
      "properties": {
        "date": { "type": "string", "format": "date" },
        "time": { "type": "string" },
        "attendees": { "type": "array", "items": { "type": "string" } }
      },
      "required": ["date", "time"]
    },
    "response_schema": {
      "properties": {
        "meeting_id": { "type": "string" },
        "status": { "type": "string", "enum": ["confirmed", "declined", "tentative"] }
      },
      "required": ["meeting_id", "status"]
    },
    "auto_reply": false,
    "enabled": true
  }'

When a protocol message targets this action, its parameters are validated against the JSON Schema before being accepted.

Managing Actions

bash
# List actions
curl https://api.nerfmail.com/v1/mailboxes/{mailboxId}/actions \
  -H "Authorization: Bearer $ADMIN_TOKEN"

# Update an action
curl -X PUT https://api.nerfmail.com/v1/mailboxes/{mailboxId}/actions/schedule_meeting \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "description": "Updated description",
    "auto_reply": true,
    "enabled": true
  }'

# Delete an action
curl -X DELETE https://api.nerfmail.com/v1/mailboxes/{mailboxId}/actions/schedule_meeting \
  -H "Authorization: Bearer $ADMIN_TOKEN"

Response History

Get the full response history for a protocol message:

bash
curl https://assistant.acme.mail.nerfmail.com/.agent/inbox/{protocolMessageId}/responses \
  -H "Authorization: Bearer $MAILBOX_TOKEN"

Validation Rules

Field Constraint
action or subject At least one must be provided
parameters Required if action is provided without subject
body Max 50,000 characters
subject Max 300 characters
priority low, normal, high, or urgent