API Reference
SESMetric REST API
One endpoint to send transactional email. Pair with templates and webhooks for a full delivery pipeline. All examples use a paid-tier key — issue one at /dashboard/keys.
Authentication
Every request sends an X-API-Key header. Issue keys at /dashboard/keys — they are scoped (email:send, email:read) and tied to a paying account. Keys are shown once at creation; store them in a secret manager.
X-API-Key: sk_live_xxxxxxxxxxxxxxxxxxxxxxxxTreat keys like passwords. Never embed in client-side JavaScript — call your own server and proxy.
POST/v1/send
Queue a transactional email. Returns immediately with a msg_… id; delivery events flow to your registered webhooks. Provide either an inline subject+html/text body or a template slug with variables.
Request fields
from_emailstringrequiredVerified identity on your account. Either the exact email or any address @ a verified domain.
tostring[]required1–50 recipients. cc + bcc count toward this total.
ccstring[]Optional CC list.
bccstring[]Optional BCC list. Recipients added to envelope only.
reply_tostringReply-To header for replies that bypass your sending mailbox.
subjectstringRequired when not using a template. Rendered as Jinja2 if a template is used.
htmlstringHTML body. Required if text is not provided (or unless using a template).
textstringPlain-text alternative. Derived from HTML when blank if a template is used.
templatestringSlug of a system catalog template or one of your cloned templates. Resolved per-account.
variablesobjectRender context for a template. Nested objects supported, e.g. { user: { first_name } }.
headersobjectAdditional message headers. Sender-controlled metadata only.
tagsstring[]Free-form labels surfaced in analytics + webhook events.
attachmentsAttachment[]Each: { filename, content_base64, content_type }. Total payload ≤ 25 MB.
Inline body
curl -X POST https://api.sesmetric.com/v1/send \
-H "X-API-Key: sk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"from_email": "you@yourdomain.com",
"to": [
"recipient@example.com"
],
"subject": "Welcome, Alex",
"html": "<p>Hi Alex — welcome aboard.</p>",
"text": "Hi Alex — welcome aboard."
}'Using a template
curl -X POST https://api.sesmetric.com/v1/send \
-H "X-API-Key: sk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"from_email": "you@yourdomain.com",
"to": [
"recipient@example.com"
],
"template": "welcome",
"variables": {
"user": {
"first_name": "Alex"
}
}
}'Response
{
"id": "msg_3f8c1b2e9a4d4b...",
"status": "queued"
}Error responses
Errors return a JSON object with a detail field. The HTTP status code is authoritative for client retry decisions.
400Validation failed — missing subject or body, invalid emails, too many recipients (>50).
401Missing or unknown `X-API-Key` header.
402Key belongs to a non-paying account. Upgrade at `/dashboard/billing`.
403`from_email` is not a verified identity on the calling account.
404Template slug not found (system templates and your own templates are both searched).
429Daily quota or per-second rate limit exceeded.
502Upstream SMTP relay returned an error. Retry after a short backoff.
Webhooks
Register HTTPS endpoints at /dashboard/webhooks to receive delivery events. Each POST is signed with HMAC-SHA256 using your webhook secret. Verify the signature before trusting the payload.
Event types
deliverybounceopenclickcomplaintSample payload
POST https://your.app/sesmetric-events
X-SM-Signature: sha256=a1b2c3d4...
Content-Type: application/json
{
"event_type": "delivery",
"user_id": 42,
"payload": {
"sm_mail_id": "msg_3f8c1b2e9a4d4b...",
"message_id": "0100018f...000000",
"recipients": ["recipient@example.com"],
"smtp_response": "250 ok",
"event_timestamp": "2026-05-19T13:42:11Z"
}
}Signature verification
import crypto from 'crypto';
function verify(rawBody, header, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
// Use timingSafeEqual to defeat timing attacks.
return crypto.timingSafeEqual(Buffer.from(header), Buffer.from(expected));
}Retry schedule: 30s, 5m, 30m, 2h, 6h. After 5 failed attempts the delivery row is marked abandoned.
Rate limits & quotas
- • Daily send quota is enforced per account by the mail-sender worker. View remaining quota at
/dashboard. - • Free accounts cannot call
/v1/send— upgrade or request a trial. - • 50 total recipients (to + cc + bcc) per request.
- • 25 MB total payload including attachments.
- • Excess returns
429with aretry-afterheader.