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:
curl https://assistant.acme.mail.nerfmail.com/.well-known/agent.jsonResponse:
{
"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
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:
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:
{
"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:
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:
- You receive a
callback_secretin the initial response - When a response is created, Nerfmail POSTs to your callback URL
- 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:
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:
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
# 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:
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 |