Documentation / Send transactional email
BUILD

Send transactional email

Send product emails with durable acceptance, explicit scheduling, and safer retries.

POST /v1/notifications

Provide a verified from address, one recipient, and either inline content or a template. category defaults to transactional. Idempotency-Key is also accepted as a request header.

curl -X POST "$BASE_URL/api/v1/notifications" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "hello@yourdomain.com",
    "to": "alex@example.com",
    "subject": "A warm welcome",
    "html": "<h1>Good to have you here.</h1>",
    "idempotency_key": "welcome-alex-001"
  }'
Field / scopeDescriptionRequirement / access
to / fromRecipient and verified sender email addressesRequired
idempotency_keyUnique key for a logical requestRequired
subject / html / textInline email contentContent or template
template_id / template_versionTemplate and optional immutable versionOptional
variablesString, number or boolean values for placeholdersOptional
scheduled_atFuture ISO 8601 timestampOptional
attachment_idsReady, unexpired attachment IDs; at most 5Optional

Idempotency and scheduling

An identical retry with the same key returns the original request. Reusing a key with different content conflicts. Scheduled requests still reserve capacity at acceptance. Cancel a message before sending with POST /v1/notifications/:id/cancel.

Acceptance is asynchronous

A 202 response acknowledges durable acceptance. Inspect the returned status and timeline; provider acceptance and recipient delivery happen later. An unknown provider outcome is not automatically resent, to avoid duplicate messages.

Send from JavaScript or Python

No vendor SDK is required. Run this on your server; do not expose API keys in frontend code.

// JavaScript (server-side)
const response = await fetch(process.env.BASE_URL + "/api/v1/notifications", {
  method: "POST",
  headers: { Authorization: "Bearer " + process.env.API_KEY,
    "Content-Type": "application/json" },
  body: JSON.stringify({ from: "hello@yourdomain.com",
    to: "alex@example.com", subject: "Welcome", html: "<p>Hello!</p>",
    idempotency_key: "welcome-alex-001" })
});
if (!response.ok) throw new Error(await response.text());
const { data } = await response.json();

# Python (standard library)
import json, os, urllib.request
payload = {"from": "hello@yourdomain.com", "to": "alex@example.com",
  "subject": "Welcome", "html": "<p>Hello!</p>",
  "idempotency_key": "welcome-alex-001"}
req = urllib.request.Request(os.environ["BASE_URL"] + "/api/v1/notifications",
  data=json.dumps(payload).encode(), method="POST",
  headers={"Authorization": "Bearer " + os.environ["API_KEY"],
    "Content-Type": "application/json"})
with urllib.request.urlopen(req) as response:
  message = json.load(response)["data"]
Building something interesting?We’d love to help