API v1

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

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

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

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.