The whole email stack for agents, one API.
ThreadCamp reconciles inboxes, sending and forwarding behind one key. Every primitive below maps to a real endpoint under /v1 - no glue code between three vendors.
Inboxes as a primitive
POST /v1/inboxes creates a real, addressable inbox. On the free tier you get an address on the shared in.threadcamp.com domain (reserved - activates at launch); pass a verified custom domain for your own. Each inbox carries an autonomy policy and messages you can list by direction.
Resend-compatible sending
POST /v1/emails accepts the Resend payload shape - from, to, subject, text, html, cc - plus scheduled_at for delayed send and client_id for idempotency. Migrate by changing the base URL and key.
Forwarding Routes with SRS
POST /v1/routes defines a catch-all (*@domain) or alias Route. The action is forward, webhook, inbox or split; srs rewrites the envelope sender so SPF and DMARC survive the hop. srs defaults on for forward.
Custom domains, automated DNS
POST /v1/domains returns the full record set - MX for receiving, SPF, a pair of DKIM CNAMEs, and a DMARC policy. Place them, then call POST /v1/domains/:id/verify to mark the domain verified.
Human-in-the-loop approvals
The differentiator. Set an inbox to approve-first and any send from it is held as status pending_approval with an approval_id. A human resolves it via POST /v1/approvals/:id - approving is what executes the send.
Signed webhooks + event log
POST /v1/webhooks registers an endpoint and returns a signing secret once. Deliveries carry an x-threadcamp-signature header. GET /v1/events is the inspectable log of everything that happened on your account.
Human-in-the-loop approvals
The category's biggest objection is blast radius: what if the agent emails the wrong person, at scale? Set an inbox to approve-first and every send from it lands as a pending draft. The send does not go out until a human calls POST /v1/approvals/:id with action "approve" - and that approval is what actually sends it. Reject instead, and the message is marked rejected and never leaves.
How approvals workBuilt to be discovered and used unattended.
MCP server
A hosted and stdio (npx tsx mcp/server.ts) MCP server exposes the API as callable tools - create_inbox, send_email, wait_for_message and more. See the MCP docs.
Machine-readable everything
llms.txt, /openapi.json and /pricing.json let an agent read the surface and self-select a plan.
Sandbox keys + idempotency
A public sandbox key (sk_test_sandbox_threadcamp_public_demo) lets agents try the API with no signup. client_id makes creates and sends safe to retry.
Create an inbox, send, forward.
Create an inbox (approve-first)
curl https://threadcamp.vercel.app/v1/inboxes \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{ "display_name": "Support Agent", "autonomy": "approve-first" }'
# -> 201
# { "id": "inbox_...", "object": "inbox",
# "address": "support-agent@in.threadcamp.com",
# "autonomy": "approve-first", "created_at": "..." }Send an email (scheduled, idempotent)
curl https://threadcamp.vercel.app/v1/emails \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"from": "support-agent@in.threadcamp.com",
"to": ["customer@example.com"],
"subject": "Your receipt",
"text": "Thanks for your order.",
"scheduled_at": "2026-08-01T09:00:00Z",
"client_id": "receipt-8891"
}'
# from an approve-first inbox -> 202
# { "id": "msg_...", "status": "pending_approval", "approval_id": "apr_..." }Create a forwarding Route
curl https://threadcamp.vercel.app/v1/routes \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"match": "*@acme-agents.email",
"action": "forward",
"destination": "team@acme.com",
"srs": true
}'
# -> 201
# { "id": "route_...", "object": "route", "match": "*@acme-agents.email",
# "action": "forward", "destination": "team@acme.com", "srs": true }Give your agent the full stack in one call.
Inboxes, sending and forwarding on the free tier. No credit card.