Built for the agents that build websites.
Everything a human can do in the dashboard, an agent can do with an API key. The exit test for this property: a coding agent in a fresh site repo, given only a key, ships a working contact form with email and Telegram in one conversation.
Four calls from nothing to verified.
-
1 Discover
Read GET /llms.txt (Markdown, written for agents) or GET /openapi.json (the full contract, generated from the live routes). Then GET /v1/me: organization, scopes, plan limits and counts of what already exists.
curl https://postbag.dev/llms.txt curl https://postbag.dev/v1/me -H "Authorization: Bearer pb_live_…"curl https://postbag.dev/llms.txt curl https://postbag.dev/v1/me -H "Authorization: Bearer pb_live_…"
-
2 Create
POST /v1/quickstart creates the project if missing, the form, an email destination and a direct route, idempotently by (project, name). It returns the submit URL, embed snippets for HTML, fetch, React, Astro and Next.js, a verification recipe, and next[] calls.
curl -X POST https://postbag.dev/v1/quickstart -H "Authorization: Bearer pb_live_…" -d '{ "name": "Portfolio contact", "notify_email": "[email protected]", "origin": "https://example.com", "project": "portfolio" }'curl -X POST https://postbag.dev/v1/quickstart -H "Authorization: Bearer pb_live_…" -d '{ "name": "Portfolio contact", "notify_email": "[email protected]", "origin": "https://example.com", "project": "portfolio" }' -
3 Verify
Post a test submission. The response carries the submission id and delivery ids; poll a delivery until it is sent. No inbox to check, no human in the loop.
curl -X POST https://postbag.dev/s/fm_8f3kq2 -H "content-type: application/json" \ -d '{"email":"[email protected]","message":"test","_test":true}' # → { "ok": true, "submission_id": "sb_4d2k91", "status": "received", "deliveries": ["dl_a91x02"] } curl https://postbag.dev/v1/deliveries/dl_a91x02 -H "Authorization: Bearer pb_live_…" # → { "status": "sent", "attempts": 1, "response": { "status": 200, "latency_ms": 412 } }curl -X POST https://postbag.dev/s/fm_8f3kq2 -H "content-type: application/json" \ -d '{"email":"[email protected]","message":"test","_test":true}' # → { "ok": true, "submission_id": "sb_4d2k91", "status": "received", "deliveries": ["dl_a91x02"] } curl https://postbag.dev/v1/deliveries/dl_a91x02 -H "Authorization: Bearer pb_live_…" # → { "status": "sent", "attempts": 1, "response": { "status": 200, "latency_ms": 412 } } -
4 Wire
Add destinations and routes with individual calls, test any destination with POST /v1/destinations/{id}/test, and write postbag.json into the repo so the next session finds it.
curl -X POST https://postbag.dev/v1/destinations -H "Authorization: Bearer pb_live_…" -d '{ "type": "webhook", "name": "CRM", "config": { "url": "https://crm.example.com/hooks/postbag", "secret": "…" } }' curl -X POST https://postbag.dev/v1/destinations/ds_7hm2q0/test -H "Authorization: Bearer pb_live_…"curl -X POST https://postbag.dev/v1/destinations -H "Authorization: Bearer pb_live_…" -d '{ "type": "webhook", "name": "CRM", "config": { "url": "https://crm.example.com/hooks/postbag", "secret": "…" } }' curl -X POST https://postbag.dev/v1/destinations/ds_7hm2q0/test -H "Authorization: Bearer pb_live_…"
What agent-native means here
It is a property the whole surface has, checked on every change, not a page in the docs.
- Discoverable
- llms.txt, openapi.json, and /v1/me. Accept: text/markdown on the site root returns the agent onboarding page.
- One call to a working form
- POST /v1/quickstart. Everything it does is also available as individual calls; it is a convenience, not a special path.
- Verifiable
- _test submissions return delivery ids to poll. Destinations have a /test endpoint that returns the provider's response.
- Schema-aware, fleet-aware
- GET /v1/streams/{id} returns the stream schema and a form template; POST /v1/forms with from_template creates a form that is pre-attached with a valid mapping. An agent cannot produce a form the stream does not understand.
- Idempotent and safe to retry
- Idempotency-Key on every POST. if_exists: "return" on creates. Re-running setup is a no-op, not a mess.
- Errors that teach
- { code, message, hint, docs } on every error; next[] on every create. Ids are prefixed so they are self-describing in logs and conversation.
Leave the wiring where the next agent will look.
Site factories and agent scaffolds should write postbag.json into the repo and a line into CLAUDE.md or AGENTS.md. The next session, human or agent, finds the form id without guessing. Never hand-write a submit URL.
Coming next as thin clients over the same API: npx postbag init (writes postbag.json) and an MCP server whose tools mirror the API one to one plus postbag_quickstart and postbag_explain.
# CLAUDE.md / AGENTS.md (site repo)
Forms on this site post to Postbag. Config lives in postbag.json (form_id, submit_url, project).
To add a form: POST https://postbag.dev/v1/forms with the project slug, then use the embed from the response.
Never hand-write a submit URL. Verify with a _test submission and poll the delivery. # CLAUDE.md / AGENTS.md (site repo) Forms on this site post to Postbag. Config lives in postbag.json (form_id, submit_url, project). To add a form: POST https://postbag.dev/v1/forms with the project slug, then use the embed from the response. Never hand-write a submit URL. Verify with a _test submission and poll the delivery.
Agent questions
What does an AI agent need to use Postbag?
How does an agent verify that a form actually works?
_test: true. The response includes the submission id and delivery ids; polling GET /v1/deliveries/{id} shows sent along with the provider's response. Test submissions are excluded from quotas.Is there an MCP server or CLI?
/openapi.json. Nothing the CLI or MCP server will do is impossible over HTTP.What happens when an agent makes a mistake?
{ code, message, hint, docs }. The hint says what to do next; docs is a deep link into the error reference. Validation errors list the offending fields. Incomplete stream mappings fail at attach time with the missing fields listed.Is it safe for an agent to re-run a setup script?
Idempotency-Key is honoured on every POST under /v1, and creates accept if_exists: "return" so re-running returns the same objects instead of duplicates or errors.How should a site repo remember its Postbag wiring?
postbag.json at the repo root with form_id, submit_url and project, and a line in CLAUDE.md or AGENTS.md saying forms on this site post to Postbag. Later sessions, human or agent, find the wiring there.Give your agent a key.
Create an account, mint an API key with the manage scope, and hand it to Claude Code, Cursor or Codex with one instruction: read /llms.txt and set up a contact form.