{
 "slug": "buttondown",
 "name": "Buttondown",
 "url": "https://buttondown.com",
 "domain": "buttondown.com",
 "category": "email-marketing",
 "category_name": "Email marketing",
 "tested_at": "2026-10-02",
 "run": "20261002T214646Z",
 "draft": false,
 "reviewed": true,
 "owner_verified": null,
 "origin": "editorial",
 "history": [
  {
   "run": "20261001T231217Z",
   "date": "2026-10-01",
   "level": 2,
   "engine": {
    "runner": "omp",
    "model": null,
    "driver": null,
    "signed": true,
    "inbox": null,
    "robots": "start"
   }
  },
  {
   "run": "20261002T214646Z",
   "date": "2026-10-02",
   "level": 4,
   "engine": {
    "runner": "omp",
    "model": "claude-opus-5-5",
    "driver": 2,
    "signed": true,
    "inbox": [
     "agentdrives.com"
    ],
    "robots": "start"
   },
   "why": "product"
  }
 ],
 "level": 4,
 "level_name": "Runs on its own",
 "level_selfhost": null,
 "entry": "self-start",
 "door": {
  "passed": 2,
  "tries": 2,
  "self_start": true
 },
 "badges": [
  "agent-can-leave"
 ],
 "stages": [
  {
   "key": "in",
   "label": "Access",
   "state": "yes",
   "text": "Gets in on its own: sign-up in a browser"
  },
  {
   "key": "work",
   "label": "Use",
   "state": "yes",
   "text": "Work done: 83% of the core"
  },
  {
   "key": "pay",
   "label": "Pay",
   "state": "part",
   "text": "Reaches the checkout: stopped at the card form",
   "value": "ready",
   "route": "card_checkout"
  },
  {
   "key": "leave",
   "label": "Leave",
   "state": "yes",
   "text": "Leaves on its own: nothing to cancel, deletes its account",
   "left": "deleted"
  }
 ],
 "outcomes": [
  {
   "key": "find",
   "label": "Find",
   "state": "part",
   "text": "Some docs agents can read: llms.txt and an OpenAPI",
   "have": [
    "llms_txt",
    "openapi"
   ]
  },
  {
   "key": "access",
   "label": "Access",
   "state": "yes",
   "text": "Gets in on its own: sign-up in a browser",
   "stage": "in"
  },
  {
   "key": "use",
   "label": "Use",
   "state": "yes",
   "text": "Work done: 83% of the core",
   "stage": "work"
  },
  {
   "key": "pay",
   "label": "Pay",
   "state": "part",
   "text": "Reaches the checkout: stopped at the card form",
   "value": "ready",
   "route": "card_checkout",
   "stage": "pay"
  },
  {
   "key": "leave",
   "label": "Leave",
   "state": "yes",
   "text": "Leaves on its own: nothing to cancel, deletes its account",
   "left": "deleted",
   "stage": "leave"
  }
 ],
 "access": [
  {
   "key": "browser_signup",
   "label": "Sign-up in a browser",
   "routes": [],
   "minutes": 3.3,
   "core": "5/6"
  }
 ],
 "minutes": 3.3,
 "next": {
  "to": 5,
  "text": "Next: pay without a person"
 },
 "stop": null,
 "core": "5/6",
 "scores": {
  "coverage": 75,
  "reliability": 100,
  "resilience": null,
  "setup": 85,
  "surface_coverage": null,
  "docs_accuracy": null,
  "docs_completeness": null
 },
 "parts": {
  "holds_up": null,
  "docs_match": null,
  "setup": 85,
  "security": null,
  "standards": []
 },
 "reliability_method": "first-try",
 "resilience": null,
 "stress": [],
 "surface_audit": null,
 "coverage_core": 83,
 "after_wall": null,
 "coverage_source": "computed",
 "driver": {
  "version": 2,
  "model": "claude-opus-5-5",
  "profile": "full",
  "assisted": false,
  "handoff": null,
  "prompt_sha": null,
  "kb_version": null,
  "identity": null
 },
 "methodology": 15,
 "rules_date": "2026-10-15",
 "engine": {
  "runner": "omp",
  "model": "claude-opus-5-5",
  "driver": 2,
  "signed": true,
  "inbox": [
   "agentdrives.com"
  ],
  "robots": "start"
 },
 "same_level_drives": 1,
 "drives": 2,
 "works_assisted": null,
 "freshness": "fresh",
 "nothing_to_pay": false,
 "core_gated": false,
 "profiles": {},
 "agent_check": null,
 "agent_pass": null,
 "who_gets_in": {
  "server": {
   "state": "in"
  },
  "signed": {
   "state": "page",
   "kind": "signup",
   "at": "2026-10-12"
  },
  "browser": {
   "state": "in",
   "measured": false
  },
  "our_key": "pending",
  "robots": null,
  "tip": false
 },
 "ladder": {
  "docs": {
   "status": "headless",
   "note": "llms.txt on buttondown.com and docs.buttondown.com, OpenAPI at docs.buttondown.com/openapi.json (77 paths); 401 errors point at the auth docs."
  },
  "signup": {
   "status": "browser",
   "note": "Sign-up is a JS form at /register (username, email, password) with no CAPTCHA; no documented sign-up API. Worked first time in our agent's browser."
  },
  "verify": {
   "status": "headless",
   "note": "Confirmation mail arrived within a minute; the link works with a plain GET (302 to /home)."
  },
  "credentials": {
   "status": "browser",
   "note": "A primary API key is created at sign-up and shown in the dashboard at /keys. There is no documented API to read or create keys.",
   "via": ""
  },
  "first_call": {
   "status": "headless",
   "note": "GET /v1/ping and /v1/accounts/me returned 200 with the key on the free plan."
  },
  "first_action": {
   "status": "headless",
   "note": "POST /v1/emails created a draft, which was read back with GET."
  },
  "pay": {
   "status": "browser",
   "grade": "P2",
   "rails": [],
   "first_party": false,
   "rail_scope": "none",
   "trial_path": "free tier",
   "note": "No x402, MPP or L402 rail: the x402., mpp. and agents. subdomains do not resolve, the well-known files return 404, there are no Bazaar or mpp.dev listings, and the OpenAPI has no billing endpoints. Upgrading happens in the dashboard (/settings/billing): a plan picker with an embedded Stripe card field ('Upgrade for $9/mo'), and an hCaptcha script was detected on that page (not visible). Nothing was paid, so whether an agent could finish checkout alone with a card is not proven. There is a free plan; there is no card-free trial of paid plans (they offer a 30-day money-back guarantee instead)."
  },
  "cancel": {
   "status": "n/a",
   "grade": "n/a",
   "note": "Nothing to cancel: our agent used the free plan.",
   "docs_note": "No paid plan was started. No billing API exists, so cancelling would go through the dashboard billing page (not exercised).",
   "nothing": "free_plan"
  },
  "delete": {
   "status": "browser",
   "note": "Settings > Danger Zone > Delete your account (type a random phrase). Afterwards the API returns 401 and the archive returns 404. There is no documented API to delete the account. The first browser try did not take; an identical second try worked.",
   "left": "deleted",
   "account": true
  }
 },
 "routes": [],
 "checkout": null,
 "docs": null,
 "claims": null,
 "pay_options": {
  "checked": "2026-10-02",
  "source": "drive",
  "options": [],
  "agentic": [],
  "paid": null,
  "exercised": null,
  "detected_grade": null,
  "trial": {
   "no_card": null,
   "card_required": null,
   "free_plan": true
  },
  "owner_fixes": [
   {
    "title": "Accept x402 or MPP on your API",
    "how": "Answer an unpaid call with 402 and a payment challenge, so an agent pays per call or buys credits without an account or a card."
   },
   {
    "title": "List your plans on Stripe Projects",
    "how": "Agents buy a plan with `stripe projects add`, paid with a token under a spend cap the owner sets (projects.dev)."
   }
  ]
 },
 "surfaces": {
  "api": true,
  "openapi": true,
  "cli": true,
  "sdk": false,
  "mcp": "none",
  "llms_txt": true,
  "webhooks": true,
  "sandbox": true
 },
 "surface_notes": {
  "api": "REST, token auth, 133 operations across 77 paths; available on the free plan",
  "openapi": "Complete and mostly accurate. GET /advertising_units/slots returns 405 although it is documented, and the per-type bulk-action metadata is not in the schema",
  "cli": "@buttondown/cli (npm): login/pull/push/create, sync-only, --json output",
  "mcp": "none found (no MCP on the site or in the docs; our web search was unavailable)",
  "sandbox": "test_mode on the newsletter (all sends go to the owner) plus firewall sandbox addresses (+firewall-N@sandbox.buttondown.com)"
 },
 "can_do": [
  "Write, edit, schedule and delete email drafts through the API",
  "Send a broadcast to subscribers through the API, with per-subscriber templating ({{ subscriber.metadata.* }})",
  "Add, update, delete and import subscribers (CSV import via /v1/imports)",
  "Read per-email analytics (recipients, deliveries, opens, clicks)",
  "Publish to the public web archive automatically on send, and read it via /v1/public/emails",
  "Register webhooks and inspect their delivery attempts",
  "Export subscribers and emails as a downloadable zip",
  "Run bulk actions and poll their status",
  "Create surveys and record responses; post comments on sent emails",
  "Invite a collaborator with scoped permissions via /v1/users",
  "Create sponsorship ad units",
  "Sync drafts from a local folder with the official CLI"
 ],
 "cannot_do": [
  {
   "what": "Sign up or get the first API key headless",
   "why": "No documented sign-up or key API; both happen in the dashboard (the browser works without a CAPTCHA)"
  },
  {
   "what": "Activate automations, RSS-to-email, tags, attachments, custom domain, or a second newsletter",
   "why": "Paid plans; the API returns a 403 that names the required plan"
  },
  {
   "what": "Buy a plan without a human-held card",
   "why": "No machine-payment rail or billing API; only a Stripe card form in the dashboard"
  },
  {
   "what": "Delete the account headless",
   "why": "Only via Settings > Danger Zone in the dashboard"
  },
  {
   "what": "Show a sold sponsorship slot",
   "why": "A sponsor has to pay through Stripe; the slots list endpoint returns 405"
  }
 ],
 "blockers": [
  "Sign-up and the first API key happen in the dashboard (browser), not over an API",
  "Most automation features (automations, RSS, tags) need a paid plan bought with a card"
 ],
 "tips_for_owner": [
  "Offer an API for sign-up and first key",
  "Add a billing API or agent payment rail",
  "Align llms.txt pricing with live plans",
  "Fix GET /advertising_units/slots 405",
  "Document bulk-action metadata per type",
  "Add an account-deletion API endpoint"
 ],
 "tips_for_agents": [
  "Get the primary API key at buttondown.com/keys after signing up in a browser; after that everything is REST with 'Authorization: Token <key>'.",
  "The first send with status about_to_send needs the header 'X-Buttondown-Live-Dangerously: true' (once per key); the 400 error tells you so.",
  "New newsletters have an aggressive subscriber firewall: API-created subscribers from a datacenter IP get 400 subscriber_blocked. Pass the real subscriber's ip_address, or 'X-Buttondown-Bypass-Firewall: true' for addresses you own.",
  "Subscribers created through the API are double opt-in (type unactivated) unless you send type 'regular'; CSV imports land as 'regular'.",
  "The API adds a fancy-editor marker to bodies without one; start the body with '<!-- buttondown-editor-mode: plaintext -->' to keep it as Markdown/plain text.",
  "Paid features return a 403 that names the required plan: create the object, then check whether activation is gated.",
  "Use test_mode on the newsletter to route sends to yourself while testing."
 ],
 "selfhost": null,
 "summary": "Buttondown is very agent-friendly once the key is in hand: a complete OpenAPI, clear errors that name the fix, and on the free plan we drafted, scheduled, sent, personalised, archived, exported, imported and bulk-edited through the API, all verified by reading back. Sign-up, the first API key and account deletion need the dashboard (no CAPTCHA, so a browser agent manages), and automations, RSS and tags are behind a card-only paid plan with no billing API.",
 "wall": "Sign-up and billing require the dashboard",
 "plan_scope": "free plan",
 "robots_stop": null,
 "robots": null,
 "plain": {
  "summary": "Buttondown is an email newsletter platform with a full API. An agent could sign up, confirm its email, draft and send a real newsletter, manage subscribers, and export its own data entirely on the free plan, reading back every result to confirm it worked. It stopped only at dashboard-only tasks (getting the first API key, upgrading to a paid plan, deleting the account) and at paid-only features like automations and custom domains, which require a human with a credit card.",
  "can_do": [
   "Write, schedule and send newsletter emails through the API, with personalized content per subscriber",
   "Add, update, remove and import subscribers, including bulk edits",
   "See delivery and open/click stats for a sent email",
   "Publish sent emails automatically to a public archive page",
   "Set up webhooks, surveys, reader comments and team invitations",
   "Export all subscriber and email data as a downloadable file",
   "Manage drafts from a command-line tool as well as the API"
  ],
  "cannot_do": [
   {
    "what": "Sign up and get the very first API key without a browser",
    "why": "Account creation and the first key only exist on the website, not as an API"
   },
   {
    "what": "Turn on automations, RSS-to-email, tags, attachments, extra newsletters or a custom domain",
    "why": "These require paying for a plan, which the free account did not have"
   },
   {
    "what": "Upgrade to a paid plan or cancel one without a human entering a card",
    "why": "No billing API exists; payment only happens through a card form in the dashboard"
   },
   {
    "what": "Delete the account through the API",
    "why": "Account deletion is a dashboard-only button, not an API endpoint"
   },
   {
    "what": "Fully test the sponsorship marketplace feature",
    "why": "Selling an ad slot needs a paying sponsor, which the test could not provide"
   }
  ]
 },
 "plan_gated": [
  {
   "capability": "Automated email sequences",
   "plan": "Standard",
   "evidence": "PATCH /v1/automations/{id} status=active -> 403 'Automation access requires the Standard plan'"
  },
  {
   "capability": "RSS-to-email",
   "plan": "Basic",
   "evidence": "PATCH /v1/external_feeds/{id} status=active -> 403 'RSS-to-email access requires the Basic plan'"
  },
  {
   "capability": "Paid subscription tiers",
   "plan": "Basic + Stripe connect",
   "evidence": "GET /v1/prices -> 400 paid_subscriptions_uninitialized; billing page lists paid subscriptions under Basic"
  },
  {
   "capability": "Tags",
   "plan": "Basic",
   "evidence": "POST /v1/tags -> 403 'Tags require a Basic plan or higher'"
  },
  {
   "capability": "Multiple newsletters",
   "plan": "paid",
   "evidence": "POST /v1/newsletters -> 403 'Please upgrade your account to create additional newsletters through the API.'"
  },
  {
   "capability": "Attachments",
   "plan": "Basic",
   "evidence": "POST /v1/attachments -> 403 feature_unavailable_on_plan"
  },
  {
   "capability": "Custom domain",
   "plan": "Standard",
   "evidence": "PATCH /v1/newsletters/{id} domain -> 403 'A custom domain requires the Standard plan'"
  },
  {
   "capability": "Remove branding",
   "plan": "paid",
   "evidence": "llms.txt pricing; billing page says 'Professional: adds whitelabeling'"
  }
 ],
 "reply": null,
 "capabilities": [
  {
   "id": "cap-01",
   "group": "Composing & sending",
   "capability": "Draft and write an email in Markdown or rich text",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "POST /v1/emails",
    "mcp": null,
    "cli": "buttondown emails create",
    "ui": "Dashboard → Emails → New"
   },
   "check": "GET /v1/emails/{id} shows status draft with the submitted body",
   "source": "https://buttondown.com/features/markdown; https://docs.buttondown.com/[redacted]"
  },
  {
   "id": "cap-02",
   "group": "Composing & sending",
   "capability": "Send a broadcast email to subscribers",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "POST /v1/emails (status: sent) or PATCH /v1/emails/{id}",
    "mcp": null,
    "cli": "buttondown emails send",
    "ui": "Dashboard → Emails → Send"
   },
   "check": "GET /v1/emails/{id} shows status sent and recipient count > 0",
   "source": "https://buttondown.com/features/api; https://docs.buttondown.com/[redacted]"
  },
  {
   "id": "cap-03",
   "group": "Composing & sending",
   "capability": "Schedule an email to send at a future time",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "POST/PATCH /v1/emails (status: scheduled, publish_date)",
    "mcp": null,
    "cli": "buttondown emails schedule",
    "ui": "Dashboard → Emails → Schedule"
   },
   "check": "GET /v1/emails/{id} shows status scheduled with the chosen publish_date",
   "source": "https://docs.buttondown.com/scheduling-emails-via-the-api"
  },
  {
   "id": "cap-04",
   "group": "Subscribers",
   "capability": "Add, update, and remove a subscriber",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "POST/PATCH/DELETE /v1/subscribers",
    "mcp": null,
    "cli": "buttondown subscribers",
    "ui": "Dashboard → Subscribers"
   },
   "check": "GET /v1/subscribers/{id} reflects the created/updated/absent subscriber",
   "source": "https://docs.buttondown.com/[redacted]"
  },
  {
   "id": "cap-05",
   "group": "Monetization",
   "capability": "Charge for the newsletter via paid subscription tiers",
   "weight": "core",
   "plan": "paid",
   "surfaces": {
    "api": "/v1/subscribers (stripe fields), per docs",
    "mcp": null,
    "cli": null,
    "ui": "Dashboard → Monetize → Subscriptions"
   },
   "check": "GET /v1/subscribers/{id} shows subscriber_type paid with an active Stripe subscription",
   "source": "https://buttondown.com/features/paid-subscriptions; https://docs.buttondown.com/[redacted]"
  },
  {
   "id": "cap-06",
   "group": "Automation",
   "capability": "Build automated email sequences (welcome series, tag-triggered flows)",
   "weight": "core",
   "plan": "paid",
   "surfaces": {
    "api": "/v1/automations (per llms.txt)",
    "mcp": null,
    "cli": null,
    "ui": "Dashboard → Automations"
   },
   "check": "GET /v1/automations/{id} shows configured steps; a new matching subscriber triggers a queued send",
   "source": "https://buttondown.com/features/automation; https://docs.buttondown.com/[redacted]"
  },
  {
   "id": "cap-07",
   "group": "RSS",
   "capability": "Turn an RSS feed into automatic newsletter sends",
   "weight": "core",
   "plan": "paid",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Dashboard → RSS-to-email settings"
   },
   "check": "Newsletter archive shows a new email issue generated after the source RSS feed publishes a new post",
   "source": "https://buttondown.com/features/rss; https://docs.buttondown.com/rss-to-email"
  },
  {
   "id": "cap-08",
   "group": "Archives",
   "capability": "Publish sent emails to a public web archive",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "/v1/emails (archive visibility)",
    "mcp": null,
    "cli": null,
    "ui": "Hosted archive at {username}.buttondown.com/archive"
   },
   "check": "GET https://{username}.buttondown.com/archive lists the sent email with a working permalink",
   "source": "https://buttondown.com/features/archives"
  },
  {
   "id": "cap-09",
   "group": "Sponsorships",
   "capability": "Sell and manage sponsorship ad slots in the newsletter",
   "weight": "core",
   "plan": "paid",
   "surfaces": {
    "api": "/advertising_units (per openapi.json)",
    "mcp": null,
    "cli": null,
    "ui": "Dashboard → Sponsorships"
   },
   "check": "GET /advertising_units/{id} shows a purchased slot with submitted/approved content",
   "source": "https://buttondown.com/features/sponsorships; https://docs.buttondown.com/openapi.json"
  },
  {
   "id": "cap-10",
   "group": "Subscribers",
   "capability": "Organize subscribers with tags",
   "weight": "secondary",
   "plan": "paid",
   "surfaces": {
    "api": "/v1/tags",
    "mcp": null,
    "cli": null,
    "ui": "Dashboard → Subscribers → Tags"
   },
   "check": "GET /v1/subscribers/{id} includes the applied tag in its tags list",
   "source": "https://docs.buttondown.com/[redacted]; https://docs.buttondown.com/tags"
  },
  {
   "id": "cap-11",
   "group": "Automation",
   "capability": "Collect feedback via surveys",
   "weight": "secondary",
   "plan": "paid",
   "surfaces": {
    "api": "/v1/surveys (per llms.txt)",
    "mcp": null,
    "cli": null,
    "ui": "Dashboard → Surveys"
   },
   "check": "GET /v1/surveys/{id}/responses shows a submitted subscriber response",
   "source": "https://buttondown.com/features (Surveys section); https://docs.buttondown.com/[redacted]"
  },
  {
   "id": "cap-12",
   "group": "Engagement",
   "capability": "Let subscribers comment on sent emails",
   "weight": "secondary",
   "plan": "paid",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Email archive page comment thread"
   },
   "check": "Archive page for the email shows the posted comment",
   "source": "https://buttondown.com/features (Comments section)"
  },
  {
   "id": "cap-13",
   "group": "Analytics",
   "capability": "View opens, clicks, referrers, and per-email analytics",
   "weight": "secondary",
   "plan": "paid",
   "surfaces": {
    "api": "docs.buttondown.com/retrieving-analytics-data",
    "mcp": null,
    "cli": "buttondown analytics",
    "ui": "Dashboard → Analytics"
   },
   "check": "Analytics dashboard / API shows nonzero open and click counts for a sent email",
   "source": "https://buttondown.com/features/analytics"
  },
  {
   "id": "cap-14",
   "group": "Automation",
   "capability": "Receive webhooks for newsletter events",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "/v1/webhooks",
    "mcp": null,
    "cli": null,
    "ui": "Dashboard → Webhooks settings"
   },
   "check": "GET /v1/webhooks/{id} shows registration; a triggering event (e.g. new subscriber) posts a payload to the configured URL",
   "source": "https://docs.buttondown.com/[redacted]; https://docs.buttondown.com/events-and-webhooks-introduction"
  },
  {
   "id": "cap-15",
   "group": "Subscribers",
   "capability": "Export subscriber/email data",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "/v1/exports",
    "mcp": null,
    "cli": "buttondown export",
    "ui": "Dashboard → Subscribers → Export"
   },
   "check": "GET /v1/exports/{id} resolves to a downloadable file containing the account's data",
   "source": "https://docs.buttondown.com/[redacted]"
  },
  {
   "id": "cap-16",
   "group": "Subscribers",
   "capability": "Perform bulk actions on many subscribers/emails at once",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "/v1/bulk_actions (per llms.txt)",
    "mcp": null,
    "cli": null,
    "ui": "Dashboard → Subscribers → bulk select"
   },
   "check": "GET /v1/bulk_actions/{id} shows completed status with the number of records affected",
   "source": "https://docs.buttondown.com/[redacted]"
  },
  {
   "id": "cap-17",
   "group": "Newsletters",
   "capability": "Run multiple distinct newsletters under one account",
   "weight": "secondary",
   "plan": "paid",
   "surfaces": {
    "api": "/v1/newsletters (per llms.txt)",
    "mcp": null,
    "cli": null,
    "ui": "Dashboard → Newsletter switcher"
   },
   "check": "GET /v1/newsletters lists more than one newsletter object owned by the account",
   "source": "https://buttondown.com/features/multiple-newsletters; https://docs.buttondown.com/[redacted]"
  },
  {
   "id": "cap-18",
   "group": "Composing & sending",
   "capability": "Attach files to an email",
   "weight": "secondary",
   "plan": "paid",
   "surfaces": {
    "api": "/v1/emails (attachments)",
    "mcp": null,
    "cli": null,
    "ui": "Email editor → Attach"
   },
   "check": "GET /v1/emails/{id} includes the uploaded attachment in its payload",
   "source": "https://buttondown.com/features/attachments; https://buttondown.com/features"
  },
  {
   "id": "cap-19",
   "group": "Composing & sending",
   "capability": "Compose/save a draft by sending an email from your own inbox",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Send to post@buttondown.email / draft@buttondown.email"
   },
   "check": "A new draft/sent email appears in the dashboard matching the inbound email's content",
   "source": "https://buttondown.com/features (Send from your own email section)"
  },
  {
   "id": "cap-20",
   "group": "Composing & sending",
   "capability": "Personalize emails with subscriber data via templating",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "/v1/emails (body with template variables)",
    "mcp": null,
    "cli": null,
    "ui": "Email editor"
   },
   "check": "Sent email HTML shows the template variable replaced with the specific subscriber's data",
   "source": "https://docs.buttondown.com/templating; https://docs.buttondown.com/template-variables"
  },
  {
   "id": "cap-21",
   "group": "CLI",
   "capability": "Draft, schedule, and manage the newsletter from a terminal CLI",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": "buttondown (full command set)",
    "ui": null
   },
   "check": "Running the CLI create/send command results in the email appearing via GET /v1/emails",
   "source": "https://buttondown.com/features/cli; https://docs.buttondown.com/buttondown-cli"
  },
  {
   "id": "cap-22",
   "group": "Migration",
   "capability": "Import subscriber/content data from another provider",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Dashboard → Import"
   },
   "check": "Subscriber count in dashboard/API increases to match the imported source list",
   "source": "https://docs.buttondown.com/importing-your-data; https://docs.buttondown.com/substack"
  },
  {
   "id": "cap-23",
   "group": "Migration",
   "capability": "Request a concierge (done-for-you) migration of an entire list",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Contact form on /features/concierge-migration"
   },
   "check": "Dashboard subscriber list matches the source platform's list after Buttondown completes the migration",
   "source": "https://buttondown.com/features/concierge-migration"
  },
  {
   "id": "cap-24",
   "group": "Teams",
   "capability": "Invite collaborators and assign roles/permissions",
   "weight": "peripheral",
   "plan": "paid",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Dashboard → Settings → Team"
   },
   "check": "Team members list shows the invited collaborator with the assigned role",
   "source": "https://buttondown.com/features/teams"
  },
  {
   "id": "cap-25",
   "group": "Branding",
   "capability": "Send and host the newsletter on a custom domain",
   "weight": "peripheral",
   "plan": "paid",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Dashboard → Settings → Domain"
   },
   "check": "Newsletter archive and outbound emails resolve under the configured custom domain",
   "source": "https://docs.buttondown.com/sending-from-a-custom-domain; https://docs.buttondown.com/hosting-on-a-custom-domain"
  },
  {
   "id": "cap-26",
   "group": "Branding",
   "capability": "Remove Buttondown branding and whitelabel the newsletter's look",
   "weight": "peripheral",
   "plan": "paid",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Dashboard → Settings → Branding"
   },
   "check": "Sent/confirmation emails and archive pages show no Buttondown branding after toggling the setting",
   "source": "https://buttondown.com/features/whitelabeling"
  },
  {
   "id": "cap-27",
   "group": "Integrations",
   "capability": "Connect third-party tools (Discord, Stripe, WordPress, Webflow, Framer, Zapier, etc.)",
   "weight": "peripheral",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Dashboard → Integrations"
   },
   "check": "Integration page shows the connection as active and triggers the documented side effect (e.g. Discord post on send)",
   "source": "https://buttondown.com/features/integrations; https://buttondown.com/features/integrations/discord"
  },
  {
   "id": "cap-28",
   "group": "API access",
   "capability": "Generate and manage API keys",
   "weight": "peripheral",
   "plan": "free",
   "surfaces": {
    "api": "GET /accounts/me; key mgmt via dashboard",
    "mcp": null,
    "cli": null,
    "ui": "Dashboard → Settings → API"
   },
   "check": "New key authenticates a GET /accounts/me call successfully",
   "source": "https://buttondown.com/features/api; https://buttondown.com/settings#api"
  },
  {
   "id": "cap-29",
   "group": "Privacy",
   "capability": "Toggle subscriber tracking/analytics collection on or off",
   "weight": "peripheral",
   "plan": "paid",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Dashboard → Settings → Analytics"
   },
   "check": "After disabling, analytics dashboard stops recording new open/click events",
   "source": "https://buttondown.com/features/analytics; https://buttondown.com/features/privacy"
  },
  {
   "id": "cap-30",
   "group": "Account",
   "capability": "Pause billing while keeping archives online",
   "weight": "peripheral",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Dashboard → Settings → Billing"
   },
   "check": "Archive URLs remain reachable while the account shows paused billing status",
   "source": "https://docs.buttondown.com/paused-billing"
  }
 ],
 "attempts": [
  {
   "t": "03:19",
   "cap": "docs",
   "capability": "Find docs",
   "task": "Find API docs, OpenAPI, llms.txt",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "llms.txt on buttondown.com and docs.buttondown.com (200 text/plain); docs.buttondown.com/openapi.json 200 application/json, 77 paths; unauthenticated GET api.buttondown.com/v1/emails -> 401 {\"code\":\"authentication_missing\",\"detail\":\"...Authorization: Token <your-api-key>\",\"documentation_url\":...}",
   "notes": "",
   "quality": {
    "error_legibility": "clear",
    "docs_match": "match"
   }
  },
  {
   "t": "03:19",
   "cap": "signup",
   "capability": "Sign up",
   "task": "Create account",
   "route": "browser",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "https://buttondown.com/register: JS form (username/email/password), no CAPTCHA signals; submitted in pw browser, landed on /home onboarding wizard. No documented signup API (no account-creation path in OpenAPI).",
   "notes": "Onboarding questions (display name, previous platform, persona, referral source) answered truthfully in browser."
  },
  {
   "t": "03:19",
   "cap": "verify",
   "capability": "Verify email",
   "task": "Confirm account email",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "Mail \"Confirm your new Buttondown account\" arrived <1 min.",
   "notes": "Link click, works headless."
  },
  {
   "t": "03:19",
   "cap": "credentials",
   "capability": "Get API key",
   "task": "Get API key",
   "route": "browser",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "Primary API key auto-created at signup, shown at https://buttondown.com/keys/<id> in dashboard (browser). No documented API to mint the first key.",
   "notes": ""
  },
  {
   "t": "03:19",
   "cap": "first_call",
   "capability": "First API call",
   "task": "GET /v1/ping and /v1/accounts/me",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "GET /v1/ping 200 {}; /v1/accounts/me 200 {\"username\":\"agentdrivestest037\",...}; /v1/newsletters 200 one newsletter news_19yh...",
   "notes": "API works on free plan despite llms.txt listing \"API access\" under Basic ($9/mo).",
   "quality": {
    "verify_route": "yes",
    "docs_match": "drift"
   }
  },
  {
   "t": "03:32",
   "cap": "cap-01",
   "capability": "Draft and write an email in Markdown or rich text",
   "task": "Create a Markdown draft, edit subject, read it back",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /v1/emails status=draft -> 201 em_3tdzrnyy789t4840xb4yxvk3b7; PATCH subject -> 200; GET -> status draft, subject edited, body kept",
   "notes": "API silently prefixed the body with \"<!-- buttondown-editor-mode: fancy -->\" (rich-text mode) although body was Markdown; agents wanting Markdown mode must add the \"<!-- buttondown-editor-mode: plaintext -->\" marker themselves (marker name inferred from the prefix, not tested).",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match",
    "idempotent": "n/a"
   }
  },
  {
   "t": "03:32",
   "cap": "first_action",
   "capability": "First real action",
   "task": "Create a draft email",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /v1/emails -> 201 em_3tdzrnyy789t4840xb4yxvk3b7, read back by GET",
   "notes": ""
  },
  {
   "t": "04:15",
   "cap": "cap-04",
   "capability": "Add, update, and remove a subscriber",
   "task": "Add subscriber, update notes/metadata, delete another, read back",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /v1/subscribers an inbox -> 201 sub_6xk3m4z3hv8j3sawjkp5c1nf91 (type unactivated, double opt-in); PATCH notes+metadata -> 200, GET by email shows update; second POST an inbox -> 400 subscriber_blocked \"blocked by your firewall\"; retried with documented X-Buttondown-Bypass-Firewall: true + type regular -> 201; DELETE -> 204; GET -> 404; list count 1",
   "notes": "Firewall (aggressive by default on this new newsletter) blocks API-created subscribers coming from our single datacenter IP; documented fix is passing ip_address or the bypass header.",
   "quality": {
    "verify_route": "yes",
    "error_legibility": "clear",
    "docs_match": "match",
    "recoverable": "yes"
   }
  },
  {
   "t": "04:42",
   "cap": "cap-03",
   "capability": "Schedule an email to send at a future time",
   "task": "Schedule an email for +7 days and read it back",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /v1/emails status=scheduled publish_date=2026-10-09T21:50:03Z -> 201 em_7b4tfqtv3t8x1amhg5q7f35nhj; GET -> status scheduled, publish_date 2026-10-09T21:50:03Z",
   "notes": "Scheduling did not require the X-Buttondown-Live-Dangerously header (only about_to_send did). Deleted before send at cleanup.",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "05:21",
   "cap": "cap-02",
   "capability": "Send a broadcast email to subscribers",
   "task": "Send an email to our one confirmed test subscriber",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /v1/emails status=about_to_send -> 400 sending_requires_confirmation (\"requires the X-Buttondown-Live-Dangerously header... only required once per API key\"); retried with header -> 201 em_4ssxys7hyd8qh87d4mxz6sdxxm; GET -> status sent; /analytics recipients 1 deliveries 1; mail arrived in an inbox inbox 1s later",
   "notes": "Only recipient is inbox the agent's inbox (confirmed via the opt-in link).",
   "quality": {
    "verify_route": "yes",
    "error_legibility": "clear",
    "docs_match": "match",
    "recoverable": "yes"
   }
  },
  {
   "t": "05:21",
   "cap": "cap-20",
   "capability": "Personalize emails with subscriber data via templating",
   "task": "Send with {{ subscriber.metadata.first_name }} and {{ subscriber.email }}",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "Received mail body: \"Hi Ada, ... (the agent's inbox)\"both variables replaced from the subscriber record",
   "notes": "",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "05:21",
   "cap": "cap-08",
   "capability": "Publish sent emails to a public web archive",
   "task": "Check the sent email shows in the public archive",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "GET https://buttondown.com/agentdrivestest037/archive/ 200 lists \"AgentDrives broadcast test\" (draft not listed); permalink /archive/agentdrives-broadcast-test/ 200 with body; documented GET /v1/public/emails/agentdrivestest037 returns it",
   "notes": "Free-plan archive at buttondown.com/<username>, not <username>.buttondown.com as the map says.",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "05:21",
   "cap": "cap-13",
   "capability": "View opens, clicks, referrers, and per-email analytics",
   "task": "Read per-email analytics for the sent email",
   "route": "api",
   "documented": true,
   "result": "partial",
   "verified": true,
   "evidence": "GET /v1/emails/{id}/analytics 200 {\"recipients\":1,\"deliveries\":1,\"opens\":0,\"clicks\":0,...}",
   "notes": "Endpoint works on the free plan; opens/clicks are 0 because the agent's inbox does not load tracking pixels and we did not fake engagement, so the \"nonzero opens\" check could not be shown.",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "05:47",
   "cap": "cap-06",
   "capability": "Build automated email sequences",
   "task": "Create a welcome automation on subscriber.confirmed and activate it",
   "route": "api",
   "documented": true,
   "result": "plan_gated",
   "verified": true,
   "evidence": "POST /v1/automations -> 201 aut_72mtd3714v9nt9hcvzqam0zjhd status inactive (creation allowed on free); PATCH status=active -> 403 {\"code\":\"forbidden\",\"detail\":\"Automation access requires the Standard plan - please upgrade your account.\",\"metadata\":{\"feature\":\"automations\",\"required_plan\":\"standard\"}}",
   "notes": "Plan name in error (\"Standard\") differs from llms.txt pricing names (Basic/Professional).",
   "quality": {
    "error_legibility": "clear",
    "recoverable": "no"
   }
  },
  {
   "t": "06:04",
   "cap": "cap-07",
   "capability": "Turn an RSS feed into automatic newsletter sends",
   "task": "Create an RSS-to-email feed (draft behaviour) and activate it",
   "route": "api",
   "documented": true,
   "result": "plan_gated",
   "verified": true,
   "evidence": "POST /v1/external_feeds -> 201 rss_67298x8cqr94hv4y8hg1wsmcbe status inactive; PATCH status=active -> 403 \"RSS-to-email access requires the Basic plan - please upgrade your account.\" (feature rss_automation, required_plan basic)",
   "notes": "First POST without cadence/filters/subject/body -> 422 listing each missing field (clear). Map listed no API route; there is a documented one (/v1/external_feeds).",
   "quality": {
    "error_legibility": "clear",
    "recoverable": "no"
   }
  },
  {
   "t": "06:09",
   "cap": "cap-10",
   "capability": "Organize subscribers with tags",
   "task": "Create a tag",
   "route": "api",
   "documented": true,
   "result": "plan_gated",
   "verified": true,
   "evidence": "POST /v1/tags -> 403 {\"code\":\"feature_disabled\",\"detail\":\"Tags require a Basic plan or higher - please upgrade your account.\"}",
   "notes": "",
   "quality": {
    "error_legibility": "clear"
   }
  },
  {
   "t": "06:26",
   "cap": "cap-09",
   "capability": "Sell and manage sponsorship ad slots",
   "task": "Create a sponsorship ad unit, read it back, list slots",
   "route": "api",
   "documented": true,
   "result": "partial",
   "verified": true,
   "evidence": "POST /v1/advertising_units -> 201 adsku_22bb4dry8493k8n9bjc0mrksmx status active; GET /v1/advertising_units lists it; GET /v1/advertising_units/slots -> 405 \"Method not allowed\" although OpenAPI documents GET",
   "notes": "Selling a slot needs a sponsor to pay through Stripe; we cannot pay, so a purchased slot (the map check) could not be produced. The slots list endpoint drifts from the OpenAPI.",
   "quality": {
    "verify_route": "yes",
    "error_legibility": "vague",
    "docs_match": "drift",
    "recoverable": "no"
   }
  },
  {
   "t": "06:26",
   "cap": "cap-05",
   "capability": "Charge for the newsletter via paid subscription tiers",
   "task": "List prices / set up paid tier via API",
   "route": "api",
   "documented": true,
   "result": "plan_gated",
   "verified": true,
   "evidence": "GET /v1/prices -> 400 {\"code\":\"paid_subscriptions_uninitialized\",\"detail\":\"Paid subscriptions have not been initialized for this newsletter; Buttondown has no Stripe product for which to list prices.\"}",
   "notes": "Requires connecting a Stripe account (OAuth in dashboard) and, per llms.txt, a paid plan; we have no Stripe account and cannot pay. Not attempted further.",
   "quality": {
    "error_legibility": "clear",
    "recoverable": "no"
   }
  },
  {
   "t": "07:04",
   "cap": "cap-14",
   "capability": "Receive webhooks for newsletter events",
   "task": "Register a subscriber.created webhook, trigger it, read delivery attempts",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /v1/webhooks -> 201 hook_2573g7d78f9qhva26t9g6magne; POST /webhooks/{id}/test -> 204 (not listed in attempts); creating subscriber an inbox -> GET /webhooks/{id}/attempts shows event subscriber.created, attempt_count 1, status failed \"Webhook returned 405\" from example.com",
   "notes": "Pointed at reserved example.com (we have no public receiver), so delivery failure is expected; the attempt log proves the event fired. signing_key came back empty.",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "07:49",
   "cap": "cap-15",
   "capability": "Export subscriber/email data",
   "task": "Export subscribers+emails and download the file",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /v1/exports -> 201 exp_3xvqvt79ar98dvbs37njrsnn6z; GET after 1s -> status ready with url; downloaded zip (2116 bytes) contains subscribers.csv (both test subscribers), emails.csv and 3 email .md files",
   "notes": "",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "07:49",
   "cap": "cap-16",
   "capability": "Perform bulk actions",
   "task": "Bulk-add a note to 2 subscribers",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /v1/bulk_actions add_notes with metadata.notes -> 400 bulk_action_invalid_metadata \"You must provide a non-empty body field.\"; retried with metadata.body -> 201; GET /bulk_actions/{id} -> processed after ~4s; GET /v1/notes shows 2 notes on both subscriber ids",
   "notes": "Per-type metadata shape is not in the OpenAPI schema (only \"typically an ids list\"); error named the field so recovery was immediate.",
   "quality": {
    "verify_route": "yes",
    "error_legibility": "clear",
    "docs_match": "drift",
    "recoverable": "yes"
   }
  },
  {
   "t": "08:21",
   "cap": "cap-11",
   "capability": "Collect feedback via surveys",
   "task": "Create a survey and record a response for our test subscriber",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /v1/surveys -> 201 srv_2ajtz24v4v80ha0pkws9pqtk9p status active (free plan); POST /v1/survey_responses: 422 each time naming the missing/invalid field (email_id required, answer must be an integer >= 1, i.e. 1-based index); then 201; GET /v1/survey_responses?survey_id= lists answer \"yes\"",
   "notes": "Response recorded via the owner API, not by the subscriber clicking in the mail.",
   "quality": {
    "verify_route": "yes",
    "error_legibility": "clear",
    "docs_match": "match",
    "recoverable": "yes"
   }
  },
  {
   "t": "08:21",
   "cap": "cap-17",
   "capability": "Run multiple distinct newsletters",
   "task": "Create a second newsletter",
   "route": "api",
   "documented": true,
   "result": "plan_gated",
   "verified": true,
   "evidence": "POST /v1/newsletters -> 403 \"Please upgrade your account to create additional newsletters through the API.\"",
   "notes": "",
   "quality": {
    "error_legibility": "clear"
   }
  },
  {
   "t": "08:26",
   "cap": "cap-18",
   "capability": "Attach files to an email",
   "task": "Upload an attachment",
   "route": "api",
   "documented": true,
   "result": "plan_gated",
   "verified": true,
   "evidence": "POST /v1/attachments (multipart) -> 403 {\"code\":\"feature_unavailable_on_plan\",\"detail\":\"Attachments aren't included on your current plan. Upgrade your account to upload attachments.\"}",
   "notes": "",
   "quality": {
    "error_legibility": "clear"
   }
  },
  {
   "t": "08:43",
   "cap": "cap-12",
   "capability": "Let subscribers comment on sent emails",
   "task": "Post a comment on the sent email as our test subscriber and see it on the archive page",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /v1/comments -> 201 com_5bvrh6pddv8vs90p64c5wk9ahd status active; GET /v1/comments/{id} 200; public archive page of the email contains the comment text",
   "notes": "Worked on the free plan (map says paid). Comment created via owner API on behalf of our own subscriber; deleted at cleanup.",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "09:01",
   "cap": "cap-22",
   "capability": "Import subscriber/content data from another provider",
   "task": "Import a CSV with one subscriber address we own",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /v1/imports (multipart CSV) -> 201 sub_imp_1c5w82p3d38258kccyqncn5rpg; GET /v1/imports/{id} -> succeeded, new_subscribers 1; GET /v1/subscribers lists the agent's inbox type regular",
   "notes": "Documented API route exists (map listed UI only). Imported subscriber became \"regular\" with no opt-in mail; provider-specific imports (Substack etc.) not tested.",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "10:11",
   "cap": "cap-21",
   "capability": "Draft, schedule, and manage the newsletter from a terminal CLI",
   "task": "Install @buttondown/cli, login, pull, create a draft, push it",
   "route": "cli",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "npm --prefix ./cli install @buttondown/cli; buttondown login --api-key --json -> logged_in; pull -> 3 emails + 1 automation pulled; create --title -> local .md; push --json -> emails created 1; GET /v1/emails?status=draft lists \"AgentDrives CLI draft\" with the appended body",
   "notes": "CLI is a sync tool (login/pull/push/create) with --json output; no dedicated send/schedule/analytics/export commands despite the map wording; status lives in front-matter. HOME pointed into the run dir so credentials stayed local.",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "10:11",
   "cap": "cap-28",
   "capability": "Generate and manage API keys",
   "task": "Create a second labelled API key and use it",
   "route": "browser",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "Dashboard /keys/new (browser): label agentdrives-second, per-scope permissions; Create -> key shown; GET /v1/accounts/me with the new key -> 200",
   "notes": "No documented API to create/rotate/delete keys; dashboard only.",
   "quality": {
    "verify_route": "yes"
   }
  },
  {
   "t": "10:11",
   "cap": "cap-19",
   "capability": "Compose/save a draft by sending an email from your own inbox",
   "task": "Mail a draft to Buttondown from our inbox",
   "route": "none",
   "documented": true,
   "result": "skipped",
   "verified": false,
   "evidence": "The agent's inbox tool can only receive mail; we have no way to send an email from the account address.",
   "notes": "Not a finding about Buttondown."
  },
  {
   "t": "10:42",
   "cap": "cap-29",
   "capability": "Toggle subscriber tracking on or off",
   "task": "Turn tracking on then off via the newsletter settings",
   "route": "api",
   "documented": true,
   "result": "partial",
   "verified": true,
   "evidence": "GET /v1/newsletters/{id} enabled_features had no \"tracking\" on a new free newsletter; PATCH enabled_features +tracking -> 200, GET shows it; PATCH back without tracking -> 200, gone",
   "notes": "Setting flips and reads back on the free plan, but we did not observe its effect on recorded opens/clicks (the map check).",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "10:42",
   "cap": "cap-25",
   "capability": "Send and host the newsletter on a custom domain",
   "task": "Set a custom hosting domain",
   "route": "api",
   "documented": true,
   "result": "plan_gated",
   "verified": true,
   "evidence": "PATCH /v1/newsletters/{id} {\"domain\":...} -> 403 \"A custom domain requires the Standard plan - please upgrade your account.\" (feature custom_domain, required_plan standard)",
   "notes": "",
   "quality": {
    "error_legibility": "clear"
   }
  },
  {
   "t": "11:03",
   "cap": "cap-24",
   "capability": "Invite collaborators and assign roles/permissions",
   "task": "Invite our own second address with email:read",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /v1/users -> 422 \"permissions Field required\"; with permissions {email: read} -> 201 inv_1qx4jdv2bw9se8h7xa0237r73c pending; GET /v1/users lists it with email read; invitation mail arrived at an inbox",
   "notes": "Worked on free plan (map says paid). Invitation not accepted (would need a second Buttondown account).",
   "quality": {
    "verify_route": "yes",
    "error_legibility": "clear",
    "docs_match": "match",
    "recoverable": "yes"
   }
  },
  {
   "t": "11:03",
   "cap": "cap-26",
   "capability": "Remove Buttondown branding",
   "task": "Remove \"Powered by Buttondown\" footer",
   "route": "none",
   "documented": true,
   "result": "plan_gated",
   "verified": false,
   "evidence": "buttondown.com/llms.txt pricing: \"Basic ($9/month): Custom domains, API access, automations, remove Buttondown branding\"; our sent mail carried \"Powered by Buttondown\". No documented API field for branding found in NewsletterUpdateInput.",
   "notes": ""
  },
  {
   "t": "11:03",
   "cap": "cap-27",
   "capability": "Connect third-party tools",
   "task": "Connect Discord/Stripe/Zapier integration",
   "route": "none",
   "documented": true,
   "result": "skipped",
   "verified": false,
   "evidence": "Integrations connect via OAuth to third-party accounts we do not have (Discord server, Stripe, Zapier); not attempted.",
   "notes": ""
  },
  {
   "t": "11:03",
   "cap": "cap-30",
   "capability": "Pause billing while keeping archives online",
   "task": "Pause billing",
   "route": "none",
   "documented": true,
   "result": "skipped",
   "verified": false,
   "evidence": "Account is on the free plan with no billing to pause; not applicable to our scope.",
   "notes": ""
  },
  {
   "t": "11:51",
   "cap": "pay",
   "capability": "Pay step",
   "task": "Find how an agent could buy a plan",
   "route": "browser",
   "documented": true,
   "result": "partial",
   "verified": true,
   "evidence": "No 402/x402/MPP/L402: x402./mpp./agents.buttondown.com do not resolve (curl 000); /.well-known/oauth-protected-resource, /auth.md, /SKILL.md, /.well-known/ucp 404 text/html; no Buttondown entries in x402 Bazaar or mpp.dev/api/services; OpenAPI has no billing/upgrade endpoint. Dashboard /settings/billing -> \"Upgrade your newsletter today\" opens in-page plan picker (Basic $9, Standard $29, Professional $79, Advanced $139) with a Stripe card field and \"Upgrade for $9/mo\"; hCaptcha script detected on that page (not visible). Not paid.",
   "notes": "Free plan with no card; no card-free trial of paid plans (30-day money-back instead). Plan names/prices on live billing page differ from llms.txt (Basic $9 / Professional $29).",
   "quality": {
    "docs_match": "drift"
   }
  },
  {
   "t": "13:51",
   "cap": "cleanup",
   "capability": "Delete created objects",
   "task": "Delete every object created during the drive via API",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "DELETE 204 then GET 404 for 4 emails, comment, automation, RSS feed, survey, webhook, invite; ad unit and 3 subscribers DELETE 204 with list count 0",
   "notes": "",
   "quality": {
    "verify_route": "yes"
   }
  },
  {
   "t": "13:51",
   "cap": "cancel",
   "capability": "Cancel plan",
   "task": "Cancel paid plan",
   "route": "none",
   "documented": true,
   "result": "skipped",
   "verified": false,
   "evidence": "No paid plan was started (free plan only), so nothing to cancel. No billing API exists in the OpenAPI; billing is in the dashboard (/settings/billing).",
   "notes": ""
  },
  {
   "t": "13:51",
   "cap": "delete",
   "capability": "Delete account",
   "task": "Delete the account and its data",
   "route": "browser",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "Dashboard Settings > Danger Zone > Delete your account: type a random 3-word phrase, click Delete account -> redirected to buttondown.com/. First browser call returned no page output and the account remained (GET /v1/accounts/me still 200); second identical try succeeded. Afterwards GET /v1/accounts/me -> 401 authentication_invalid and https://buttondown.com/agentdrivestest037/archive/ -> 404.",
   "notes": "No documented API to delete the account (DELETE /v1/newsletters/{id} exists for single newsletters).",
   "quality": {
    "verify_route": "yes"
   }
  }
 ],
 "stale": false,
 "icon": "/logos/buttondown.png",
 "monitored": false,
 "verdict": "Runs on its own: our agent got in on its own through a plain sign-up form, no CAPTCHA, confirmed by mail, and reached the dashboard to get a key with no documented key API. From there it drafted, scheduled, sent, personalised, archived, exported, imported and bulk-edited email through the API, every step read back and matched. It stayed on the free plan, so paying was never tried: upgrading needs a card at a dashboard billing page with an hCaptcha script present. Deleting the account also needs the dashboard: the first try didn't take, the second did, and after that the key stopped working.",
 "page": "https://agentdrives.com/tools/buttondown?via=api"
}