Sendex

API Reference

The Sendex API lets you send and receive email programmatically using your verified domains. All endpoints follow RESTful conventions and return JSON.

Email content is encrypted at rest using AES-256-GCM and stored for up to 30 days. If you prefer that no email content is saved to our servers, you can opt out at any time from Dashboard → Settings

Base URL

https://sendexapi.com/api/v1

Authentication

Every request must include your API key in the Authorization header as a Bearer token. Generate keys from the API Keys section of your dashboard.

Authorization: Bearer sk_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

send_only

Can send emails via POST /api/v1/emails. Cannot read or list messages.

full

Full read and write access: send, list, and retrieve emails and domains.

Keys can optionally be scoped to specific domains. Requests from out-of-scope domains return 403 Forbidden.

Rate Limits

Rate limits are enforced per API key. Exceeding the limit returns 429 Too Many Requests. The underlying AWS SES sending limits apply to outbound mail regardless of API limits.

Delivery & Retries

Sendex uses an internal queue between your API call and the actual SES send. This decouples your request from the network call to AWS, so transient SES failures are handled automatically without any effort on your side.

How it works

  1. Your POST /api/v1/emails request returns 202 Accepted immediately — the email is queued, not yet sent.
  2. A background worker picks up the job and sends it to AWS SES.
  3. If SES returns an error, the job is automatically retried with exponential backoff.
  4. Once sent (or permanently failed), a webhook fires so you know the outcome.

Retry schedule

AttemptDelay before retry
1 → 230 s
2 → 360 s
3 → 42 min
4 → 54 min
5+8 min → 30 min (cap)
Max attempts54 total — ~24 h coverage
A 202 Accepted response does not mean the email was delivered — only that it was queued. Subscribe to the email.sent and email.failed webhooks to track the actual outcome.

Errors

All errors return a JSON body with error (machine-readable slug) and message (human-readable string).

{
  "error": "bad_request",
  "message": "from, to, subject, and text or html are required."
}
HTTP statuserror slugMeaning
400bad_requestMissing or invalid parameters.
401unauthorizedMissing or invalid API key.
403forbiddenKey lacks permission for this resource.
404not_foundThe requested resource does not exist.
422unprocessable_entityDomain is not verified for sending.
429too_many_requestsRate limit exceeded.
502bad_gatewayUpstream SES error.
500internal_server_errorUnexpected server error.

Webhooks

Webhooks allow Sendex to push real-time event notifications to your server. Register endpoints from the Webhooks section of your dashboard.

Payload format

Every webhook request is an HTTP POST with a JSON body and a signature header.

POST https://your-server.com/webhook
Content-Type: application/json
X-Sendex-Signature: sha256=<hmac-sha256-hex>

{
  "event": "email.sent",
  "created_at": "2026-03-05T12:00:00.000Z",
  "data": { ... }
}

Verifying signatures

Compute HMAC-SHA256(secret, rawBody) and compare it to the value in the X-Sendex-Signature header (after stripping the sha256= prefix). Use a timing-safe comparison.

import crypto from "crypto";

function verifyWebhook(rawBody: string, secret: string, header: string): boolean {
  const expected = "sha256=" + crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(header),
    Buffer.from(expected)
  );
}

Events

EventDescriptionRequires
email.sentEmail successfully sent via SES.
email.failedEmail send to SES failed.
email.receivedInbound email received.
email.deliveredSES confirmed delivery.SES_CONFIG_SET
email.bouncedSES reported a bounce.SES_CONFIG_SET
email.complainedRecipient marked as spam.SES_CONFIG_SET
email.openedRecipient opened the email.SES_CONFIG_SET + open tracking
email.clickedRecipient clicked a link.SES_CONFIG_SET + click tracking
broadcast.queuedBroadcast was created and queued.
broadcast.startedBroadcast worker began sending.
broadcast.completedBroadcast finished sending.
broadcast.pausedBroadcast was paused.
broadcast.cancelledBroadcast was cancelled.
broadcast.failedBroadcast worker encountered a fatal error.
contact.createdA contact was created or upserted.
contact.subscribedContact subscription was set to true.
contact.unsubscribedContact unsubscribed (via API or unsubscribe page).

SES delivery events setup

Events like email.delivered, email.bounced, and email.complained require an AWS SES Configuration Set with an SNS destination pointing to /api/ses-notifications. Set the SES_CONFIG_SET environment variable to the name of your configuration set.