# SuperSend TX — full documentation bundle Generated for AI agents. Canonical index: https://docs.supersendtx.com/llms.txt OpenAPI: https://docs.supersendtx.com/openapi.yaml --- # SuperSend TX — Quickstart Send your first transactional email in about five minutes. Migrating from another provider? Start with [Resend](./migration.md), [Postmark](./migration/postmark.md), or [Amazon SES](./migration/ses.md), then mirror send + webhook flows from the hosted [API reference](https://docs.supersendtx.com/api-reference). Building auth email? See [password reset](./guides/password-reset-emails.md), [Supabase Auth](./guides/supabase.md), and [Clerk / Auth.js](./guides/auth-provider-email.md). Using React Email components? See [Send React Email](./guides/react-email.md). **Hosted docs:** [docs.supersendtx.com](https://docs.supersendtx.com) **Dashboard:** [app.supersendtx.com](https://app.supersendtx.com) **API:** `https://api.supersendtx.com` --- ## For AI agents - **Index:** [docs.supersendtx.com/llms.txt](https://docs.supersendtx.com/llms.txt) - **Full bundle:** [docs.supersendtx.com/llms-full.txt](https://docs.supersendtx.com/llms-full.txt) - **OpenAPI:** [docs.supersendtx.com/openapi.yaml](https://docs.supersendtx.com/openapi.yaml) - **Agent skill notes:** [docs.supersendtx.com/ai/agent-skill](https://docs.supersendtx.com/ai/agent-skill) - **MCP server:** [docs.supersendtx.com/ai/mcp](https://docs.supersendtx.com/ai/mcp) (`supersendtx-mcp` on npm) - **AI app builders:** [docs.supersendtx.com/builders](https://docs.supersendtx.com/builders) (Lovable, Replit, Bolt, Base44, v0 prompts) Use the dashboard **Get started** page to copy a personalized setup prompt with your API key and sandbox rules. --- ## 1. Create an account 1. Open the dashboard at [app.supersendtx.com](https://app.supersendtx.com). 2. Sign up with email + password (or email code if you prefer). 3. If using email code: enter the code emailed to you. --- ## 2. Send a sandbox test (fastest path) On **Get started** (`/overview`), choose one of two doors: ### Set it up here (dashboard) 1. Click **Send test email** — we create an API key if needed and send from the shared sandbox sender to your account email. 2. Check your inbox for “SuperSend TX — your first email”. 3. Copy the `stx_…` secret if shown (once). No domain or DNS required for this step. ### Use with Cursor or Claude 1. On **Get started**, click **Copy setup prompt** or **Install in Cursor**. 2. Paste the prompt into your editor, or add the `supersendtx-mcp` MCP server with your API key. 3. Let the agent wire `POST /emails` (or the SDK) into your app and run the sandbox self-test. See [`docs/ai/agent-skill.md`](./ai/agent-skill.md) and [`docs/ai/mcp.md`](./ai/mcp.md). --- ## 3. Create an API key (if you skipped the dashboard flow) 1. Go to **API Keys → Create** (or use an existing `stx_…` key). 2. Copy the secret — it is shown **once**. ```bash export SUPERSENDTX_API_KEY=stx_your_key_here ``` --- ## 4. Verify a sending domain (when ready for production `from`) ### Dashboard (recommended) 1. Optional but easiest: **Settings → Integrations** → paste a Cloudflare API token (Zone DNS Edit) → Save. 2. Go to **Domains → Add domain** and enter your domain (e.g. `yourdomain.com`). 3. On the domain page: - If Cloudflare is connected: click **Apply DNS (Cloudflare)**, then **Verify DNS**. - If your DNS is at GoDaddy: switch to **GoDaddy**, paste an API key + secret for a one-time apply, then **Verify DNS**. - Otherwise paste the shown TXT records at your DNS host (merge SPF if you already have one), then **Verify DNS**. 4. Optional after verification: set **Delivery settings** on the domain detail page for: - open tracking - click tracking - `tls_mode` (`opportunistic` or `enforced`) 5. Check the built-in DMARC/BIMI guidance on the same page before you roll out branded inbox features. | Type | Purpose | |------|---------| | TXT `_supersendtx.yourdomain.com` | Domain ownership | | TXT `{selector}._domainkey.yourdomain.com` | DKIM (domain signing key) | | CNAME `rp.yourdomain.com` | Return path → `rp.core.superesp.com` | | TXT `yourdomain.com` | SPF (`include:spf.supersendtx.com`) | | TXT `_dmarc.yourdomain.com` | DMARC | Ownership, SPF, DKIM, and return-path are required to verify. Verify also confirms mail-server DKIM readiness so sends are signed with your domain (not the shared pool). Local Docker auto-verifies when `SUPERSENDTX_DEV_AUTO_VERIFY=true`. If a domain is already attached to another SuperSend TX team, `POST /domains` returns a 409 with claim instructions instead of creating a duplicate owner. ### CLI (from your editor / terminal) Save a Cloudflare token under **Settings → Integrations** first (recommended). Then: ```bash export SUPERSENDTX_API_KEY=stx_your_key_here npx -y --package=supersendtx-cli -- supersendtx domains add yourdomain.com # Uses the Cloudflare token stored in SuperSend TX (no local CLOUDFLARE_API_TOKEN needed) npx -y --package=supersendtx-cli -- supersendtx domains apply yourdomain.com --provider cloudflare npx -y --package=supersendtx-cli -- supersendtx domains verify yourdomain.com ``` Optional override: set `CLOUDFLARE_API_TOKEN` locally to apply with a machine token instead of the dashboard one. GoDaddy still uses local `GODADDY_API_KEY` / `GODADDY_API_SECRET`. --- ## 5. Send from your app Pick one integration method below. Replace `you@yourdomain.com` with an address on your **verified** domain. ### Sandbox self-test (before DNS) Use the shared sandbox sender on `mail.supersendtx.com`, but only send to **your own account email**: ```bash curl -X POST https://api.supersendtx.com/emails \ -H "Authorization: Bearer $SUPERSENDTX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "from": "noreply@mail.supersendtx.com", "to": "you@example.com", "subject": "Sandbox check", "html": "
SuperSend TX sandbox works.
" }' ``` Once your domain is verified, switch `from` to your own domain. ### curl (production) ```bash 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 from SuperSend TX", "html": "It works.
" }' ``` ### Node.js SDK ```bash npm install supersendtx ``` ```ts import { SuperSendTX } from 'supersendtx' const client = new SuperSendTX(process.env.SUPERSENDTX_API_KEY!) const { id, status } = await client.emails.send({ from: 'you@yourdomain.com', to: 'user@example.com', subject: 'Hello from SuperSend TX', html: 'It works.
', }) console.log(id, status) ``` ### CLI ```bash SUPERSENDTX_API_KEY=$SUPERSENDTX_API_KEY npx -y --package=supersendtx-cli -- supersendtx emails send \ --from you@yourdomain.com \ --to user@example.com \ --subject "Hello from SuperSend TX" \ --html "It works.
" ``` Or install globally: `npm install -g supersendtx-cli`, then run `supersendtx emails send …`. --- ## Success response ```json { "id": "msg_abc123…", "status": "sent" } ``` --- ## Plan limits When billing is enabled, Sandbox is for integration and test sends (hard daily and monthly caps). Pool and Dedicated meter overage past included volume. Over Sandbox limit: ```json { "error": { "message": "…", "code": "plan_limit", "upgrade_url": "/settings/billing" } } ``` HTTP **429**. Upgrade in the dashboard under **Settings → Billing**. ## Common errors | HTTP | Meaning | Fix | |------|---------|-----| | 401 | Invalid or missing API key | Check `Authorization: Bearer stx_…` | | 403 | From domain not verified | Verify domain in dashboard; `from` must match | | 400 | Missing `from`, `to`, or `subject` | Send required fields + `html` or `text` | | 429 | Plan send limit (`code: plan_limit`) | Upgrade at Settings → Billing | | 503 | Mail delivery temporarily unavailable | Retry later or contact support | Full reference: [docs.supersendtx.com/api-reference](https://docs.supersendtx.com/api-reference) --- ## 6. Webhooks (optional) 1. Go to **Webhooks** in the dashboard (or use the API). 2. Add your HTTPS endpoint URL. 3. Copy the signing secret (`whsec_…`) — shown once. 4. Verify `SuperSendTX-Signature` on incoming `POST`s. ```ts await client.webhooks.create({ url: 'https://yourapp.com/webhooks/supersendtx', }) ``` See [docs.supersendtx.com/api-reference](https://docs.supersendtx.com/api-reference) for payload shape and signature verification. --- ## 7. Receive email (optional) Want an app inbox or agent mailbox? 1. Create a dedicated inbound subdomain such as `inbound.example.com`. 2. Add it with `inbound_enabled: true` (API) or `supersendtx domains add inbound.example.com --inbound true` (CLI). 3. Verify the domain, then publish the returned MX record. 4. Subscribe to `email.received` and/or poll `GET /received-emails`. See [`docs/api/inbound.md`](./api/inbound.md) for the full flow and the MX conflict warning. --- ## 8. Event-driven automations (optional) SuperSend TX can trigger transactional sequences from custom events. **Dashboard:** open **Automations**, create from a starter (or blank) on the visual canvas, configure steps in the side panel (send-email can use a published **Templates** entry or inline HTML), then Activate. **CLI / API:** create and activate from a JSON file (handy in Cursor or CI): ```bash supersendtx automations create --file ./welcome.json supersendtx automations activate --id "$AUTOMATION_ID" ``` Then send the trigger event from your app: ```bash curl -X POST https://api.supersendtx.com/events \ -H "Authorization: Bearer $SUPERSENDTX_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: evt_user_created_123" \ -d '{ "name": "user.created", "user_id": "user_123", "email": "user@example.com", "data": { "name": "Ada Lovelace" } }' ``` Response: ```json { "event": { "id": "ae_123", "name": "user.created", "user_id": "user_123", "email": "user@example.com", "data": { "name": "Ada Lovelace" }, "source": "api", "created_at": "2026-07-26T12:00:00.000Z" }, "matched_automations": 1, "resumed_runs": 0 } ``` See [`docs/api/automations.md`](./api/automations.md) and [`docs/api/events.md`](./api/events.md). --- ## Next steps - Docs home: [docs.supersendtx.com](https://docs.supersendtx.com) - API reference: [docs.supersendtx.com/api-reference](https://docs.supersendtx.com/api-reference) - Next.js quickstart: [docs.supersendtx.com/frameworks/nextjs](https://docs.supersendtx.com/frameworks/nextjs) - React Email: [docs.supersendtx.com/guides/react-email](https://docs.supersendtx.com/guides/react-email) - Node.js quickstart: [docs.supersendtx.com/frameworks/node](https://docs.supersendtx.com/frameworks/node) - Send API: [`docs/api/emails.md`](./api/emails.md) - Domains API: [`docs/api/domains.md`](./api/domains.md) - Inbound email API: [`docs/api/inbound.md`](./api/inbound.md) - Deliverability: [`docs/api/deliverability.md`](./api/deliverability.md) - Events: [`docs/api/events.md`](./api/events.md) - Templates: [`docs/api/templates.md`](./api/templates.md) - Automations: [`docs/api/automations.md`](./api/automations.md) - SMTP status: [`docs/api/smtp.md`](./api/smtp.md) - Webhooks: [`docs/api/webhooks.md`](./api/webhooks.md) - AI onboarding: [docs.supersendtx.com/llms.txt](https://docs.supersendtx.com/llms.txt), [docs.supersendtx.com/llms-full.txt](https://docs.supersendtx.com/llms-full.txt), [`docs/ai/agent-skill.md`](./ai/agent-skill.md), [`docs/ai/mcp.md`](./ai/mcp.md) (`supersendtx-mcp` npm package) - OpenAPI spec: [docs.supersendtx.com/openapi.yaml](https://docs.supersendtx.com/openapi.yaml) · [`openapi/supersendtx.yaml`](../openapi/supersendtx.yaml) - Product plan: [`PLAN.md`](../PLAN.md) --- # Authentication SuperSend TX authenticates API requests with Bearer API keys that start with `stx_`. ## Obtain a key 1. Open the [dashboard](https://app.supersendtx.com). 2. Go to **API Keys → Create**. 3. Copy the secret — it is shown **once**. ```bash export SUPERSENDTX_API_KEY=stx_your_key_here ``` Keep keys server-side only. Never ship them in browser bundles or public repos. ## Request header Send the key on every management and send request: ```bash curl 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": "It works.
" }' ``` ### Node SDK ```javascript import { SuperSendTX } from 'supersendtx' const client = new SuperSendTX(process.env.SUPERSENDTX_API_KEY) ``` ### CLI ```bash export SUPERSENDTX_API_KEY=stx_your_key_here npx -y --package=supersendtx-cli -- supersendtx emails send \ --from you@yourdomain.com \ --to user@example.com \ --subject "Hello" \ --html "It works.
" ``` ## Base URLs | Surface | URL | |---------|-----| | API | `https://api.supersendtx.com` | | Dashboard | `https://app.supersendtx.com` | ## Unauthorized responses Missing or invalid keys return **401** with: ```json { "error": { "message": "Unauthorized" } } ``` See [Errors](/errors) for the full error shape. --- # Errors SuperSend TX returns JSON errors that match the OpenAPI contract. ## Shape ```json { "error": { "message": "Human-readable summary", "details": {} } } ``` `details` is optional and may include field-level validation info. ## Common status codes | Status | When | |--------|------| | `400` | Invalid JSON or failed validation | | `401` | Missing/invalid `Authorization: Bearer stx_…` | | `403` | Authenticated but not allowed (e.g. unverified sending domain) | | `404` | Resource not found | | `409` | Conflict (e.g. domain already claimed) | | `429` | Rate limited | | `502` | Upstream mail delivery failure | ## Examples ### Unverified domain (403) ```json { "error": { "message": "Sending domain is not verified" } } ``` ### Validation (400) ```json { "error": { "message": "Validation failed", "details": { "to": "Required" } } } ``` ## Idempotency Some write endpoints accept an `Idempotency-Key` header. Replays with the same key return the original success response instead of creating duplicates — see the [API Explorer](/api-explorer) and OpenAPI spec for which operations support it. --- # Migration from Resend Also migrating from other providers? - [Postmark](/migration/postmark) - [Amazon SES](/migration/ses) - [SendGrid](/migration/sendgrid) --- If you are moving an existing Resend integration, the SuperSend TX send flow maps closely: - Bearer API keys - `POST /emails` with a familiar JSON body - Webhooks / activity for delivery outcomes The main migration steps are: 1. swap the base URL 2. swap your API key to `stx_...` 3. verify a sending domain in SuperSend TX 4. update any provider-specific optional fields --- ## Quick mapping | Resend | SuperSend TX | |--------|---------------| | `https://api.resend.com` | `https://api.supersendtx.com` | | `re_...` API key | `stx_...` API key | | `POST /emails` | `POST /emails` | | `from` must be verified | `from` must be verified | | dashboard activity | dashboard activity + deliverability summary | --- ## Minimal curl diff ```bash 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": "It works.
" }' ``` --- ## Accepted payload aliases SuperSend TX accepts a few migration-friendly aliases on the HTTP send API: - `htmlBody` or `html_body` -> `html` - `textBody`, `text_body`, or `plain_body` -> `text` - `replyTo` -> `reply_to` - `scheduledAt` -> `scheduled_at` Attachment aliases are also accepted: - `filename` -> `name` - `contentType` -> `content_type` - `content` -> `data` - `contentId` -> `content_id` These aliases are meant to make low-friction migrations easier; new code should still prefer the canonical field names in docs/examples. --- ## Domain verification differences Unlike provider-managed sandbox products, SuperSend TX expects you to verify your own sending domain for production traffic. Before DNS is ready, you can still self-test with the shared sandbox sender: ```json { "from": "noreply@mail.supersendtx.com", "to": "you@example.com", "subject": "Sandbox check", "html": "Sandbox works.
" } ``` Sandbox restriction: - the sandbox `from` domain is only allowed when all recipients match the account email on the API key owner Once your own domain is verified, switch `from` back to your branded domain. --- ## DNS apply SuperSend TX can write DNS for you in two ways: - Cloudflare: save a token once under **Settings -> Integrations** - GoDaddy: paste one-time API credentials on the domain detail page, or pass them through the SDK/CLI locally See [`docs/api/domains.md`](./api/domains.md). --- ## SMTP If your old integration still depends on SMTP, see [`docs/api/smtp.md`](./api/smtp.md). Today, SuperSend TX does **not** mint account-scoped SMTP credentials; the recommended path is the HTTP send API. --- # Migration from Postmark Move transactional sends from Postmark to SuperSend TX without changing your product’s email jobs — receipts, password resets, alerts, and invites still go out over `POST /emails`. --- ## Why teams switch - **HTTP API + npm SDK** with a short path from API key to first send - **Owned transactional mail infrastructure**, not a thin layer on rented cloud email - **Sandbox → Pool → Dedicated** so you can test free, run production on a paid shared transactional network, then isolate on managed servers and IPs when you need allowlists --- ## Quick mapping | Postmark | SuperSend TX | |----------|--------------| | Server API token | `stx_...` API key (`Authorization: Bearer`) | | `https://api.postmarkapp.com` | `https://api.supersendtx.com` | | `POST /email` | `POST /emails` | | Verified Sender Signature / domain | Verified sending domain in SuperSend TX | | Message Streams (Transactional) | Transactional-only product (no cold/marketing mix) | | Webhooks | Webhooks + dashboard activity | --- ## Minimal send ```bash 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": "It works.
" }' ``` Node: ```bash npm install supersendtx ``` ```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: 'It works.
', }) ``` --- ## Migration checklist 1. Create a SuperSend TX account and API key 2. Add and verify your sending domain ([Domains](/domains)) 3. Point your app’s send client at `https://api.supersendtx.com` with `stx_...` 4. Map Postmark fields: `From` → `from`, `To` → `to`, `Subject` → `subject`, `HtmlBody` → `html`, `TextBody` → `text`, `ReplyTo` → `reply_to` 5. Reconfigure webhooks to SuperSend TX endpoints ([Webhooks](/webhooks)) 6. Send a canary through Sandbox or your verified domain, then cut over HTTP aliases accepted today: `htmlBody` / `html_body`, `textBody` / `text_body` / `plain_body`, `replyTo` → `reply_to`. Postmark’s PascalCase `HtmlBody` is **not** accepted — map it to `html` (or `htmlBody`) in your client. New code should use canonical names (`html`, `text`, `reply_to`). --- ## Domains and DNS Production `from` addresses must use a domain verified in SuperSend TX. Cloudflare and GoDaddy apply flows can write records for you — see [Domains](/domains). Before DNS is ready, self-test with the shared sandbox sender on `mail.supersendtx.com` (recipients limited to your account email). Details: [Quickstart](/quickstart). --- ## Related - [Migration from Resend](/migration) - [Migration from Amazon SES](/migration/ses) - [Quickstart](/quickstart) --- # Migration from Amazon SES If you send transactional mail through Amazon SES (SDK, SMTP, or a thin API on top of SES), you can move the application-facing send path to SuperSend TX while keeping the same jobs: auth mail, receipts, alerts, and notifications. --- ## What changes | SES-oriented setup | SuperSend TX | |--------------------|--------------| | AWS credentials / IAM | `stx_...` API key | | Regional SES endpoint | `https://api.supersendtx.com` | | `SendEmail` / `SendRawEmail` | `POST /emails` | | SES-verified identity | SuperSend TX verified domain | | Configuration sets / event destinations | Webhooks + dashboard activity | | Shared SES IP pools (typical) | Pool (owned transactional network) or Dedicated (managed servers + IPs) | SuperSend TX runs on **owned mail infrastructure**, not as a reseller of SES. That matters when you care who else shares the pipe — and when you later need Dedicated isolation. --- ## Minimal send ```bash 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": "It works.
" }' ``` ```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: 'It works.
', }) ``` --- ## Migration checklist 1. Sign up at [app.supersendtx.com](https://app.supersendtx.com) and create an API key 2. Verify your sending domain ([Domains](/domains)) — SPF, DKIM, return path 3. Replace SES SDK calls with SuperSend TX HTTP or the `supersendtx` npm package 4. Map bodies: HTML → `html`, text → `text`, reply addresses → `reply_to` 5. Point bounce/complaint/delivery handling at SuperSend TX [webhooks](/webhooks) 6. Run parallel canary sends, then shift production traffic --- ## Sandbox vs production - **Sandbox:** send from `noreply@mail.supersendtx.com` to your account email only while integrating - **Pro (from $20/mo):** production on the shared transactional network (10 domains) - **Scale:** volume tiers with declining overage (up to 1,000 domains) - **Dedicated (from $299/mo):** managed server and IPs when you need isolation See [Pricing](https://supersendtx.com/pricing) and [Quickstart](/quickstart). --- ## SMTP SES SMTP users: SuperSend TX does **not** currently issue account-scoped SMTP credentials. Prefer the HTTP API. Status: [SMTP](/smtp). --- ## Related - [Migration from Resend](/migration) - [Migration from Postmark](/migration/postmark) - [Quickstart](/quickstart) --- # Migration from SendGrid Move transactional sends from SendGrid to SuperSend TX — receipts, password resets, alerts, and invites still go out over `POST /emails` with a simpler JSON body than SendGrid's v3 mail send payload. --- ## Why teams switch - **Straightforward HTTP API** — one `POST /emails` instead of nested `personalizations` / `content` arrays - **Owned transactional mail infrastructure**, separate from cold/outbound reputation - **Sandbox → Pool → Dedicated** — test for free, run production on a shared transactional network, isolate on managed servers when you need allowlists --- ## Quick mapping | SendGrid | SuperSend TX | |----------|--------------| | `SG.` API key | `stx_…` API key (`Authorization: Bearer`) | | `https://api.sendgrid.com/v3/mail/send` | `https://api.supersendtx.com/emails` | | `personalizations[].to[]` | `to` (string or array) | | `from.email` + `from.name` | `from` (single address string) | | `content[]` with `type` / `value` | `html` and/or `text` | | Dynamic templates (`template_id`) | Template `alias` on send | | Event Webhook | Webhooks + dashboard activity | | ASM / unsubscribe groups | Managed unsubscribe + suppressions | --- ## Minimal send **SendGrid (v3):** ```bash curl -X POST https://api.sendgrid.com/v3/mail/send \ -H "Authorization: Bearer $SENDGRID_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "personalizations": [{ "to": [{ "email": "user@example.com" }] }], "from": { "email": "you@yourdomain.com" }, "subject": "Hello", "content": [{ "type": "text/html", "value": "It works.
" }] }' ``` **SuperSend TX:** ```bash 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": "It works.
" }' ``` --- ## Node.js **SendGrid:** ```ts import sgMail from '@sendgrid/mail' sgMail.setApiKey(process.env.SENDGRID_API_KEY!) await sgMail.send({ to: 'user@example.com', from: 'you@yourdomain.com', subject: 'Hello', html: 'It works.
', }) ``` **SuperSend TX:** ```ts 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: 'It works.
', }) ``` --- ## Webhooks SendGrid Event Webhook posts JSON arrays of events. SuperSend TX sends one signed JSON object per delivery with `SuperSendTX-Signature` (HMAC-SHA256). Map event names as follows: | SendGrid event | SuperSend TX | |----------------|--------------| | `processed` | `email.sent` | | `delivered` | `email.delivered` | | `deferred` | `email.delivery_delayed` | | `bounce` | `email.bounced` | | `dropped` | `email.failed` or `email.suppressed` | | `open` | `email.opened` | | `click` | `email.clicked` | | `spamreport` | `email.complained` | Use **Send test event** on the dashboard webhooks page (or `POST /emails/test`) to verify your handler before cutover. --- ## Checklist 1. Create a SuperSend TX API key (`stx_…`) 2. Add and verify your sending domain (SPF, DKIM, return-path) 3. Swap the client to `api.supersendtx.com` and map fields per table above 4. Recreate webhook endpoints and update signature verification 5. Send from Sandbox, then production after domain verify --- ## Compare Marketing overview: [SendGrid alternative](https://supersendtx.com/compare/sendgrid). --- # Password reset and verification emails Transactional auth mail — password resets, email verification, magic links — is a core SuperSend TX use case. Send them with `POST /emails` (or the npm SDK) from a verified domain. --- ## Recommended flow 1. Create an API key in the dashboard 2. Verify your sending domain ([Domains](/domains)) 3. When your app issues a reset or verify token, call SuperSend TX with the link in `html` / `text` 4. Optionally track delivery via [webhooks](/webhooks) --- ## Example: password reset ```js import { SuperSendTX } from 'supersendtx' const client = new SuperSendTX(process.env.SUPERSENDTX_API_KEY) export async function sendPasswordResetEmail({ to, resetUrl, }: { to: string resetUrl: string }) { return client.emails.send({ from: 'noreply@yourdomain.com', to, subject: 'Reset your password', html: `Reset your password:
If you did not request this, you can ignore this email.
`, text: `Reset your password: ${resetUrl}\n\nIf you did not request this, you can ignore this email.`, }) } ``` curl: ```bash curl -X POST https://api.supersendtx.com/emails \ -H "Authorization: Bearer $SUPERSENDTX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "from": "noreply@yourdomain.com", "to": "user@example.com", "subject": "Reset your password", "html": "" }' ``` --- ## Example: email verification ```js await client.emails.send({ from: 'noreply@yourdomain.com', to: user.email, subject: 'Verify your email', html: `Confirm your email:
`, text: `Confirm your email: ${verifyUrl}`, }) ``` --- ## Templates For repeated auth copy, store HTML in [Templates](/templates) and send with template variables instead of inlining markup every time. --- ## Auth providers (Supabase, Clerk, Auth.js) Those products often expect **custom SMTP**. SuperSend TX supports SMTP relay credentials ([SMTP](/smtp)) and HTTP hooks. For Supabase, see [Supabase Auth email](/guides/supabase). For Clerk and Auth.js, see [Auth provider email](/guides/auth-provider-email). --- ## Related - [Quickstart](/quickstart) - [Emails API](/emails) - [Supabase Auth email](/guides/supabase) - [Auth provider email](/guides/auth-provider-email) --- # Auth provider email (Supabase, Clerk, Auth.js) Many auth stacks let you bring your own email for magic links, verification, and password resets. SuperSend TX is built for that traffic over the **HTTP API**. > SuperSend TX supports **HTTP** (`POST /emails`) and **SMTP relay** ([SMTP](/smtp)). If a provider only supports custom SMTP, create an SMTP credential in the dashboard. For hooks and server routes, call the HTTP API instead. --- ## Pattern (all providers) 1. Verify `yourdomain.com` in SuperSend TX 2. Create an `stx_...` API key 3. In the auth provider’s **email hook**, **custom mailer**, or your app’s auth callback, send with SuperSend TX 4. Keep `from` on your verified domain ```js import { SuperSendTX } from 'supersendtx' const tx = new SuperSendTX(process.env.SUPERSENDTX_API_KEY) export async function sendAuthEmail({ to, subject, html, text, }: { to: string subject: string html: string text?: string }) { return tx.emails.send({ from: 'noreply@yourdomain.com', to, subject, html, text, }) } ``` --- ## Supabase Use the **Send Email** auth hook with an Edge Function that calls `POST /emails`, **or** configure [Supabase custom SMTP](/smtp) with a SuperSend TX SMTP credential (host `smtp.supersendtx.com`, username `supersendtx`). Full hook setup: **[Supabase Auth email](/guides/supabase)**. For local testing before your domain verifies, use the SuperSend TX sandbox sender limited to your account email ([Quickstart](/quickstart)). --- ## Clerk Clerk supports customized auth email in several ways (including SMTP on some plans). Prefer: 1. A **webhook or backend job** when Clerk would send mail, **or** 2. Clerk’s documented path for custom email delivery that invokes your server Your server: ```js await tx.emails.send({ from: 'noreply@yourdomain.com', to: emailAddress, subject: 'Sign in to your account', html: clerkProvidedHtmlOrYourTemplate, }) ``` If you must fill Clerk’s SMTP fields, use a SuperSend TX SMTP credential ([SMTP](/smtp)). Otherwise prefer HTTP from your app. --- ## Auth.js (NextAuth) In Auth.js, implement a custom `sendVerificationRequest` (or equivalent email provider) that calls SuperSend TX: ```js import { SuperSendTX } from 'supersendtx' const tx = new SuperSendTX(process.env.SUPERSENDTX_API_KEY) async function sendVerificationRequest({ identifier, url, provider }) { await tx.emails.send({ from: provider.from || 'noreply@yourdomain.com', to: identifier, subject: 'Sign in', html: ``, text: `Sign in: ${url}`, }) } ``` Wire that function into your Auth.js email provider config per Auth.js docs. --- ## Checklist - [ ] Domain verified in SuperSend TX - [ ] `from` matches that domain - [ ] Secrets only in server env (`SUPERSENDTX_API_KEY`) - [ ] Webhooks optional for delivery/bounce visibility - [ ] Sandbox used only for self-tests --- ## Related - [Password reset and verification emails](/guides/password-reset-emails) - [Emails API](/emails) - [Migration guides](/migration) --- # Supabase Auth email with SuperSend TX Send Supabase signup, magic link, password reset, and invite emails through SuperSend TX using the **Send Email** auth hook and an Edge Function. > SuperSend TX does **not** require the Send Email hook if your provider supports custom SMTP. Create an SMTP credential in the dashboard and paste host, username `supersendtx`, and password into Supabase → Authentication → SMTP. See [SMTP relay](/smtp). For hook-based delivery (Edge Functions), use the HTTP API (`POST /emails`) from your handler — the same pattern Supabase documents for other ESPs. --- ## When to use this - You built on **Supabase Auth** (often via Lovable, Vite, or Next.js) and want branded mail on your domain - You outgrew Supabase’s built-in SMTP limits or need delivery visibility in SuperSend TX - You want one transactional provider for auth mail **and** product mail (receipts, alerts) --- ## Architecture 1. User triggers auth (signup, reset, magic link, etc.) 2. Supabase Auth calls your **Send Email** hook (HTTPS Edge Function) 3. The function verifies the webhook signature, builds the message, and calls `POST https://api.supersendtx.com/emails` 4. Return `200` with `{}` so Supabase knows the email was handled Reference: [Supabase Send Email Hook](https://supabase.com/docs/guides/auth/auth-hooks/send-email-hook). --- ## Prerequisites 1. SuperSend TX account + `stx_…` API key 2. Verified sending domain (or Sandbox for self-tests only — see [Quickstart](/quickstart)) 3. Supabase project with the [Supabase CLI](https://supabase.com/docs/guides/cli) installed --- ## 1. Create the Edge Function ```bash supabase functions new send-email ``` `supabase/functions/send-email/index.ts`: ```ts import { Webhook } from 'https://esm.sh/standardwebhooks@1.0.0' const hookSecret = (Deno.env.get('SEND_EMAIL_HOOK_SECRET') ?? '').replace(/^v1,whsec_/, '') const apiKey = Deno.env.get('SUPERSENDTX_API_KEY') const fromEmail = Deno.env.get('SUPERSENDTX_FROM_EMAIL') ?? 'noreply@yourdomain.com' const projectRef = Deno.env.get('SUPABASE_PROJECT_REF') const subjects: RecordYour verification code is ${email_data.token}
` : `` const text = action === 'reauthentication' ? `Your verification code is ${email_data.token}` : `${subject}: ${link}` const res = await fetch('https://api.supersendtx.com/emails', { method: 'POST', headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ from: fromEmail, to: user.email, subject, html, text, }), }) if (!res.ok) { const body = await res.text() throw new Error(`SuperSend TX ${res.status}: ${body}`) } } catch (error) { console.error(error) return new Response(JSON.stringify({ error: String(error) }), { status: 500, headers: { 'Content-Type': 'application/json' }, }) } return new Response(JSON.stringify({}), { status: 200, headers: { 'Content-Type': 'application/json' }, }) }) ``` Customize subjects and HTML (or render [React Email](/guides/react-email) in the function) for production. --- ## 2. Set secrets and deploy `supabase/functions/.env` (local) — do not commit: ```bash SUPERSENDTX_API_KEY=stx_your_key_here SUPERSENDTX_FROM_EMAIL=noreply@yourdomain.com SUPABASE_PROJECT_REF=your-project-ref SEND_EMAIL_HOOK_SECRET=v1,whsec_... # from Supabase dashboard after step 3 ``` ```bash supabase secrets set --env-file supabase/functions/.env supabase functions deploy send-email --no-verify-jwt ``` Note the deployed function URL (e.g. `https://Hi Ada
', }) ``` Or use a published [dashboard template](/templates) with `template: { id | alias, variables }`. --- ## Troubleshooting | Symptom | Fix | |---------|-----| | Error about `@react-email/render` | `npm install @react-email/render react` | | `403` unverified domain | Verify DNS or use sandbox `from` / account `to` | | Want MCP / agents | [MCP server](/ai/mcp) · [Agent Skills](/ai/agent-skills) — agents should link React Email’s own skills for authoring | --- ## Related - [Templates API](/templates) — server-side aliases and variables - [Password reset emails](/guides/password-reset-emails) - [Node.js](/frameworks/node) · [Next.js](/frameworks/nextjs) - React Email docs: [react.email](https://react.email) --- # AI app builders Use SuperSend TX in Lovable, Replit, Bolt, Base44, v0, and similar AI builders. Add your `stx_…` API key as a secret, paste the builder prompt, and let the agent wire `POST /emails`. ## Pick your builder | Builder | Best for | Guide | |---------|----------|-------| | [Lovable](/builders/lovable) | React + Supabase apps, chat-driven features | Secrets + agent prompt | | [Replit](/builders/replit) | Full-stack Replit Agent projects | Replit Secrets + agent prompt | | [Bolt.new](/builders/bolt) | Vite / React prototypes from chat | `.env` + agent prompt | | [Base44](/builders/base44) | Base44 apps with optional custom email | When to use TX vs built-in mail | | [v0](/builders/v0) | Next.js from Vercel v0 | Route Handler + Vercel env | ## Before you paste a prompt 1. Create a [SuperSend TX account](https://app.supersendtx.com) and an API key (`stx_…`). 2. Store it as **`SUPERSENDTX_API_KEY`** in the builder’s secrets / env UI (server-side only). 3. For a first send before your domain verifies, use the sandbox rules in [Quickstart](../quickstart.md) and [Agent skill notes](../ai/agent-skill.md). ## Standard env var ```bash SUPERSENDTX_API_KEY=stx_your_key_here ``` Some builders also accept `STX_API_KEY` — if their UI suggests that name, map it to the same `stx_…` value. Prefer `SUPERSENDTX_API_KEY` in generated code for consistency with our SDK and docs. ## Reference - [Agent skill notes](../ai/agent-skill.md) — integration defaults for AI agents - [OpenAPI](../openapi.yaml) — API contract - [Next.js](../frameworks/nextjs.md) — server-side send pattern - [Auth provider email](../guides/auth-provider-email.md) — Clerk / Auth.js hooks - [Supabase Auth email](../guides/supabase.md) — Send Email hook + Edge Function --- # SuperSend TX + Lovable Add transactional email to a Lovable app using your SuperSend TX API key and a chat prompt. ## When to use SuperSend TX - Password reset, verification, receipts, and other **transactional** mail - Branded `from` on your own domain after DNS verify - Supabase Auth hooks or Edge Functions that should call an HTTP API instead of SMTP Lovable projects often use Supabase — see [Supabase Auth email](../guides/supabase.md) for the Send Email hook and Edge Function setup. ## 1. Add your API key 1. Open [app.supersendtx.com](https://app.supersendtx.com) → **API Keys** → create a key (`stx_…`). 2. In Lovable, open your project **Settings** → **Secrets** (or the env/secrets panel Lovable exposes for backend code). 3. Add: ```text SUPERSENDTX_API_KEY=stx_your_key_here ``` Use the secret name exactly — server routes and Edge Functions should read `process.env.SUPERSENDTX_API_KEY`. Never put the key in client-side React components. ## 2. Paste this prompt in Lovable chat ```text Integrate SuperSend TX transactional email into this app. Docs (read first): - https://docs.supersendtx.com/guides/supabase - https://docs.supersendtx.com/ai/agent-skill - https://docs.supersendtx.com/openapi.yaml - https://docs.supersendtx.com/builders/lovable Rules: 1. Store the API key in SUPERSENDTX_API_KEY (already in Lovable Secrets). Never expose stx_ keys in the browser. 2. Send via POST https://api.supersendtx.com/emails with Authorization: Bearer $SUPERSENDTX_API_KEY. 3. Until our domain is verified, sandbox sends must use from "noreply@mail.supersendtx.com" and to only our account email. 4. Add a server-side send path (Supabase Edge Function, API route, or backend helper) for password-reset / verification email. 5. Use canonical fields: html, text, reply_to. Prefer npm package supersendtx if the backend is Node. After domain verify in SuperSend TX, switch from to noreply@ourdomain.com. ``` Replace “our account email” with the email on your SuperSend TX account if the agent asks. ## 3. Minimal server send (Node / Edge) ```ts const res = await fetch('https://api.supersendtx.com/emails', { method: 'POST', headers: { Authorization: `Bearer ${process.env.SUPERSENDTX_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ from: 'noreply@yourdomain.com', to: 'user@example.com', subject: 'Verify your email', html: 'Click the link to verify.
', }), }) ``` Or install `supersendtx` and use the SDK — see [Next.js](../frameworks/nextjs.md). ## Sandbox self-test Before DNS verify: ```json { "from": "noreply@mail.supersendtx.com", "to": "YOUR_ACCOUNT_EMAIL", "subject": "SuperSend TX sandbox check", "html": "It works.
" } ``` ## Production 1. Add your domain in the SuperSend TX dashboard. 2. Apply DNS (Cloudflare integration or registrar credentials). 3. Verify, then update `from` to an address on that domain. ## Links - [Quickstart](../quickstart.md) - [Domains API](../api/domains.md) - [Password reset guide](../guides/password-reset-emails.md) - [Supabase Auth email](../guides/supabase.md) --- # SuperSend TX + Replit Wire SuperSend TX into a Replit Agent project with **Replit Secrets** and a copy-paste agent prompt. ## When to use SuperSend TX - Replit Agent builds that need password reset, invites, or notifications - Node, Python, or other backends where you control server env vars - Production mail from your own domain after verify ## 1. Add your API key 1. Create an API key at [app.supersendtx.com](https://app.supersendtx.com) (`stx_…`). 2. In Replit, open **Tools** → **Secrets** (or **Integrations** → secrets, depending on Replit UI). 3. Create a secret: | Key | Value | |-----|-------| | `SUPERSENDTX_API_KEY` | `stx_your_key_here` | Replit injects secrets as environment variables in the repl runtime. Access via `process.env.SUPERSENDTX_API_KEY` (Node) or `os.environ["SUPERSENDTX_API_KEY"]` (Python). ## 2. Paste this prompt in Replit Agent ```text Integrate SuperSend TX transactional email into this Replit project. Docs: - https://docs.supersendtx.com/ai/agent-skill - https://docs.supersendtx.com/openapi.yaml - https://docs.supersendtx.com/builders/replit Rules: 1. Read SUPERSENDTX_API_KEY from Replit Secrets (already configured). Never log or expose the key to the client. 2. Send with POST https://api.supersendtx.com/emails and Authorization: BearerThanks for your order.
" } ``` ## Production checklist - [ ] Domain added and verified in SuperSend TX - [ ] `from` uses verified domain - [ ] API key only in secrets, not in frontend - [ ] Bounce/complaint handling via [webhooks](../api/webhooks.md) if needed ## Links - [Quickstart](../quickstart.md) - [Domains](../api/domains.md) - [Auth provider email](../guides/auth-provider-email.md) --- # SuperSend TX + v0 (Vercel) v0 generates Next.js apps. Run SuperSend TX from a **Route Handler or Server Action** and store `SUPERSENDTX_API_KEY` in Vercel environment variables. ## When to use SuperSend TX - v0 apps deployed to Vercel that need password reset, magic links, or receipts - Server Components / Route Handlers — same pattern as [Next.js](../frameworks/nextjs.md) - Production sends from your verified domain ## 1. Add your API key **Local** — `.env.local`: ```bash SUPERSENDTX_API_KEY=stx_your_key_here ``` **Vercel** — Project → **Settings** → **Environment Variables**: | Name | Environments | |------|----------------| | `SUPERSENDTX_API_KEY` | Production, Preview, Development | Redeploy after adding the variable. ## 2. Paste this prompt in v0 chat ```text Integrate SuperSend TX transactional email into this Next.js app. Docs: - https://docs.supersendtx.com/ai/agent-skill - https://docs.supersendtx.com/frameworks/nextjs - https://docs.supersendtx.com/openapi.yaml - https://docs.supersendtx.com/builders/v0 Rules: 1. SUPERSENDTX_API_KEY is server-only (process.env) — never use NEXT_PUBLIC_ for the API key. 2. Send via POST https://api.supersendtx.com/emails or npm package supersendtx from a Route Handler / Server Action. 3. Sandbox: from "noreply@mail.supersendtx.com", to account email only until domain verify. 4. Add app/api/... route or server action for at least one transactional email flow. 5. Use html, text, reply_to. Follow Next.js server patterns — no client-side stx_ keys. Document that Vercel env var SUPERSENDTX_API_KEY must be set before deploy. ``` ## 3. Route Handler example Create `app/api/email/send/route.ts`: ```ts import { NextResponse } from 'next/server' import { SuperSendTX } from 'supersendtx' const tx = new SuperSendTX(process.env.SUPERSENDTX_API_KEY!) export async function POST(request: Request) { const body = await request.json() const result = await tx.emails.send({ from: body.from ?? 'noreply@yourdomain.com', to: body.to, subject: body.subject, html: body.html, text: body.text, }) return NextResponse.json(result) } ``` Install: `npm install supersendtx` ## Sandbox Until your domain verifies, test with the sandbox sender and your SuperSend TX account email — see [Agent skill notes](../ai/agent-skill.md). ## Production 1. Verify domain in SuperSend TX dashboard. 2. Set production `from` to your domain. 3. Confirm `SUPERSENDTX_API_KEY` is set on Vercel Production. ## Links - [Next.js guide](../frameworks/nextjs.md) - [Quickstart](../quickstart.md) - [OpenAPI](../openapi.yaml) --- # Emails Send transactional email and list recent sends. Migrating from Resend? See [`docs/migration.md`](../migration.md). --- ## Send email `POST /emails` Send a transactional email from a verified domain. Base URL: `https://api.supersendtx.com` --- ## Authentication ```http 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) | | `unsubscribe` | `boolean` | No | Opt in to managed unsubscribe (see below). Off by default for transactional mail. | \* At least one of `html` or `text` is required. ### Managed unsubscribe (opt-in) Pure transactional mail (password resets, receipts, security alerts) should leave `unsubscribe` off. When `unsubscribe: true`, SuperSend TX: - Injects RFC 8058 `List-Unsubscribe` and `List-Unsubscribe-Post` headers (one-click unsubscribe) - Replaces `{{unsubscribe_url}}` in `subject`, `html`, and `text` with a signed confirmation link - Binds the link to the first `to` address for that message When sending with a published template, the template's `unsubscribe_enabled` flag is used unless you pass `unsubscribe` explicitly on the send request. ```json { "from": "you@yourdomain.com", "to": "user@example.com", "subject": "Product updates", "html": "Hi there.
", "unsubscribe": true } ``` ### Example ```json { "from": "you@yourdomain.com", "to": "user@example.com", "subject": "Hello from SuperSend TX", "html": "It works.
" } ``` With display name: ```json { "from": { "email": "you@yourdomain.com", "name": "Your App" }, "to": ["user@example.com", "other@example.com"], "subject": "Hello", "html": "Hi
", "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: ```json { "from": "noreply@mail.supersendtx.com", "to": "owner@example.com", "subject": "Sandbox check", "html": "Sandbox works.
" } ``` The sandbox sender is limited to the account email attached to the API key owner. --- ## Responses ### 200 — Accepted ```json { "id": "msg_abc123…", "status": "sent" } ``` Scheduled sends return: ```json { "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`: ```http Idempotency-Key: order-123 ``` Keys are scoped per account, retained for **24 hours**. Replays return the original response. Reusing a key with a different body returns **409** `idempotency_conflict`. ```ts await client.emails.send({ …, idempotencyKey: 'order-123' }) ``` --- ## Retrieve email `GET /emails/{id}` Returns one send by public id (`msg_…`). ```ts 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: ```ts await client.emails.resend('msg_abc123…') ``` CLI: ```bash 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: ```json { "from": "you@yourdomain.com", "to": "user@example.com", "subject": "Tomorrow", "html": "See you tomorrow.
", "scheduled_at": "2026-08-01T12:00:00.000Z" } ``` Scheduled emails can be updated only while their status is `scheduled`: ```http PATCH /emails/msg_abc123… ``` ```json { "scheduled_at": "2026-08-01T13:00:00.000Z" } ``` Cancel a scheduled email: ```json { "cancel": true } ``` SDK: ```ts await client.emails.update('msg_abc123…', { scheduledAt: '2026-08-01T13:00:00.000Z' }) await client.emails.cancel('msg_abc123…') ``` CLI: ```bash 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: ```json { "emails": [ { "from": "you@yourdomain.com", "to": "user@example.com", "subject": "Hello", "html": "Hi
" } ] } ``` The response is index-aligned: ```json { "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: ```ts 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 ```json { "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 ```ts const { emails, next_cursor } = await client.emails.list({ limit: 10 }) ``` ### Error format All errors return: ```json { "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 ```bash 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":"Hi
"}' ``` ### Node.js ```ts 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: 'Hi
', }) ``` Throws `SuperSendTXError` on failure (`error.status`, `error.message`, `error.details`). ### CLI ```bash supersendtx emails send \ --from you@yourdomain.com \ --to user@example.com \ --subject "Hello" \ --html "Hi
" \ --tag order_id=ord_123 \ --schedule 2026-08-01T12:00:00.000Z ``` Requires `SUPERSENDTX_API_KEY` or `--api-key`. --- ## OpenAPI Machine-readable spec: [`openapi/supersendtx.yaml`](../../openapi/supersendtx.yaml) --- # Domains API Manage sending domains, DNS verification, inbound receiving flags, tracking preferences, TLS mode, one-click DNS apply, and DMARC/BIMI guidance. Base URL: `https://api.supersendtx.com` Auth: ```http Authorization: Bearer stx_... ``` --- ## Create a domain `POST /domains` ```bash curl -X POST https://api.supersendtx.com/domains \ -H "Authorization: Bearer $SUPERSENDTX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "example.com" }' ``` Success response: ```json { "domain": { "id": "d_123", "name": "example.com", "status": "pending", "created_at": "2026-07-26T00:00:00.000Z", "verified_at": null, "open_tracking": false, "click_tracking": false, "tls_mode": "opportunistic" }, "records": [ { "type": "TXT", "host": "_supersendtx.example.com", "value": "supersendtx-verify=...", "purpose": "Domain ownership" } ] } ``` To request inbound receiving during creation, include `"inbound_enabled": true`. The response will also include `inbound_records` (MX) and `inbound_note`. Full receiving flow: [`docs/api/inbound.md`](./inbound.md). Expected DNS records (after create syncs with the mail server): - ownership TXT: `_supersendtx.example.com` - DKIM TXT: Postal selector host such as `ss-abc123._domainkey.example.com` with Postal's real public key - return-path CNAME: `rp.example.com` → `rp.core.superesp.com` (DNS only / not proxied) - SPF include: `include:spf.supersendtx.com` - DMARC starter record SuperSend TX registers the domain on the shared Postal TX server at create time and replaces placeholder DKIM with Postal's signing records before apply/verify. ### Cross-team claim conflict If the domain is already attached to another SuperSend TX team, the API returns **409** with claim instructions: ```json { "error": { "message": "Domain already belongs to another SuperSend TX team. Remove it from the current team or contact support to claim it.", "code": "conflict", "details": { "reason": "domain_claim_required", "domain": "example.com", "instructions": [ "Ask the current SuperSend TX team admin to remove the domain if you still have access.", "If you own the domain but no longer control the original team, contact support and include proof of DNS control." ] } } } ``` --- ## Get a domain `GET /domains/{id}` Returns the domain, required DNS records, inbound MX guidance, and best-effort DMARC/BIMI analysis: ```json { "domain": { "id": "d_123", "name": "example.com", "status": "verified", "created_at": "2026-07-26T00:00:00.000Z", "verified_at": "2026-07-26T00:05:00.000Z", "open_tracking": true, "click_tracking": false, "tls_mode": "enforced", "inbound_enabled": true, "inbound_status": "active", "inbound_error": null }, "records": [], "inbound_records": [ { "type": "MX", "host": "example.com", "priority": 10, "value": "mx.core.superesp.com", "purpose": "Inbound receiving" } ], "inbound_note": "Inbound receiving requires pointing this hostname's MX record to SuperSend TX. That conflicts with any existing mailbox provider on the same hostname, so use a dedicated subdomain such as inbound.example.com when Google Workspace or Microsoft 365 should keep handling your main mailboxes.", "analysis": { "dmarc": { "host": "_dmarc.example.com", "configured": true, "record": "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com", "policy": "quarantine", "rua": ["mailto:dmarc@example.com"], "guidance": "DMARC is enforced. Keep report mailboxes monitored and tighten alignment as you roll out BIMI." }, "bimi": { "host": "default._bimi.example.com", "configured": false, "record": null, "location": null, "authority": null, "requires_dmarc_enforcement": false, "guidance": "Optional: add a BIMI record at default._bimi once your branded SVG logo and optional VMC are ready." } } } ``` ### DMARC/BIMI notes - **DMARC** is recommended for every sending domain. - **BIMI** is optional, but most mailbox providers expect DMARC enforcement (`p=quarantine` or `p=reject`) before BIMI is effective. - `analysis` is advisory. It does not block sending, and it does not replace your own deliverability monitoring. --- ## Verify DNS `POST /domains/{id}` ```json { "action": "verify" } ``` When ownership, SPF, Postal DKIM, and the return-path CNAME are visible in public DNS, SuperSend TX asks the mail server to re-check delivery DNS and marks the domain verified only when mail-server **DKIM** and **return-path** statuses are OK. That step activates customer-domain DKIM signing (`d=yourdomain`) so DMARC can pass. Without DKIM OK, mail would fall back to the shared pool signer. DMARC is reported back but does not currently block verification. Re-running verify on an already-verified domain re-checks mail-server DKIM (useful after DNS propagation). Success responses include: ```json { "verified": true, "signing_ready": true, "postal_signing": { "dkim_ok": true, "return_path_ok": true, "dkim_status": "OK", "return_path_status": "OK" } } ``` If public DNS looks correct but the mail server has not yet accepted the DKIM TXT or return-path CNAME, verify returns **400** with `postal_signing.dkim_ok` / `return_path_ok` reflecting the failure — wait for propagation and verify again. --- ## Apply DNS `POST /domains/{id}` ### Cloudflare via stored dashboard token ```json { "action": "apply", "provider": "cloudflare" } ``` ### Cloudflare via inline credentials ```json { "action": "apply", "provider": "cloudflare", "credentials": { "apiToken": "cf_...", "zoneId": "..." } } ``` ### GoDaddy via one-time credentials ```json { "action": "apply", "provider": "godaddy", "credentials": { "apiKey": "gd_key", "apiSecret": "gd_secret" } } ``` GoDaddy credentials are used for that request only and are **not stored** by SuperSend TX. Response shape: ```json { "provider": "godaddy", "domain": "example.com", "results": [ { "purpose": "SPF", "host": "example.com", "action": "merged", "detail": "v=spf1 include:spf.supersendtx.com ~all" } ] } ``` --- ## Update tracking, inbound, and TLS preferences `PATCH /domains/{id}` ```bash curl -X PATCH https://api.supersendtx.com/domains/example.com \ -H "Authorization: Bearer $SUPERSENDTX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "inbound_enabled": true, "open_tracking": true, "click_tracking": true, "tls_mode": "enforced" }' ``` Aliases `openTracking`, `clickTracking`, `tlsMode`, and `inboundEnabled` are also accepted. ### Inbound enablement - `inbound_enabled: true` marks the domain for receiving. - Before verification, inbound stays `pending`. - After verification, SuperSend TX activates inbound receiving and updates `inbound_status` to `active` or `error`. - See [`docs/api/inbound.md`](./inbound.md) for received-email retrieval and `email.received` webhooks. ### TLS modes - `opportunistic` — use TLS when the downstream mail path supports it. - `enforced` — require TLS for the downstream mail path. ### Tracking and TLS preferences `open_tracking`, `click_tracking`, and `tls_mode` are stored on the domain immediately when you update them. When open or click tracking is enabled: 1. SuperSend TX provisions a Postal track domain for your hostname. 2. The domain detail response includes a **tracking CNAME** (`ps.yourdomain.com` → `track.core.superesp.com`). 3. Apply and verify DNS so Postal can rewrite links and inject open pixels. 4. `tracking_dns.ok` in `GET /domains/{id}` reports whether the CNAME is live. If platform mail-server admin credentials are missing, settings are still saved but `tracking_postal_error` may be returned on `PATCH`. --- ## SDK ```ts import { SuperSendTX } from 'supersendtx' const client = new SuperSendTX(process.env.SUPERSENDTX_API_KEY!) await client.domains.create({ name: 'example.com' }) await client.domains.apply('example.com') await client.domains.apply('example.com', { provider: 'godaddy', credentials: { apiKey: process.env.GODADDY_API_KEY!, apiSecret: process.env.GODADDY_API_SECRET!, }, }) await client.domains.verify('example.com') const detail = await client.domains.get('example.com') const updated = await client.domains.update('example.com', { open_tracking: true, tls_mode: 'enforced', }) ``` --- ## CLI ```bash supersendtx domains add example.com supersendtx domains apply example.com --provider cloudflare GODADDY_API_KEY=... GODADDY_API_SECRET=... supersendtx domains apply example.com --provider godaddy supersendtx domains verify example.com ``` --- ## Delete a domain `DELETE /domains/{id}` Removes the domain from your account and revokes sending authorization for that hostname. ```bash supersendtx domains delete example.com ``` If upstream teardown fails, the domain is kept and the API returns **502**. --- ## Common errors | Status | Meaning | |--------|---------| | 400 | invalid domain, DNS not ready, missing provider credentials | | 401 | missing or invalid auth | | 403 | domain limit reached | | 404 | domain not found | | 409 | domain already exists or is already claimed | | 502 | Domain registration, teardown, or DNS provider API failed | Full contract: [`openapi/supersendtx.yaml`](../../openapi/supersendtx.yaml) --- # Webhooks Receive signed HTTP callbacks for email lifecycle events. Base URL: `https://api.supersendtx.com` Manage endpoints in the dashboard (**Webhooks**) or via the API / SDK / CLI below. --- ## Authentication ```http Authorization: Bearer stx_… ``` Dashboard session cookies also work for browser requests to `/api/webhooks`. --- ## Supported events | Event | When fired | |-------|------------| | `email.received` | An inbound email arrived on a receive-enabled domain; retrieve full content from `/received-emails/{id}` | | `email.sent` | SuperSend TX accepted the message for delivery | | `email.delivered` | The message was delivered to the recipient mailbox provider | | `email.delivery_delayed` | Delivery was delayed or temporarily held | | `email.bounced` | Hard/soft bounce; recipient is auto-suppressed | | `email.complained` | Recipient marked the message as spam/complaint | | `email.opened` | Open pixel loaded when open tracking is on | | `email.clicked` | Tracked link clicked when click tracking is on | | `email.failed` | Delivery failed; permanent SMTP failures also auto-suppress the recipient | | `email.suppressed` | Send blocked because a recipient is on the suppression list | | `email.scheduled` | Email accepted with `scheduled_at` | | `contact.unsubscribed` | Recipient completed a managed unsubscribe; address added to suppressions | | `automation.started` | An active automation matched an incoming event and a run was created | | `automation.step_completed` | One automation step completed successfully | | `automation.completed` | A run finished all steps (or ended early on a false condition) | | `automation.failed` | A run failed (send failure, timeout, validation, etc.) | Open/click tracking are domain settings (`open_tracking` / `click_tracking`) configured per domain. --- ## Create endpoint `POST /webhooks` ```json { "url": "https://yourapp.com/webhooks/supersendtx", "events": ["email.delivered", "email.bounced"] } ``` `events` is optional — defaults to all supported events. ### 200 — Created ```json { "webhook": { "id": "clx…", "url": "https://yourapp.com/webhooks/supersendtx", "events": ["email.delivered", "email.bounced"], "enabled": true, "created_at": "2026-07-25T12:00:00.000Z", "updated_at": "2026-07-25T12:00:00.000Z" }, "secret": "whsec_…" } ``` Copy `secret` immediately — it is only returned once. Use it to verify incoming webhook signatures. --- ## List endpoints `GET /webhooks` Cursor pagination: `limit`, `cursor` → `{ webhooks, has_more, next_cursor }`. --- ## Retrieve endpoint `GET /webhooks/{id}` ```json { "webhook": { "id": "clx…", "url": "https://yourapp.com/webhooks/supersendtx", "events": ["email.delivered", "email.bounced"], "enabled": true, "created_at": "2026-07-25T12:00:00.000Z", "updated_at": "2026-07-25T12:00:00.000Z" } } ``` --- ## Update endpoint `PATCH /webhooks/{id}` ```json { "url": "https://yourapp.com/new-path", "events": ["email.bounced"], "enabled": false } ``` All fields are optional. --- ## Delete endpoint `DELETE /webhooks/{id}` ```json { "ok": true } ``` --- ## Test sink `POST /emails/test` (full-scope API key) ```json { "event": "email.bounced", "email_id": "msg_…", "deliver": true } ``` Builds a webhook payload (optionally for an existing email) and, when `deliver` is not `false`, enqueues delivery to your subscribed endpoints. Useful in CI. --- ## Incoming webhook payload SuperSend TX `POST`s JSON to your endpoint URL when a subscribed event occurs. ### Email event example ```json { "type": "email.received", "created_at": "2026-07-25T12:05:00.000Z", "data": { "email_id": "inb_abc123…", "to": ["sales@inbound.example.com"], "from": "SenderHi {{name}}
", "text": "Hi {{name}}", "variables": ["name"], "published_at": "2026-07-26T12:00:00.000Z", "created_at": "2026-07-26T11:00:00.000Z", "updated_at": "2026-07-26T12:00:00.000Z" } ], "has_more": false, "next_cursor": null } ``` --- ## Create `POST /templates` → **201** ```json { "name": "Welcome", "alias": "welcome", "subject": "Hello {{name}}", "html": "Hi {{name}}
", "text": "Hi {{name}}", "variables": ["name"] } ``` Creates a **draft**. Publish before sending. --- ## Starter catalog `GET /templates/starters` — list copyable starters (full-scope key). `POST /templates/from-starter` — copy one into your account as **published** with a fixed alias. | Alias | Variables | |-------|-----------| | `password-reset` | `name`, `reset_url` | | `email-verification` | `name`, `verify_url`, `code` | | `welcome` | `name`, `dashboard_url` | | `invoice` | `name`, `amount`, `invoice_url`, `invoice_id` | | `team-invite` | `name`, `inviter_name`, `team_name`, `invite_url` | ```bash curl -X POST https://api.supersendtx.com/templates/from-starter \ -H "Authorization: Bearer $SUPERSENDTX_API_KEY" \ -H "Content-Type: application/json" \ -d '{"alias":"password-reset"}' ``` ```ts await client.templates.fromStarter('password-reset') await client.emails.send({ from: 'noreply@yourdomain.com', to: 'user@example.com', template: { id: 'password-reset', variables: { name: 'Ada', reset_url: 'https://app.example.com/reset?token=…' }, }, }) ``` Dashboard: **Templates → Start from a template**. Returns **409** if the name or alias already exists on the account. --- ## Retrieve / update / delete - `GET /templates/{id}` — UUID or alias - `PATCH /templates/{id}` — update fields - `DELETE /templates/{id}` --- ## Publish / duplicate `POST /templates/{id}` ```json { "action": "publish" } ``` ```json { "action": "duplicate", "name": "Welcome (copy)" } ``` Duplicate creates a new **draft** (alias cleared). `name` is optional (defaults to `… (copy)`). --- ## Send with a template `POST /emails` ```json { "from": "you@yourdomain.com", "to": "user@example.com", "template": { "id": "welcome", "variables": { "name": "Ada" } } } ``` `template` is mutually exclusive with `html` / `text`. Subject comes from the template unless you pass `subject` to override. Only **published** templates can be used. --- ## SDK ```ts import { SuperSendTX } from 'supersendtx' const client = new SuperSendTX(process.env.SUPERSENDTX_API_KEY!) const { template } = await client.templates.create({ name: 'Welcome', alias: 'welcome', subject: 'Hello {{name}}', html: 'Hi {{name}}
', }) await client.templates.publish(template.id) await client.emails.send({ from: 'you@yourdomain.com', to: 'user@example.com', template: { id: 'welcome', variables: { name: 'Ada' } }, }) ``` ### React Email (optional peer) Install `@react-email/render` (and `react`) to pass a React element: ```bash npm install @react-email/render react ``` ```ts await client.emails.send({ from: 'you@yourdomain.com', to: 'user@example.com', subject: 'Hello', react: EmailComponent({ name: 'Ada' }), }) ``` The SDK compiles `react` to HTML before `POST /emails`. Mutually exclusive with `html` / `text` / `template`. Full guide: [Send React Email](/guides/react-email). --- ## CLI ```bash supersendtx templates list supersendtx templates starters supersendtx templates from-starter password-reset supersendtx templates create --name Welcome --subject "Hi {{name}}" --html "Hi {{name}}
" --alias welcome ``` --- ## OpenAPI [`openapi/supersendtx.yaml`](../../openapi/supersendtx.yaml) --- # Events Send custom events into SuperSend TX to trigger transactional automations. Base URL: `https://api.supersendtx.com` --- ## Authentication ```http Authorization: Bearer stx_… ``` Dashboard session cookies also work for browser requests to `/api/events`, which is how the automations canvas editor sends test events. --- ## Trigger an event `POST /events` ```json { "name": "user.created", "user_id": "user_123", "email": "user@example.com", "data": { "name": "Ada Lovelace", "plan": "pro" } } ``` `type` is accepted as an alias for `name`. ### Idempotency Use `Idempotency-Key` for replay-safe retries: ```http Idempotency-Key: evt_user_created_123 ``` Retries with the same key and body return the original response. Reusing the key with a different body returns HTTP `409`. ### 202 Accepted ```json { "event": { "id": "ae_123", "name": "user.created", "user_id": "user_123", "email": "user@example.com", "data": { "name": "Ada Lovelace", "plan": "pro" }, "source": "api", "created_at": "2026-07-26T12:00:00.000Z" }, "matched_automations": 2, "resumed_runs": 1 } ``` - `matched_automations` = active automations whose trigger matched this event - `resumed_runs` = waiting runs resumed by this event (`wait_for_event`) --- ## Event shape | Field | Type | Notes | |------|------|-------| | `name` | string | Required unless `type` is provided | | `type` | string | Alias for `name` | | `user_id` | string | Optional identity hint for wait/resume matching | | `email` | string | Optional identity hint for wait/resume matching | | `data` | object | Optional event payload used by conditions and email templates | Inside automations, you can reference: - `{{event.name}}` - `{{event.email}}` - `{{event.user_id}}` - `{{event.data.foo}}` --- ## Typical flow 1. Create an automation (dashboard canvas, `POST /automations`, or `supersendtx automations create`) with trigger `user.created` 2. Activate it (`POST /automations/{id}` with `{ "action": "activate" }`) 3. Send `POST /events` from your app when that business event happens 4. SuperSend TX queues the run in Bull/Redis 5. Send-email steps flow through the same transactional send path as `POST /emails` See also [`docs/api/automations.md`](./automations.md). --- ## SDK ```ts import { SuperSendTX } from 'supersendtx' const client = new SuperSendTX(process.env.SUPERSENDTX_API_KEY!) await client.events.trigger({ name: 'user.created', user_id: 'user_123', email: 'user@example.com', data: { name: 'Ada Lovelace' }, idempotencyKey: 'evt_user_created_123', }) ``` --- ## CLI ```bash SUPERSENDTX_API_KEY=$SUPERSENDTX_API_KEY npx -y --package=supersendtx-cli -- supersendtx events send \ --name user.created \ --email user@example.com \ --user-id user_123 \ --data '{"name":"Ada Lovelace"}' ``` --- ## OpenAPI Machine-readable spec: [`openapi/supersendtx.yaml`](../../openapi/supersendtx.yaml) --- # Automations Create and manage event-driven transactional automations with a Bearer `stx_…` API key (or dashboard session). Base URL: `https://api.supersendtx.com` You can also build flows visually in the dashboard canvas under **Automations**. --- ## Authentication ```http Authorization: Bearer stx_… ``` --- ## Create an automation `POST /automations` Creates a **draft**. Activate it before events will match. ```json { "name": "Welcome email", "trigger": { "type": "event", "event": "user.created" }, "steps": [ { "type": "send_email", "email": { "from": "you@yourdomain.com", "to": "{{event.email}}", "subject": "Welcome", "html": "Hi {{event.data.name}}
" } } ] } ``` Examples below are generated from `src/lib/dx/snippets.ts` (same source as the dashboard). ### curl ```bash curl -X POST https://api.supersendtx.com/automations \ -H "Authorization: Bearer stx_…" \ -H "Content-Type: application/json" \ -d '{"name":"Welcome email","trigger":{"type":"event","event":"user.created"},"steps":[{"type":"send_email","email":{"from":"you@yourdomain.com","to":"{{event.email}}","subject":"Welcome","html":"Hi {{event.data.name}}
"}}]}' ``` ### npm ```ts npm install supersendtx import { SuperSendTX } from 'supersendtx' const client = new SuperSendTX('stx_…') const { automation } = await client.automations.create({ name: 'Welcome email', trigger: { type: 'event', event: 'user.created' }, steps: [ { type: 'send_email', email: { from: 'you@yourdomain.com', to: '{{event.email}}', subject: 'Welcome', html: 'Hi {{event.data.name}}
', }, }, ], }) await client.automations.activate(automation.id) ``` ### CLI ```bash SUPERSENDTX_API_KEY=stx_… npx -y --package=supersendtx-cli -- supersendtx automations create --file ./welcome.json SUPERSENDTX_API_KEY=stx_… npx -y --package=supersendtx-cli -- supersendtx automations activate --id "$AUTOMATION_ID" ``` `welcome.json` should match the request body above. --- ## Endpoints | Method | Path | Notes | |--------|------|-------| | `GET` | `/automations` | List | | `POST` | `/automations` | Create draft | | `GET` | `/automations/{id}` | Get | | `PATCH` | `/automations/{id}` | Update name/trigger/steps | | `DELETE` | `/automations/{id}` | Delete | | `POST` | `/automations/{id}` | `{ "action": "activate" \| "pause" }` | | `GET` | `/automations/runs` | Optional `?automation_id=` | | `GET` | `/automations/runs/{id}` | Run detail | | `POST` | `/automations/runs/{id}` | `{ "action": "cancel" \| "retry" }` | --- ## Step types | Type | Purpose | |------|---------| | `send_email` | Send via the same transactional send path as `POST /emails` — inline `subject`/`html` **or** a published [`email.template`](./templates.md) | | `delay` | Wait `seconds` before the next step | | `condition` | Continue only if true; **false stops the run** (not if/else branching) | | `wait_for_event` | Pause until another event arrives (optional `timeout_seconds`) | Placeholders in email steps: `{{event.email}}`, `{{event.user_id}}`, `{{event.data.foo}}`. Template example (mutually exclusive with inline `subject` / `html` / `text`): ```json { "type": "send_email", "email": { "from": "you@yourdomain.com", "to": "{{event.email}}", "template": { "id": "welcome", "variables": { "name": "{{event.data.name}}" } } } } ``` --- ## Trigger the flow After activate, send events with [`POST /events`](./events.md) or: ```bash supersendtx events send --name user.created --email user@example.com --data '{"name":"Ada"}' ``` --- # API keys Manage SuperSend TX API keys from the public API (Bearer auth with a **full**-scope key) or the dashboard. Base URL: `https://api.supersendtx.com` --- ## Scopes | Scope | Access | |-------|--------| | `full` (default) | Domains, webhooks, keys, emails | | `sending` | `POST/GET /emails` only | --- ## List `GET /api-keys?limit=25&cursor=…` ```json { "data": [ { "id": "…", "name": "Default", "scope": "full", "prefix": "stx_abcd", "created_at": "2026-07-26T00:00:00.000Z", "last_used_at": null } ], "has_more": false, "next_cursor": null } ``` --- ## Create `POST /api-keys` ```json { "name": "CI", "scope": "sending" } ``` Response (token shown once): ```json { "id": "…", "name": "CI", "scope": "sending", "prefix": "stx_…", "token": "stx_…", "created_at": "2026-07-26T00:00:00.000Z" } ``` --- ## Delete `DELETE /api-keys/{id}` → `{ "ok": true }` Cannot delete the key authenticating the request. --- ## SDK / CLI ```ts await client.apiKeys.create({ name: 'CI', scope: 'sending' }) await client.apiKeys.list() await client.apiKeys.remove(id) ``` ```bash supersendtx keys create --name CI --scope sending supersendtx keys list supersendtx keys delete --idHello there!
", "auto_submitted": null, "received_at": "2026-07-26T12:00:00.000Z", "created_at": "2026-07-26T12:00:00.000Z" } } ``` Attachments are base64 encoded. --- ## `email.received` webhook Subscribe a webhook endpoint to `email.received` with `POST /webhooks`. Webhook deliveries include metadata only, not full attachment data: ```json { "type": "email.received", "created_at": "2026-07-26T12:00:01.000Z", "data": { "email_id": "inb_abc123", "to": ["sales@inbound.example.com"], "from": "SenderHi
', }) ``` --- ## Rules - `From` must use a **verified domain** for your account (or sandbox rules apply) - Revoke credentials from the dashboard or `DELETE /smtp-credentials/{id}` - SMTP credentials are **send-only** — use API keys for management APIs --- ## Local development Run the SMTP relay worker: ```bash npm run build:worker npm run worker:smtp ``` Default bind: `0.0.0.0:2525` (plain SMTP, no TLS). Set `SUPERSENDTX_SMTP_PORT` to override. --- ## Related - [Emails API](/emails) - [Supabase Auth email](/guides/supabase) - [Auth provider email](/guides/auth-provider-email) --- # SuperSend TX with Node.js Use the Node SDK in Express, Fastify, workers, cron jobs, queue consumers, or any other server runtime where your API key can stay private. ## 1. Install the SDK ```bash npm install supersendtx ``` ## 2. Configure your API key ```bash export SUPERSENDTX_API_KEY=stx_your_key_here ``` ## 3. Send an email ```ts import { SuperSendTX } from 'supersendtx' const tx = new SuperSendTX(process.env.SUPERSENDTX_API_KEY!) const result = await tx.emails.send({ from: 'ops@yourdomain.com', to: 'user@example.com', subject: 'Your receipt', html: 'Thanks for your purchase.
', }) console.log(result.id, result.status) ``` --- # SuperSend TX with Next.js Use SuperSend TX from a **server context** in Next.js: Route Handlers, Server Actions, background jobs, or any trusted backend code. Do **not** expose your `stx_…` API key in the browser. ## 1. Install the SDK ```bash npm install supersendtx ``` ## 2. Set your API key ```bash export SUPERSENDTX_API_KEY=stx_your_key_here ``` In Vercel or Kubernetes, store the same value as an environment variable instead of committing it to the repo. ## 3. Send from an API route Create `app/api/send-welcome/route.ts`: ```ts import { NextResponse } from 'next/server' import { SuperSendTX } from 'supersendtx' const tx = new SuperSendTX(process.env.SUPERSENDTX_API_KEY!) export async function POST() { const result = await tx.emails.send({ from: 'onboarding@yourdomain.com', to: 'user@example.com', subject: 'Welcome to your app', html: 'Your account is ready.
', }) return NextResponse.json(result) } ``` ## React Email Author components with [React Email](https://react.email), then pass them to the SDK: ```bash npm install @react-email/render react ``` ```ts await tx.emails.send({ from: 'onboarding@yourdomain.com', to: 'user@example.com', subject: 'Welcome', react: WelcomeEmail({ name: 'Ada' }), }) ``` Full walkthrough: [Send React Email](/guides/react-email). --- # Python SDK The official Python SDK is **coming soon**. --- # Go SDK The official Go SDK is **coming soon**. --- # PHP SDK The official PHP SDK is **coming soon**. --- # Agent Skills Official Agent Skills for Cursor, Claude Code, Codex, and other clients that support the [Agent Skills](https://agentskills.io) format. Skills teach agents how to send with SuperSend TX, install MCP/CLI, and follow email deliverability basics — without stuffing the entire docs corpus into every prompt. **Index:** [llms.txt](https://docs.supersendtx.com/llms.txt) · [Agent skill notes](./agent-skill.md) · [MCP server](./mcp.md) · [GitHub (public)](https://github.com/Super-Send/supersendtx-skills) --- ## Install ```bash # All four skills npx skills add Super-Send/supersendtx-skills -y # Individual skills npx skills add Super-Send/supersendtx-skills --skill supersendtx -y npx skills add Super-Send/supersendtx-skills --skill supersendtx-mcp -y npx skills add Super-Send/supersendtx-skills --skill supersendtx-cli -y npx skills add Super-Send/supersendtx-skills --skill email-best-practices -y ``` Scope flags: - `-g` — install globally for your user - default — project-level skills in the current repo Machine-readable listing: [/.well-known/agent-skills/index.json](https://docs.supersendtx.com/.well-known/agent-skills/index.json) --- ## Available skills | Skill | When to use | |-------|-------------| | **supersendtx** | Send API, `stx_` auth, sandbox rules, domains, SDK / OpenAPI | | **supersendtx-mcp** | Install and use `supersendtx-mcp` in Cursor or Claude Code | | **supersendtx-cli** | Terminal flows (`emails`, `domains`, `webhooks`, `suppressions`, …) | | **email-best-practices** | SPF/DKIM, suppressions, key hygiene, sandbox vs production | For **React Email** authoring and preview, use React Email’s own tools and skills. Send with SuperSend TX — see [Send React Email](/guides/react-email) (`npm install supersendtx @react-email/render react`). --- ## Cursor / Claude / Codex After `npx skills add …`, restart or reload the agent so skill names/descriptions are discovered. The agent loads full `SKILL.md` bodies only when a task matches the skill description. Prefer: 1. Install **supersendtx** for any send/integration work 2. Add **supersendtx-mcp** when the user wants MCP tools instead of writing HTTP 3. Add **email-best-practices** when reviewing deliverability or production readiness The dashboard **Get started** page can still generate a personalized setup prompt (API key + sandbox rules) for Cursor or Claude. --- ## Related - Narrative agent defaults (same content as the core skill, as a docs page): [Agent skill notes](./agent-skill.md) - MCP package install: [MCP server](./mcp.md) - Full doc corpus for agents: [llms-full.txt](https://docs.supersendtx.com/llms-full.txt) --- # SuperSend TX agent skill notes If you are an AI agent integrating with SuperSend TX, prefer these defaults: 1. Send through `POST /emails` at `https://api.supersendtx.com` 2. Authenticate with `Authorization: Bearer stx_...` 3. Verify customer domains before production sends 4. Use the shared sandbox sender only for self-tests to the account email 5. Prefer the OpenAPI spec at `https://docs.supersendtx.com/openapi.yaml` as the source of truth The dashboard **Get started** page can generate a personalized setup prompt (with sandbox rules and API key) for Cursor or Claude. Use that when onboarding a developer in their editor. **Machine-readable docs:** [llms.txt](https://docs.supersendtx.com/llms.txt) · [llms-full.txt](https://docs.supersendtx.com/llms-full.txt) · [Agent Skills](./agent-skills.md) · [MCP setup](./mcp.md) · [AI app builders](../builders/index.md) Install Cursor/Claude skills: ```bash npx skills add Super-Send/supersendtx-skills --skill supersendtx -y ``` See [Agent Skills](./agent-skills.md) for all four skills (`supersendtx`, `supersendtx-mcp`, `supersendtx-cli`, `email-best-practices`). --- ## Core send flow ```json { "from": "you@yourdomain.com", "to": "user@example.com", "subject": "Hello", "html": "It works.
" } ``` Migration-friendly aliases accepted by the HTTP API: - `htmlBody` - `textBody` - `replyTo` - `scheduledAt` - attachment aliases like `filename`, `contentType`, and `content` Prefer canonical field names (`html`, `text`, `reply_to`) in generated code even when aliases work. --- ## Safe sandbox behavior Before the customer verifies DNS, agents can self-test with: ```json { "from": "noreply@mail.supersendtx.com", "to": "owner@example.com", "subject": "Sandbox check", "html": "Sandbox works.
" } ``` Replace `owner@example.com` with the account email from the setup prompt. Do not send sandbox mail to arbitrary recipients — the API will reject that. --- ## Domain verification flow 1. `POST /domains` with `{ "name": "yourdomain.com" }` 2. `POST /domains/{id}` with `{ "action": "apply" }` to apply DNS (Cloudflare token in dashboard, or GoDaddy one-time credentials) 3. `POST /domains/{id}` with `{ "action": "verify" }` after DNS propagates 4. Switch production `from` to an address on the verified domain Explain when the customer still needs DNS or registrar access. --- ## React Email Author and preview with [React Email](https://react.email). Send with the Node SDK: ```bash npm install supersendtx @react-email/render react ``` ```ts await client.emails.send({ from: 'you@yourdomain.com', to: 'user@example.com', subject: 'Welcome', react: WelcomeEmail({ name: 'Ada' }), }) ``` `react` is mutually exclusive with `html` / `text` / `template`. Full guide: [Send React Email](/guides/react-email). Starter aliases (after `POST /templates/from-starter` or dashboard): `password-reset`, `email-verification`, `welcome`, `invoice`, `team-invite` — see [Templates](/templates). --- ## Webhooks and events - Register webhooks in the dashboard or via `POST /webhooks` - Listen for `delivered`, `bounced`, `complained`, and related event types - Use `GET /events` to poll recent activity when webhooks are not wired yet - See [Webhooks API](../api/webhooks.md) and [Events API](../api/events.md) --- ## Errors - `401` — missing or invalid API key - `403` — unverified domain, sandbox recipient mismatch, or account restriction - `400` — validation (missing `from`/`to`/`subject`, malformed email) - Error body shape: `{ "error": { "message": "...", "details": ... } }` See [Errors](../errors.md) for the full list. --- ## Useful follow-up calls - `GET /emails` and `GET /emails/{id}` for send status - `GET /deliverability` for best-effort delivery metrics (not full mailbox-provider telemetry) - `GET /suppressions` before retrying to a bounced address --- ## Anti-patterns - Do not expose `stx_` API keys in browser code or client bundles - Do not send production mail from the sandbox `from` address - SMTP relay: create credentials via dashboard **SMTP** or `POST /smtp-credentials`; connect with host `smtp.supersendtx.com`, port `587`, username `supersendtx` - Do not describe deliverability metrics as guaranteed inbox placement - Do not brand SuperSend TX as a clone of any competitor in customer-facing copy --- ## MCP alternative For Cursor or Claude Code, install the `supersendtx-mcp` package — see [MCP server](./mcp.md). Tools: emails, domains, webhooks, suppressions, templates, deliverability, and webhook test — see [MCP server](./mcp.md). --- # SuperSend TX MCP server Expose SuperSend TX to Cursor, Claude Code, or any MCP client with a curated tool surface. **Package:** `supersendtx-mcp` on npm (published with `supersendtx` + `supersendtx-cli` via `./scripts/publish-npm.sh`) **Version:** `0.4.0` **Docs index for agents:** [llms.txt](https://docs.supersendtx.com/llms.txt) · [Agent Skills](./agent-skills.md) · [Agent skill notes](./agent-skill.md) --- ## Transports | Mode | How to run | Auth | |------|------------|------| | **stdio** (default) | `npx -y supersendtx-mcp` | Env `SUPERSENDTX_API_KEY=stx_…` | | **HTTP** (local) | `npx -y supersendtx-mcp --http --port 3000` | `Authorization: Bearer stx_…` per request | | **HTTP** (hosted) | `https://mcp.supersendtx.com/mcp` | **OAuth** (recommended) or `Authorization: Bearer stx_…` | Local HTTP listens on `http://127.0.0.1:3000/mcp` by default (`--host` / `--port` override). `GET /health` is unauthenticated (local and hosted). ### Hosted OAuth (recommended) Remote MCP clients (Cursor, Claude Code) can connect **without pasting an API key**: 1. Add the hosted URL only — `https://mcp.supersendtx.com/mcp` (no `headers` block). 2. The client discovers OAuth via `WWW-Authenticate` + `/.well-known/oauth-protected-resource`. 3. Sign in on `app.supersendtx.com`, approve access, and the client receives tokens. Authorization server metadata: `https://app.supersendtx.com/.well-known/oauth-authorization-server` Bearer `stx_…` still works for scripts, CI, and advanced setups. --- ## Install in Cursor (stdio) 1. Create an API key in the dashboard (or use **Get started → Copy setup prompt / Install in Cursor**). 2. Add to `.cursor/mcp.json` (or global `~/.cursor/mcp.json`): ```json { "mcpServers": { "supersendtx": { "command": "npx", "args": ["-y", "supersendtx-mcp"], "env": { "SUPERSENDTX_API_KEY": "stx_your_key_here" } } } } ``` 3. Restart Cursor. The tools appear in Agent chat. Optional: set `SUPERSENDTX_API_URL` when pointing at a local app (`http://localhost:3003/api`). The dashboard **Install in Cursor** button generates a deeplink with your key pre-filled. ### Cursor (HTTP) Terminal: ```bash npx -y supersendtx-mcp --http --port 3000 ``` `.cursor/mcp.json` (URL + Bearer; exact shape depends on Cursor version): ```json { "mcpServers": { "supersendtx": { "url": "http://127.0.0.1:3000/mcp", "headers": { "Authorization": "Bearer stx_your_key_here" } } } } ``` ### Cursor (hosted remote) **OAuth (recommended):** no local process, no API key in config. ```json { "mcpServers": { "supersendtx": { "url": "https://mcp.supersendtx.com/mcp" } } } ``` Cursor runs the browser OAuth flow on first connect. **Bearer (advanced):** dashboard **Copy hosted MCP JSON** pre-fills your key. ```json { "mcpServers": { "supersendtx": { "url": "https://mcp.supersendtx.com/mcp", "headers": { "Authorization": "Bearer stx_your_key_here" } } } } ``` Health check: `GET https://mcp.supersendtx.com/health` --- ## Claude Code ```bash # stdio claude mcp add --transport stdio supersendtx -- npx -y supersendtx-mcp # HTTP (local — start --http server first) claude mcp add --transport http supersendtx http://127.0.0.1:3000/mcp # HTTP (hosted) claude mcp add --transport http supersendtx https://mcp.supersendtx.com/mcp ``` Export `SUPERSENDTX_API_KEY=stx_…` for stdio. For HTTP (local or hosted), configure Bearer headers in the client. --- ## Tools All tools call the `supersendtx` SDK (no duplicate HTTP). | Tool | Purpose | |------|---------| | `send_email` | `POST /emails` | | `list_emails` / `get_email` | List or fetch sends | | `list_domains` / `create_domain` | Domain inventory | | `apply_domain_dns` / `verify_domain` | DNS apply + verify | | `list_webhooks` / `create_webhook` / `delete_webhook` | Webhook endpoints | | `list_suppressions` / `add_suppression` / `remove_suppression` | Suppression list | | `list_templates` / `get_template` | Templates by id or alias | | `send_test_webhook_event` | `POST /emails/test` (CI / webhook sink) | | `get_deliverability` | Best-effort metrics (`7d` / `30d`) | ### `send_email` Inputs: `from`, `to`, `subject`, optional `html` / `text` / `reply_to`. Sandbox: if `from` is `noreply@mail.supersendtx.com`, recipients must match the account email. ### `send_test_webhook_event` Inputs: - `event` (required) — e.g. `email.bounced`, `email.delivered` - optional `email_id` (`msg_…`) - optional `deliver` (default true) — enqueue to subscribed webhooks --- ## Implementation Source: `packages/supersendtx-mcp` in the SuperSend TX monorepo. For agents without MCP, use the dashboard **Copy setup prompt** flow, [Agent Skills](./agent-skills.md), or [agent-skill.md](./agent-skill.md) with [llms.txt](https://docs.supersendtx.com/llms.txt). ```bash npx -y supersendtx-mcp npx -y supersendtx-mcp --http --port 3000 # or npm install -g supersendtx-mcp ``` ### Smithery `packages/supersendtx-mcp/smithery.yaml` configures stdio install for [Smithery](https://smithery.ai). After npm publish, list/publish the package from the Smithery dashboard or CLI so agents can discover it. ---