API reference Markdown

Statistics

GET /api/v1/campaigns/{id}/stats returns the numbers of one campaign in three parts: totals, the funnel from the campaign list and a breakdown by step and A/B variant. No number is computed differently from the app. Totals match the Stats tab, the funnel matches the campaign list.

Method Path Action
GET /api/v1/campaigns/{id}/stats Statistics of a campaign
curl "https://app.anymail.watch/api/v1/campaigns/3f2b1c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d/stats" \
  -H "Authorization: Bearer $ANYMAIL_TOKEN"
const res = await fetch("https://app.anymail.watch/api/v1/campaigns/3f2b1c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d/stats", {
  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/campaigns/3f2b1c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d/stats",
    headers={
        "Authorization": f"Bearer {os.environ['ANYMAIL_TOKEN']}",
    },
)
print(response.status_code, response.text)

Response 200

{
  "campaign_id": "3f2b1c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
  "totals": {
    "sent": 312,
    "delivered": 305,
    "opened": null,
    "clicked": null,
    "replied": 19,
    "interested": 6,
    "maybe_later": 9,
    "not_interested": 4,
    "autoreplied": 3,
    "bounced": 7,
    "unsubscribed": 2,
    "reply_rate": 0.0609,
    "enrolled": 100,
    "tracking_enabled": false
  },
  "funnel": {
    "contacted": 96,
    "enrolled": 100,
    "contactedPct": 96,
    "delivered": 305,
    "deliveredPct": 98,
    "replyRatio": 0.0609,
    "interested": 6,
    "neutral": 9,
    "negative": 4
  },
  "steps": [
    {
      "position": 1,
      "subject": "Quick question, {{first_name}}",
      "sent": 96,
      "delivered": 93,
      "bounced": 3,
      "replied": 11,
      "interested": 4,
      "maybe_later": 5,
      "opened": null,
      "opened_unique": null,
      "queued": 4,
      "branch": null,
      "variants": [
        { "label": "A", "subject": "Quick question, {{first_name}}", "active": true, "deleted": false, "sent": 48, "delivered": 47, "bounced": 1, "replied": 7, "interested": 3, "maybe_later": 2, "opened": null },
        { "label": "B", "subject": "{{first_name}}, a question about {{company}}", "active": true, "deleted": false, "sent": 48, "delivered": 46, "bounced": 2, "replied": 4, "interested": 1, "maybe_later": 3, "opened": null }
      ]
    }
  ]
}

Totals#

Field Notes
sent, delivered, bounced Messages. delivered is sent minus bounced. SMTP does not report delivery.
replied Replies, without autoresponders.
interested, maybe_later, not_interested Replies by classification. maybe_later is the neutral class.
autoreplied Autoresponders, counted apart from replies.
reply_rate replied / sent as a fraction from 0 to 1.
enrolled People enrolled in the campaign.
opened, clicked null until the tracking domain of the workspace is verified. null means not measured. It does not mean zero.

Funnel#

The funnel mixes two units, as in the app. contacted and enrolled count people. delivered and replyRatio count messages.

Field Notes
contacted People who received at least one message.
contactedPct contacted as a rounded percentage of enrolled. null when nobody is enrolled.
deliveredPct delivered as a rounded percentage of sent messages.
replyRatio Replies per sent message, 0 to 1. null when nothing was sent.
interested, neutral, negative Replies by classification.

The funnel keys are in camelCase, unlike the rest of the API. They are the same keys the app uses.

Steps and variants#

steps has one row per email step, in order.

Field Notes
queued Active enrolments that wait for this step.
opened Open events for messages of this step, with repeats. null without tracking.
opened_unique Messages of this step opened at least once, which is the number of people. null without tracking.
branch { "yes": n, "no": n } when a condition built in the app gates this step, otherwise null.
variants One row per A/B variant. deleted: true marks a variant that was removed after it sent messages, so its history stays visible.

Unsubscribes have no per step number, because the unsubscribe link is the same on every step.

Treat opens as a weak signal. Apple Mail Privacy Protection opens the tracking pixel without a person.

Errors: 404 with Campaign not found., including a campaign from another workspace and an id that is not a UUID.