Emails
Send transactional email and list recent sends. Migrating from Resend? See docs/migration.md.
Send email
POST /emails
Send a transactional email from a verified domain.
Base URL: https://api.supersendtx.com
Authentication
Authorization: Bearer stx_…API keys are created in the dashboard (API Keys). Keys start with stx_.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
from |
string or { email, name? } |
Yes | Must be on a verified domain |
to |
string or string[] |
Yes | Recipient(s) |
subject |
string |
Yes | Subject line |
html |
string |
No* | HTML body (htmlBody / html_body aliases accepted) |
text |
string |
No* | Plain-text body (textBody, text_body, and plain_body aliases accepted) |
reply_to |
string or string[] |
No | Reply-to address(es) (replyTo alias accepted) |
cc |
string or string[] |
No | CC recipient(s) |
bcc |
string or string[] |
No | BCC recipient(s) |
tags |
{ name, value }[] or object |
No | Up to 10 key/value tags stored with the email |
headers |
object |
No | Custom headers; dangerous transport headers are rejected |
attachments |
array |
No | Up to 10 files, 10MB decoded each; executable/script extensions are blocked. Attachment aliases filename, contentType, content, and contentId are also accepted. |
scheduled_at |
string |
No | ISO 8601 timestamp. Creates a scheduled email instead of sending immediately (scheduledAt alias accepted) |
* At least one of html or text is required.
Example
{
"from": "you@yourdomain.com",
"to": "user@example.com",
"subject": "Hello from SuperSend TX",
"html": "<p>It works.</p>"
}With display name:
{
"from": { "email": "you@yourdomain.com", "name": "Your App" },
"to": ["user@example.com", "other@example.com"],
"subject": "Hello",
"html": "<p>Hi</p>",
"text": "Hi",
"reply_to": ["support@yourdomain.com"],
"tags": [{ "name": "order_id", "value": "ord_123" }],
"headers": { "X-Entity-ID": "ord_123" }
}Sandbox self-test
Before your own domain is verified, you can self-test with the shared sandbox domain:
{
"from": "noreply@mail.supersendtx.com",
"to": "owner@example.com",
"subject": "Sandbox check",
"html": "<p>Sandbox works.</p>"
}The sandbox sender is limited to the account email attached to the API key owner.
Responses
200 — Accepted
{
"id": "msg_abc123…",
"status": "sent"
}Scheduled sends return:
{
"id": "msg_abc123…",
"status": "scheduled"
}id is a stable public message ID (msg_…). Use it to correlate webhook events and dashboard activity.
Idempotency
Optional header on POST /emails:
Idempotency-Key: order-123Keys are scoped per account, retained for 24 hours. Replays return the original response. Reusing a key with a different body returns 409 idempotency_conflict.
await client.emails.send({ …, idempotencyKey: 'order-123' })Retrieve email
GET /emails/{id}
Returns one send by public id (msg_…).
const { email } = await client.emails.get('msg_abc123…')Resend
POST /emails/{id}/resend
Creates a new send from a previously stored email (same from/to/subject/body, tags, and headers). Returns a new msg_… id. Attachment bytes are not stored, so attachments are omitted.
Dashboard: Emails → Resend on any row.
SDK:
await client.emails.resend('msg_abc123…')CLI:
supersendtx emails resend --id msg_abc123…Schedule, reschedule, and cancel
Add scheduled_at to POST /emails to store the message and enqueue it for later delivery:
{
"from": "you@yourdomain.com",
"to": "user@example.com",
"subject": "Tomorrow",
"html": "<p>See you tomorrow.</p>",
"scheduled_at": "2026-08-01T12:00:00.000Z"
}Scheduled emails can be updated only while their status is scheduled:
PATCH /emails/msg_abc123…{ "scheduled_at": "2026-08-01T13:00:00.000Z" }Cancel a scheduled email:
{ "cancel": true }SDK:
await client.emails.update('msg_abc123…', { scheduledAt: '2026-08-01T13:00:00.000Z' })
await client.emails.cancel('msg_abc123…')CLI:
supersendtx emails cancel --id msg_abc123…Scheduled sends store message bodies so the worker can send them later. Attachments are not supported on scheduled emails in v1 because raw attachment data is not stored.
Batch send
POST /emails/batch
Send up to 100 emails in one request:
{
"emails": [
{
"from": "you@yourdomain.com",
"to": "user@example.com",
"subject": "Hello",
"html": "<p>Hi</p>"
}
]
}The response is index-aligned:
{
"data": [
{ "index": 0, "id": "msg_abc123…", "status": "sent" }
]
}Per-email validation or delivery failures are returned in that item’s error. Attachments are rejected for batch sends in v1.
SDK:
const result = await client.emails.batch([{ from, to, subject, html }])List emails
GET /emails?limit=25&cursor=…
Returns recent sends for the authenticated API key’s account. limit is 1–100 (default 25). Use opaque cursor / next_cursor for pagination.
Responses include rate-limit headers: ratelimit-limit, ratelimit-remaining, ratelimit-reset.
200
{
"emails": [
{
"id": "msg_abc123…",
"from": "you@yourdomain.com",
"to": ["user@example.com"],
"cc": [],
"bcc": [],
"reply_to": [],
"subject": "Hello",
"status": "delivered",
"last_event": "delivered",
"bounce_reason": null,
"tags": [],
"scheduled_at": null,
"cancelled_at": null,
"created_at": "2026-07-25T12:00:00.000Z",
"sent_at": "2026-07-25T12:00:01.000Z",
"delivered_at": "2026-07-25T12:00:05.000Z",
"bounced_at": null
}
],
"has_more": false,
"next_cursor": null
}Status values: queued, scheduled, sent, delivered, bounced, failed, cancelled.
SDK
const { emails, next_cursor } = await client.emails.list({ limit: 10 })Error format
All errors return:
{
"error": {
"message": "Human-readable message",
"code": "validation_error",
"details": {}
}
}| Status | When |
|---|---|
| 400 | Invalid JSON, missing fields, invalid from |
| 401 | Missing/invalid Bearer token or API key |
| 403 | from domain not verified for this key, or sandbox sender used for recipients outside the account email |
| 409 | Idempotency key conflict |
| 429 | Free plan send limit (plan_limit) |
| 502 | Upstream mail delivery error |
| 503 | Mail delivery temporarily unavailable |
Attachment limits
- Maximum 10 attachments per non-batch, non-scheduled send
- Maximum 10MB decoded size per attachment
- Blocked filename extensions:
.exe,.bat,.cmd,.com,.scr,.js,.vbs,.dll
Examples
curl
curl -X POST https://api.supersendtx.com/emails \
-H "Authorization: Bearer $SUPERSENDTX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"from":"you@yourdomain.com","to":"user@example.com","subject":"Hello","html":"<p>Hi</p>"}'Node.js
import { SuperSendTX } from 'supersendtx'
const client = new SuperSendTX(process.env.SUPERSENDTX_API_KEY!)
await client.emails.send({
from: 'you@yourdomain.com',
to: 'user@example.com',
subject: 'Hello',
html: '<p>Hi</p>',
})Throws SuperSendTXError on failure (error.status, error.message, error.details).
CLI
supersendtx emails send \
--from you@yourdomain.com \
--to user@example.com \
--subject "Hello" \
--html "<p>Hi</p>" \
--tag order_id=ord_123 \
--schedule 2026-08-01T12:00:00.000ZRequires SUPERSENDTX_API_KEY or --api-key.
OpenAPI
Machine-readable spec: openapi/supersendtx.yaml