Political Operations
Transactional email
One-off system mail from your own apps: confirmations, password resets, invites, reminders, and form receipts. Campaign mail is a separate product. This mail does not add an unsubscribe footer, and a marketing unsubscribe does not block it.
Quickstart
- Sign in and open Account, then the Transactional tab.
- Turn it on. New organizations start on the sandbox tier: 200 recipients a day and 10 requests a minute. Only an administrator can set the production tier (50,000 a day and 120 a minute) or another cap.
- Enter a From address on a domain you control. Publish the DKIM, SPF, and DMARC records, then click Verify. Sending stays off until the domain is verified.
- The account owner creates an API key limited to transactional email and copies it once.
- Add funds. Each accepted recipient is charged at the rate shown on that page. The default is $1.00 per 1,000 recipients.
API
POST /api/v1/email/transactional and the alias POST /api/v1/emails. Scope email:transactional. Send Authorization: Bearer and an optional Idempotency-Key. A successful accept returns 202 { "id", "status": "queued" }. A response in the 200 range that has an id and no error is success.
curl -sS -X POST https://campaigncommanderapp.com/api/v1/emails \
-H "Authorization: Bearer $CC_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: signup-confirm-user-42" \
-d '{
"from": "Notifications <noreply@your-domain.org>",
"to": ["new.member@example.com"],
"subject": "Confirm your account",
"html": "<p>Confirm your account: {{confirm_url}}</p>",
"text": "Confirm your account: {{confirm_url}}",
"variables": { "confirm_url": "https://example.org/confirm?token=example" }
}'to accepts one address or up to 50 across to, cc, and bcc. from is optional and must be a verified sender for your organization.tracking defaults to false. GET /api/v1/email/transactional lists recent messages. GET /api/v1/email/transactional/:id returns one, including per-recipient status, attempt count, and the next retry time. Status queued means the send is still waiting. The rendered body is not in that response. Templates live at /api/v1/email/transactional/templates and use {{variable}} placeholders.
Insufficient balance returns 402 and nothing is queued. A hard bounce or a spam complaint suppresses that address. A complaint still blocks this mail after the person unsubscribes from campaign mail. The same Idempotency-Key with the same body returns the original id for 24 hours and does not send twice. See the full API & MCP documentation for template endpoints, sending-domain verification, and MCP tools. Webhooks are POST /api/v1/email/transactional/webhooks with an https url. The secret is returned once. Events are delivered, bounced, and failed. Sign the raw body with X-Campaign-Commander-Signature as t=<unix>,v1=<hmac sha256 of t.rawBody> and reject a clock more than 5 minutes off.
Moving an existing integration
Point the same JSON body at Campaign Commander and send your API key as a bearer token. Fields match the usual transactional shape: from, to, subject, html, text, cc, bcc, reply_to, headers, tags, and attachments. There is no SMTP relay. Provider SMTP credentials would skip billing, the send log, and suppression.
const response = await fetch("https://campaigncommanderapp.com/api/v1/emails", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CC_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": `password-reset-${userId}`,
},
body: JSON.stringify({
from: "Notifications <noreply@your-domain.org>",
to: [user.email],
subject: "Reset your password",
html: "<p>Reset your password.</p>",
text: "Reset your password.",
}),
})
const { id } = await response.json()Pricing and limits
The price on your transactional email page is the price you are charged, per recipient, when the message is accepted. The platform default is $1.00 per 1,000, with a 1 cent minimum. A new organization starts on the sandbox tier: 200 recipients a day and 10 requests a minute. Only an administrator sets the production tier. If bounce or complaint rates cross the platform thresholds, sending pauses until an administrator turns it back on. Typo and syntax-invalid addresses are left out of that sample.