API v1

SendAnchor API

Connect your own SMTP or a supported provider API, 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

MethodPathPurpose
GET/api/v1/meWorkspace and subscribed contact count
GET/api/v1/listsLists with contact counts
GET/api/v1/contactsContacts, filter with list_id, q, limit, offset
POST/api/v1/contactsCreate or update a contact
POST/api/workspaces/:id/contacts/verifyVerify a batch of contacts by MX, disposable domain, and role account
GET/api/smtp-presetsProvider presets for SES, SendGrid, Mailgun, Postmark, SparkPost, Elastic Email, Brevo, and Resend
GET/api/v1/campaignsCampaigns with sent/open/click counts
POST/api/v1/campaignsCreate a draft campaign
POST/api/v1/campaigns/:id/sendQueue a campaign for sending
POST/api/v1/ecommerce/eventsRecord a normalized e-commerce event
POST/api/v1/ecommerce/stripeParse a Stripe event payload
POST/api/v1/ecommerce/shopifyParse a Shopify order webhook
POST/api/v1/ecommerce/woocommerceParse a WooCommerce order webhook
GET/api/v1/revenueRevenue totals, daily series, campaign attribution, recent orders
POST/api/v1/importsImport contacts from a Mailchimp, MailWizz, Sendy, SendgoMail, or generic CSV
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

POST
/api/workspaces/:id/contacts/verify

Verify a batch of contacts by MX, disposable domain, and role account

GET
/api/smtp-presets

Provider presets for SES, SendGrid, Mailgun, Postmark, SparkPost, Elastic Email, Brevo, and Resend

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

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 and steps

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.

Steps support delay, email, condition, action, and webhook. Conditions can compare email, name, phone, tag, or a custom field with equals, contains, exists, greater-than, and less-than. Actions can add or remove tags, add or remove list membership, set a field, unsubscribe, or suppress. Webhooks receive a signed JSON payload with the contact and automation context.

{
  "type": "condition",
  "field": "custom",
  "custom_key": "plan",
  "operator": "equals",
  "value": "pro"
}

Forms, inline embeds, and popups

Create a form in Forms & popups. Inline forms can be embedded with an iframe. Popups can trigger immediately, after a delay, at a scroll depth, on exit intent, or on a CSS selector click. Each form has a position, light or dark theme, accent color, custom CSS, success message, redirect URL, and a frequency cap stored in the visitor's browser.

<script src="https://sendanchor.org/f/FORM_ID/embed.js" async></script>

Forms include a honeypot and a time trap. Submissions are rate-limited per IP. Double opt-in sends a confirmation email through the workspace SMTP account.

Email verification

POST /api/workspaces/:id/contacts/verify checks contacts in batches. Verification uses syntax checks, MX records, disposable-domain detection, and role-account detection. It does not probe the recipient's SMTP server, so it never puts your sending IP at risk. Results are verified, risky, invalid, or unknown. Add "suppress_invalid": true to suppress invalid addresses automatically.

{ "list_id": "list-uuid", "limit": 50, "suppress_invalid": true }

SMTP and provider APIs

GET /api/smtp-presets returns presets for Amazon SES, SendGrid, Mailgun, Postmark, SparkPost, Elastic Email, Brevo, Resend, and generic SMTP. A preset only fills the host, port, TLS mode, and username hint. Set delivery to api to send through Resend, SendGrid, Mailgun, Postmark, or SparkPost directly; the password field holds the API key. SMTP remains the default. SendAnchor connects directly to your provider and never relays through our servers.

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.

Tracking domain

All click, open, and unsubscribe links use the shared domain track.sendanchor.org, so your main application domain stays out of the message body. Custom tracking domains are disabled to keep Cloudflare usage and billing at zero. Connect your own SMTP account or provider API key to send from your own domain.

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.

Abuse isolation

SendAnchor never sends through a shared relay. Each workspace connects its own SMTP or provider API account, so a compromised or spammy sender burns their own provider reputation and their own domain, not SendAnchor's. Messages carry X-Abuse-Contact: abuse@sendanchor.org and one-click List-Unsubscribe headers.

Workspaces can be paused automatically for a bounce spike or a manual abuse review. A paused workspace cannot start campaigns or automation email until support reviews it. Forms have a honeypot, a time trap, and per-IP rate limits. Report abuse to abuse@sendanchor.org.

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, usage, and fair use

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. Paid and lifetime plans return null limits, which means unlimited contacts and sends under fair use.

Fair use protects deliverability, not volume. There is no daily or monthly send ceiling on paid and lifetime plans. The guard pauses a workspace only when the bounce rate is above 10% over a meaningful sample, or when support places it under manual review for spam, purchased lists, or phishing. Sending always uses the workspace's own SMTP or provider API account, so a spammer damages their own provider reputation, not SendAnchor's. There is no shared relay and no shared sending IP.

Billing is handled through Creem checkout. POST /api/billing/checkout creates a checkout session; paid plans are activated by the signed Creem webhook.

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: Sayan Roy Chowdhury. Contact sayan@sendanchor.org or support@sendanchor.org.