SendAnchor API
Connect your own SMTP, manage contacts and campaigns, and stream e-commerce events for revenue attribution. All API calls use a workspace API key created in Settings.
Authentication
Authorization: Bearer sa_...
Create a key in Settings - API keys. The full key is shown once. Keys are stored as SHA-256 hashes and can be revoked at any time.
Endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /api/v1/me | Workspace and subscribed contact count |
| GET | /api/v1/lists | Lists with contact counts |
| GET | /api/v1/contacts | Contacts, filter with list_id, q, limit, offset |
| POST | /api/v1/contacts | Create or update a contact |
| GET | /api/v1/campaigns | Campaigns with sent/open/click counts |
| POST | /api/v1/campaigns | Create a draft campaign |
| POST | /api/v1/campaigns/:id/send | Queue a campaign for sending |
| POST | /api/v1/ecommerce/events | Record a normalized e-commerce event |
| POST | /api/v1/ecommerce/stripe | Parse a Stripe event payload |
| POST | /api/v1/ecommerce/shopify | Parse a Shopify order webhook |
| POST | /api/v1/ecommerce/woocommerce | Parse a WooCommerce order webhook |
| GET | /api/v1/revenue | Revenue totals, daily series, campaign attribution, recent orders |
| POST | /api/v1/imports | Import contacts from a Mailchimp, MailWizz, Sendy, SendgoMail, or generic CSV |
/api/v1/meWorkspace and subscribed contact count
/api/v1/listsLists with contact counts
/api/v1/contactsContacts, filter with list_id, q, limit, offset
/api/v1/contactsCreate or update a contact
/api/v1/campaignsCampaigns with sent/open/click counts
/api/v1/campaignsCreate a draft campaign
/api/v1/campaigns/:id/sendQueue a campaign for sending
/api/v1/ecommerce/eventsRecord a normalized e-commerce event
/api/v1/ecommerce/stripeParse a Stripe event payload
/api/v1/ecommerce/shopifyParse a Shopify order webhook
/api/v1/ecommerce/woocommerceParse a WooCommerce order webhook
/api/v1/revenueRevenue totals, daily series, campaign attribution, recent orders
/api/v1/importsImport contacts from a Mailchimp, MailWizz, Sendy, SendgoMail, or generic CSV
MCP server
SendAnchor exposes a Model Context Protocol endpoint at POST /mcp using the same Bearer API key. It supports JSON-RPC initialize, tools/list, and tools/call.
Tools: get_workspace, list_lists, list_contacts, list_campaigns, get_campaign, get_analytics, get_revenue, and create_contact. Campaign sending is intentionally not exposed over MCP.
POST /mcp
Authorization: Bearer sa_...
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": { "name": "list_lists", "arguments": {} }
}
E-commerce events
Send a normalized event from any store. external_id deduplicates retries. If it is omitted, SendAnchor generates one. value_cents is an integer in the currency's minor unit.
curl -X POST https://sendanchor.org/api/v1/ecommerce/events \
-H "Authorization: Bearer sa_..." \
-H "Content-Type: application/json" \
-d '{
"provider": "custom",
"event_type": "order_paid",
"email": "customer@example.com",
"external_id": "order_1042",
"value_cents": 8900,
"currency": "USD",
"utm": { "campaign_id": "campaign-uuid", "source": "newsletter" },
"items": [{ "sku": "TEE-01", "quantity": 2 }]
}'
Supported event types: cart_abandoned, order_placed, order_paid, refund. Provider aliases such as checkout.session.completed are normalized automatically.
Migration imports
Send a CSV export from Mailchimp, MailWizz, Sendy, SendgoMail, or any tool. Header aliases such as Email Address, First Name, Last Name, and Phone Number are detected automatically.
POST /api/v1/imports
{
"provider": "mailchimp",
"list_id": "list-uuid",
"csv": "Email Address,First Name,Last Name\nada@example.com,Ada,Lovelace"
}
The response reports total rows, imported contacts, and skipped rows. Every run is logged and visible in Contacts - Import history.
Automation triggers
Automations can start on a list subscription, cart_abandoned, order_placed, order_paid, tag_added, or an api_event. Set an optional trigger_event to match a specific tag or event name.
A/B subject tests
POST /api/workspaces/:workspaceId/campaigns/:campaignId/ab-test
{
"name": "Subject test",
"subject_a": "A quieter way to send email",
"subject_b": "Your list, your SMTP, one price",
"split_percent": 50
}
Recipients are assigned deterministically at send time. GET .../ab-results returns recipients, sends, opens, clicks, and rates per variant.
Team and audit
Workspace owners and admins manage members at GET/POST /api/workspaces/:id/members, PATCH/DELETE /api/workspaces/:id/members/:userId, and read recent activity at GET /api/workspaces/:id/audit.
Roles: owner (full control), admin (settings and content), editor (content only), and viewer (read-only). Only the owner can manage admins.
IP allowlist
Workspace owners and admins can restrict access by IP at GET/POST /api/workspaces/:id/ip-allowlist and DELETE /api/workspaces/:id/ip-allowlist/:entryId. An empty list allows every IP. Rules apply to session routes, API keys, and MCP.
Use an IPv4 CIDR such as 203.0.113.0/24, or an exact IP. Adding the first rule can lock you out; keep a D1 console path available.
Custom hostnames
Custom tracking domains require a paid Cloudflare for SaaS plan; Cloudflare returns a no-quota error on free zones. The API is present (POST /api/workspaces/:id/custom-hostnames), but the free build does not expose a provisioning form. When a plan is available, set CF_ZONE_ID and a scoped CF_API_TOKEN with SSL and Certificates edit access; active tracking hostnames are used for click, open, and unsubscribe links.
Account access without email
This build sends no account email and needs no external provider. Registration returns a one-time SA-REC-... recovery key; use it to reset the password. There is no verification email and no forgot-password email.
Inbound bounces and complaints
Route a bounce address to this Worker with Cloudflare Email Routing. Deliverability health also checks the sending domain against Spamhaus DBL. The Worker reads X-SendAnchor-Workspace, X-Failed-Recipients, Final-Recipient, Status, and ARF Feedback-Type/Original-Rcpt-To. Hard bounces and complaints mark the contact and add a suppression automatically. You can also use a bounce+<workspaceId>@yourdomain address.
Account recovery
Registration returns a one-time SA-REC-... recovery key. Reset a password with POST /api/auth/recover using the email, recovery key, and new password. Signed-in users can rotate the key with POST /api/auth/recovery-key.
Production operations
GET /api/workspaces/:id/export downloads the workspace as JSON. DELETE /api/workspaces/:id permanently deletes it and requires the exact workspace name in confirm; only the owner can delete.
Sign-in and signup are rate-limited per IP and email; API v1 is limited to 120 requests per minute per key and MCP to 60. Responses include HSTS, CSP, nosniff, referrer, and permissions headers. SMTP hard bounces mark the contact bounced and add a suppression automatically. Expired rate-limit rows are cleared by Cron. Set ALERT_WEBHOOK_URL to receive unhandled-error and failed-cron alerts.
Back up D1 with npx wrangler d1 export sendanchor-db --remote --output backup.sql. Cloudflare Time Travel is available for point-in-time restore.
Referrals and usage
GET /api/workspaces/:id/referrals returns your referral code and link. A new workspace created with ?ref=code gives the referrer 1,000 bonus emails and the new workspace 500. GET /api/workspaces/:id/usage returns contact and monthly email usage against the free limits.
Paid billing is not enabled. POST /api/workspaces/:id/upgrade-requests records a manual plan-review request.
Agency license keys
POST /api/workspaces/:id/licenses creates an agency license key. Validate it with GET /api/licenses/:key, and revoke it with DELETE /api/workspaces/:id/licenses/:licenseId.
SMS gateway
Connect your own SMS webhook with POST /api/workspaces/:id/sms-channels. Test it with POST /api/workspaces/:id/sms-channels/:channelId/test or send through the API with POST /api/v1/sms; SendAnchor posts JSON containing to, body, from, and secret.
Template marketplace
GET /api/marketplace/templates lists published templates. Publish with POST /api/workspaces/:id/marketplace, install with POST /api/workspaces/:id/marketplace/:marketplaceId/install, and unpublish with DELETE /api/workspaces/:id/marketplace/:marketplaceId.
Only published templates are listed publicly. Installing copies the template into the workspace; the source HTML is never returned by the public listing.
Webhooks
Each delivery is signed with HMAC-SHA256 over the raw JSON body:
X-SendAnchor-Event: contact.created
X-SendAnchor-Signature: sha256=<hex>
Events include contact.created, unsubscribe, campaign.sent, and ecommerce.<event_type>. Failed deliveries retry with exponential backoff (1m, 5m, 15m, 1h, 6h; five attempts total). Deliveries are logged with status, attempt count, response code, and response body; failed or pending deliveries can be replayed from Settings.
SendAnchor is a product of ByteVault Enterprise, 18/1 Banerjee Para Road, Barrackpore - Kolkata - 700122, India. Founder: Jacob Silva. Contact jacob.silva@sendanchor.org or support@sendanchor.org.