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_xxxxxxxxxxxxxxxxxxxxxxxx

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

Verified identity on your account. Either the exact email or any address @ a verified domain.

tostring[]required

1–50 recipients. cc + bcc count toward this total.

ccstring[]

Optional CC list.

bccstring[]

Optional BCC list. Recipients added to envelope only.

reply_tostring

Reply-To header for replies that bypass your sending mailbox.

subjectstring

Required when not using a template. Rendered as Jinja2 if a template is used.

htmlstring

HTML body. Required if text is not provided (or unless using a template).

textstring

Plain-text alternative. Derived from HTML when blank if a template is used.

templatestring

Slug of a system catalog template or one of your cloned templates. Resolved per-account.

variablesobject

Render context for a template. Nested objects supported, e.g. { user: { first_name } }.

headersobject

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

StatusCause
400

Validation failed — missing subject or body, invalid emails, too many recipients (>50).

401

Missing or unknown `X-API-Key` header.

402

Key belongs to a non-paying account. Upgrade at `/dashboard/billing`.

403

`from_email` is not a verified identity on the calling account.

404

Template slug not found (system templates and your own templates are both searched).

429

Daily quota or per-second rate limit exceeded.

502

Upstream 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

deliverybounceopenclickcomplaint

Sample 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 429 with a retry-after header.