API reference Markdown

Inbox

The inbox endpoints read the messages that arrived in the mailboxes of the workspace, with the full text, and send an answer. Replies returns the same messages with a snippet and is the place to correct a classification.

Method Path Action
GET /api/v1/inbox/messages List messages with the full text
POST /api/v1/inbox/messages/{id}/reply Answer a message

List messages#

Parameter Type Notes
category string One of interested, neutral, not_interested, unclassified, autoresponder.
unread string true for unread messages only, false for read ones.
since ISO 8601 Messages received at or after this time.
campaign_id UUID Messages in reply to one campaign.
prospect_id UUID Messages from one prospect.
limit integer 1 to 100. Default 50.
cursor string See Pagination.

Without category, the list leaves out autoresponders, like the All replies folder in the app. Newest messages come first.

curl "https://app.anymail.watch/api/v1/inbox/messages?unread=true&category=interested" \
  -H "Authorization: Bearer $ANYMAIL_TOKEN"
const res = await fetch("https://app.anymail.watch/api/v1/inbox/messages?unread=true&category=interested", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.ANYMAIL_TOKEN}`,
  },
});
console.log(res.status, await res.text());
import os
import requests

response = requests.request(
    "GET",
    "https://app.anymail.watch/api/v1/inbox/messages?unread=true&category=interested",
    headers={
        "Authorization": f"Bearer {os.environ['ANYMAIL_TOKEN']}",
    },
)
print(response.status_code, response.text)

Response 200

{
  "data": [
    {
      "id": "20000000-0000-0000-0000-000000000001",
      "prospect": { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "email": "ada@example.com", "first_name": "Ada", "last_name": null },
      "company": { "id": "1b4e28ba-2fa1-11d2-883f-0016d3cca427", "name": "Example Ltd", "domain": "example.com" },
      "campaign": { "id": "3f2b1c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d", "name": "Q3 outbound" },
      "mailbox_id": "b2c3d4e5-0000-4000-8000-000000000001",
      "from_email": "ada@example.com",
      "subject": "Re: Quick question",
      "classification": "interested",
      "classification_overridden": false,
      "is_autoresponder": false,
      "is_read": false,
      "received_at": "2026-09-03T10:00:00.000+00:00",
      "snippet": "Sounds good, let's talk next week. Does Tuesday 10:00 work?",
      "body": "Sounds good, let's talk next week. Does Tuesday 10:00 work?\n\nAda"
    }
  ],
  "next_cursor": null
}

The fields are those of Replies plus body, the full text of the message. Reading the list does not mark a message as read.

Errors: 400 for an invalid category, unread, since, UUID, limit or cursor.

Answer a message#

POST /api/v1/inbox/messages/{id}/reply sends an answer from the mailbox the message arrived in, in the same thread, to the sender of the message. It runs the Reply action of the inbox in the app. This sends real email.

Body (JSON, up to 64 KiB)

Field Type Required Notes
body string Yes Plain text, up to 20,000 characters after trimming.
curl -X POST "https://app.anymail.watch/api/v1/inbox/messages/20000000-0000-0000-0000-000000000001/reply" \
  -H "Authorization: Bearer $ANYMAIL_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 1d7c2f4e-8a90-4b3c-9d1e-2f3a4b5c6d7e" \
  -d '{"body":"Thanks Ada, Tuesday 10:00 works. I will send an invite."}'
const res = await fetch("https://app.anymail.watch/api/v1/inbox/messages/20000000-0000-0000-0000-000000000001/reply", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.ANYMAIL_TOKEN}`,
    "Content-Type": "application/json",
    "Idempotency-Key": "1d7c2f4e-8a90-4b3c-9d1e-2f3a4b5c6d7e",
  },
  body: JSON.stringify({"body": "Thanks Ada, Tuesday 10:00 works. I will send an invite."}),
});
console.log(res.status, await res.text());
import os
import requests

response = requests.request(
    "POST",
    "https://app.anymail.watch/api/v1/inbox/messages/20000000-0000-0000-0000-000000000001/reply",
    headers={
        "Authorization": f"Bearer {os.environ['ANYMAIL_TOKEN']}",
        "Idempotency-Key": "1d7c2f4e-8a90-4b3c-9d1e-2f3a4b5c6d7e",
    },
    json={'body': 'Thanks Ada, Tuesday 10:00 works. I will send an invite.'},
)
print(response.status_code, response.text)

Response 200

{ "sent": true, "to": "ada@example.com" }

When the message went out but anymail could not record it, the response is still 200, with warning in place of to. Do not retry in that case, because a retry sends a second email. An Idempotency-Key protects a retry after a timeout.

Errors

Status Message
400 `body` must be a non-empty string., `body` is limited to 20000 characters.
404 Message not found. This includes a message from another workspace and an id that is not a UUID.
409 The mailbox this reply arrived in no longer exists. or This reply has no sender address to answer.
502 Couldn't send: <reason>. The mail server refused the message.