BoomSauce API
Programmatic email infrastructure. Same pipeline as the dashboard, same rate limits, same compliance guarantees.
Base URL: https://app.boomsauce.com/api/v1. JSON only. OpenAPI 3.1 spec at /api/v1/openapi.json.
Authentication
Create keys at Account → API Keys. Shown once; we store a SHA-256 hash only. Live keys send real email and debit your wallet; test keys (bs_test_) validate and render but skip SMTP + wallet.
httpAuthorization: Bearer bs_live_abcd1234...Rate limits + per-mailbox cap
300 req/min per tenant across all keys + endpoints. Every response carries X-RateLimit-Limit/Remaining/Reset. 429 responses include retry_after_seconds.
Per-mailbox daily cap: product policy max 300/day, default 75/day. API + UI + warmup all share one counter per mailbox. Cap-exceeded sends fail with 429 mailbox_cap_reached. Set mailbox_rotation: true to rotate automatically.
Idempotency
Include Idempotency-Key on any POST to make retries safe. We cache the response 24h keyed on (api_key, idempotency_key).
Sends
/api/v1/sendsSend one email. Applies merge tags, spintax, link rewriting, open pixel, and the CAN-SPAM footer.
curlcurl -X POST https://app.boomsauce.com/api/v1/sends \
-H "Authorization: Bearer bs_live_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: campaign-42-contact-8821" \
-d '{
"from_brand_id": 7,
"to": { "email": "alex@example.com", "first_name": "Alex" },
"subject": "Hi {{first_name}}",
"html": "<p>Hey {{first_name}}, ...</p>",
"spintax": true,
"mailbox_rotation": true
}'/api/v1/sends/batchUp to 500 recipients per request. The endpoint validates every recipient, reserves an mt_sends shell row for the accepted ones, and returns immediately. Each accepted send is dispatched asynchronously; poll /sends/:id or /sends?since=... for status.
curlcurl -X POST https://app.boomsauce.com/api/v1/sends/batch \
-H "Authorization: Bearer bs_live_..." \
-H "Content-Type: application/json" \
-d '{
"from_brand_id": 7,
"subject": "Quick intro for {{first_name}}",
"html": "<p>Hey {{first_name}}...</p>",
"mailbox_rotation": true,
"recipients": [
{ "email": "a@ex.com", "first_name": "A" },
{ "email": "b@ex.com", "first_name": "B" }
]
}'json{
"batch_id": "f5b2...",
"accepted": [
{ "index": 0, "send_id": 914221, "email": "a@ex.com" },
{ "index": 1, "send_id": 914222, "email": "b@ex.com" }
],
"rejected": [],
"counts": { "accepted": 2, "rejected": 0, "total": 2 },
"mode": "live",
"queued": true
}/api/v1/sends/:idLookup one send. Scoped by tenant.
/api/v1/sendsList sends with filters: since, status, brand_id, contact_email. Cursor pagination with cursor + limit (max 200).
Replies
/api/v1/repliesPoll inbound replies. Excludes warmup and unsolicited mail by default. Filter by classification or pass include_warmup=true.
curlcurl "https://app.boomsauce.com/api/v1/replies?since=2026-04-20T00:00:00Z&classification=interested" \
-H "Authorization: Bearer bs_live_..."/api/v1/repliesReply on a thread. We set In-Reply-To + References headers from the prior message.
curlcurl -X POST https://app.boomsauce.com/api/v1/replies \
-H "Authorization: Bearer bs_live_..." \
-H "Content-Type: application/json" \
-d '{
"in_reply_to_reply_id": 38211,
"html": "<p>Thanks, {{first_name}}. Tuesday 10am work?</p>"
}'Contacts
/api/v1/contactsSearch, filter by status, cursor paginate.
/api/v1/contactsCreate or upsert (merges non-null fields on conflict). Returns 201 on new, 200 on upsert.
curlcurl -X POST https://app.boomsauce.com/api/v1/contacts \
-H "Authorization: Bearer bs_live_..." \
-H "Content-Type: application/json" \
-d '{ "email":"alex@acme.com","first_name":"Alex","company":"Acme" }'/api/v1/contacts/:idLookup by numeric id or by email (e.g. /contacts/alex@acme.com).
/api/v1/contacts/:idPartial update. metadata is shallow-merged. Send an explicit null to clear a field.
/api/v1/contacts/:idSoft-delete (sets status="deleted"). We never hard-delete contact records.
Webhooks
Register a URL + event list. We POST a signed JSON payload to your URL whenever a matching event fires. Retry schedule: 5 attempts with exponential backoff (4s → 8 → 16 → 32 → 64s). After 10 consecutive failures we auto-pause the subscription.
/api/v1/webhookscurlcurl -X POST https://app.boomsauce.com/api/v1/webhooks \
-H "Authorization: Bearer bs_live_..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-service.example.com/boomsauce",
"label": "prod replies",
"events": ["email.replied","email.bounced","email.opened"]
}'Response includes a secret (whsec_...) returned ONCE. Store it safely.
Events you can subscribe to
fieldsemail.sent email.bounced sequence.step_sent
email.delivered email.complained sequence.completed
email.opened email.replied sequence.stopped
email.clicked campaign.paused
campaign.completed
contact.created contact.updated domain.addedSignature verification
Each delivery has BoomSauce-Signature: t=<unix_ts>,v1=<hex_hmac>. The signed payload is "{timestamp}.{rawBody}". Use your stored secret to recompute the HMAC-SHA-256 and compare in constant time.
nodeimport crypto from 'crypto';
function verify(secret, rawBody, header) {
const parts = Object.fromEntries(header.split(',').map(p => p.split('=')));
const t = parseInt(parts.t, 10);
const v1 = parts.v1;
if (Math.abs(Date.now()/1000 - t) > 300) return false; // 5min tolerance
const expected = crypto.createHmac('sha256', secret)
.update(`${t}.${rawBody}`).digest('hex');
return crypto.timingSafeEqual(Buffer.from(v1,'hex'), Buffer.from(expected,'hex'));
}/api/v1/webhooksList your subscriptions.
/api/v1/webhooks/:idUpdate events list, label, or pause state. URL + secret are immutable — rotate by creating a new webhook.
/api/v1/webhooks/:idRevoke. The worker stops dispatching immediately.
/api/v1/webhooks/:id/deliveriesDebug view: last N delivery attempts with HTTP status, response body preview, duration, and error message if any.
/api/v1/webhooks/:id/testEnqueues a synthetic webhook.test delivery so you can verify your endpoint + signature verification without waiting for a real event.
Warmup
Enroll a mailbox in the CheddarInbox peer-to-peer warmup network. Each mailbox is tracked, billed, paused, and resumed independently.
/api/v1/warmupList warmup status across all your mailboxes.
/api/v1/warmupEnable warmup on a mailbox.
curlcurl -X POST https://app.boomsauce.com/api/v1/warmup \
-H "Authorization: Bearer bs_live_..." \
-H "Content-Type: application/json" \
-d '{ "mailbox_id": 42, "daily_volume": 30 }'/api/v1/warmup/:mailbox_idFull status including upstream CheddarInbox metrics.
/api/v1/warmup/:mailbox_idChange daily_volume (5..1000) or status (active|paused|cancelled).
/api/v1/warmup/:mailbox_idCancel warmup entirely.
Merge tags + spintax
Merge tags use {{name}}. Built-ins: {{first_name}}, {{last_name}}, {{email}}, {{company}}, {{unsubscribe_url}}. Anything under metadata resolves as {{key}}.
Spintax uses {option1|option2|option3}. One option is chosen per send so every recipient gets a slightly different copy. Disable per-request with spintax: false.
TypeScript SDK
Single-file drop-in at src/sdk/boomsauce.ts in our repo. Grab the raw file and import. No npm package yet — intentional; one file avoids the versioning + vuln-tracking overhead.
typescriptimport BoomSauce from './boomsauce';
const bs = new BoomSauce(process.env.BS_API_KEY!);
const { send_id } = await bs.sends.create({
from_brand_id: 7,
to: { email: 'alex@example.com', first_name: 'Alex' },
subject: 'Hi {{first_name}}',
html: '<p>Hi {{first_name}}.</p>',
});
const status = await bs.sends.get(send_id);
const replies = await bs.replies.list({ since: '2026-04-20T00:00:00Z' });
// Webhook verification in your handler:
await BoomSauce.verifySignature(SECRET, rawBody, req.header('BoomSauce-Signature'));Python + other languages: use the OpenAPI spec with openapi-generator until we ship an official Python SDK.
Errors
json{ "error": "mailbox_cap_reached",
"message": "Mailbox sender@acme.com has hit today's cap (75/75)." }fields401 unauthorized bad/missing/revoked key
400 canspam_address_missing set address in Account → Profile
400 invalid_body malformed JSON or missing fields
400 invalid_events unknown event name(s) on webhook
404 brand_not_found from_brand_id not yours
404 send_not_found reply target doesn't exist
409 contact_unsubscribed recipient opted out
429 rate_limit_exceeded 300/min per tenant
429 mailbox_cap_reached mailbox at daily cap
429 no_mailbox_available all rotation mailboxes at cap
429 webhook_limit_reached 20 active webhooks per tenant
502 send_failed SMTP provider rejected
502 cheddar_error upstream warmup API failure
503 queue_unavailable Redis down — rarePricing
$1.50 per 1,000 sends on both single and batch endpoints. Replies bill the same. Test-mode sends are free. Warmup billing (per-mailbox CPM against CheddarInbox) continues to accrue against your wallet whether you toggle it via API or UI.
Bug reports, feature requests, or rate-limit bumps: /support.