# 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:

${resetUrl}

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": "

Reset password

" }' ``` --- ## Example: email verification ```js await client.emails.send({ from: 'noreply@yourdomain.com', to: user.email, subject: 'Verify your email', html: `

Confirm your email:

Verify 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: `

Sign in

`, 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: Record = { signup: 'Confirm your email', recovery: 'Reset your password', invite: 'You have been invited', magiclink: 'Your sign-in link', email_change: 'Confirm your new email', email_change_new: 'Confirm your new email', reauthentication: 'Your verification code', } function confirmationUrl(emailData: { token_hash: string email_action_type: string redirect_to: string }) { const base = `https://${projectRef}.supabase.co/auth/v1/verify` const params = new URLSearchParams({ token: emailData.token_hash, type: emailData.email_action_type, redirect_to: emailData.redirect_to, }) return `${base}?${params.toString()}` } Deno.serve(async (req) => { if (req.method !== 'POST') { return new Response('method not allowed', { status: 405 }) } if (!apiKey || !hookSecret || !projectRef) { return new Response('server misconfigured', { status: 500 }) } const payload = await req.text() const headers = Object.fromEntries(req.headers) try { const wh = new Webhook(hookSecret) const { user, email_data } = wh.verify(payload, headers) as { user: { email: string } email_data: { token: string token_hash: string redirect_to: string email_action_type: string } } const action = email_data.email_action_type const subject = subjects[action] ?? 'Notification' const link = confirmationUrl(email_data) const html = action === 'reauthentication' ? `

Your verification code is ${email_data.token}

` : `

${subject}

` 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://.supabase.co/functions/v1/send-email`). --- ## 3. Enable the Send Email hook **Alternative:** If you prefer Supabase’s built-in SMTP settings UI, create an SMTP credential in SuperSend TX (**SMTP** in the dashboard) and configure [custom SMTP in Supabase](https://supabase.com/docs/guides/auth/auth-smtp) with host `smtp.supersendtx.com`, port `587`, username `supersendtx`, and your credential password. Skip the hook steps below. In [Supabase Dashboard → Authentication → Hooks](https://supabase.com/dashboard/project/_/auth/hooks): 1. Add **Send Email** hook 2. Type: **HTTPS** 3. URL: your Edge Function URL 4. **Generate secret** — copy the `v1,whsec_…` value into `SEND_EMAIL_HOOK_SECRET` 5. Save Redeploy or update secrets if you generated the secret after the first deploy. While the hook is enabled, Supabase does **not** send auth mail itself — your function must succeed and return `200` + `{}`. --- ## 4. Auth email types Handle every `email_action_type` your app uses: | `email_action_type` | Typical use | |---------------------|-------------| | `signup` | Email confirmation | | `recovery` | Password reset | | `magiclink` | Passwordless sign-in | | `invite` | User invite | | `email_change` | Confirm email change | | `email_change_new` | Confirm new address (secure email change) | | `reauthentication` | Step-up OTP | If the hook is on and a type is missing from your templates, that mail can fail silently. --- ## 5. Sandbox vs production | Stage | `from` | `to` | |-------|--------|------| | Sandbox (no domain verified) | `noreply@mail.supersendtx.com` (or your sandbox domain) | Your SuperSend TX account email only | | Production | `noreply@yourdomain.com` | Any recipient | Verify your domain in SuperSend TX before switching `SUPERSENDTX_FROM_EMAIL`. --- ## 6. Webhooks (optional) Subscribe to `email.delivered`, `email.bounced`, and `email.complained` in SuperSend TX to monitor auth mail health. See [Webhooks](/webhooks). --- ## Lovable / AI builders If you generated the app in Lovable, store `SUPERSENDTX_API_KEY` in project secrets and ask the agent to wire this hook — see [Lovable + SuperSend TX](/builders/lovable). --- ## Related - [Auth provider email (Clerk, Auth.js)](/guides/auth-provider-email) - [Password reset emails](/guides/password-reset-emails) - [React Email](/guides/react-email) - [Marketing overview](https://supersendtx.com/integrations/supabase) --- # Send React Email with SuperSend TX Use [React Email](https://react.email) to author components, preview them locally, then send with the SuperSend TX Node SDK. The SDK accepts a `react` element and compiles it to HTML before `POST /emails`. You do **not** need to fork React Email or add `@react-email/components` to SuperSend TX — keep authoring in your app. --- ## Prerequisites - A SuperSend TX API key (`stx_…`) - A verified sending domain (or sandbox: `from` = `noreply@mail.supersendtx.com`, `to` = your account email) - Node 18+ --- ## 1. Install ```bash npm install supersendtx @react-email/render react # Optional — components + local preview tooling from React Email npm install @react-email/components npx create-email@latest ``` `@react-email/render` is an **optional peer** of `supersendtx`. Install it only if you use the `react` option. Without it, send with `html` / `text` / `template` as usual. --- ## 2. Author and preview Create a component (example): ```tsx // emails/WelcomeEmail.tsx import * as React from 'react' import { Html, Button, Text } from '@react-email/components' export function WelcomeEmail({ name }: { name: string }) { return ( Hi {name}, welcome aboard. ) } export default WelcomeEmail ``` Preview with React Email’s CLI / app (`npx email dev` or your project’s create-email setup). SuperSend TX is not involved until you send. --- ## 3. Send with the SDK ```ts import { SuperSendTX } from 'supersendtx' import { WelcomeEmail } from './emails/WelcomeEmail' const client = new SuperSendTX(process.env.SUPERSENDTX_API_KEY!) await client.emails.send({ from: 'onboarding@yourdomain.com', to: 'user@example.com', subject: 'Welcome', react: WelcomeEmail({ name: 'Ada' }), }) ``` The SDK calls `@react-email/render` and POSTs `{ from, to, subject, html }` to `https://api.supersendtx.com/emails`. **Rules:** - `react` is mutually exclusive with `html`, `text`, and `template` - Server-side only — never put `stx_` in the browser - Same auth, sandbox, and domain rules as any other send ([Quickstart](/quickstart), [Agent skill notes](/ai/agent-skill)) --- ## 4. Next.js (Route Handler) ```ts // app/api/send-welcome/route.ts import { NextResponse } from 'next/server' import { SuperSendTX } from 'supersendtx' import { WelcomeEmail } from '@/emails/WelcomeEmail' const tx = new SuperSendTX(process.env.SUPERSENDTX_API_KEY!) export async function POST(request: Request) { const { to, name } = (await request.json()) as { to: string; name: string } const result = await tx.emails.send({ from: 'onboarding@yourdomain.com', to, subject: 'Welcome', react: WelcomeEmail({ name }), }) return NextResponse.json(result) } ``` More Next.js patterns: [Next.js framework guide](/frameworks/nextjs). --- ## 5. Already have HTML? If you render elsewhere (or export from React Email yourself), send `html` instead of `react`: ```ts await client.emails.send({ from: 'onboarding@yourdomain.com', to: 'user@example.com', subject: 'Welcome', html: '

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: Bearer . 3. Sandbox: from "noreply@mail.supersendtx.com", to only the SuperSend TX account email until a domain is verified. 4. Implement server-side email for at least one flow (welcome, reset, or notification). 5. Use html and text fields; prefer supersendtx npm package on Node. When ready for production, verify a sending domain in SuperSend TX and update from addresses. ``` ## 3. Minimal Express route (Node) ```js import express from 'express' const app = express() app.use(express.json()) app.post('/api/send-test', async (req, res) => { const apiKey = process.env.SUPERSENDTX_API_KEY if (!apiKey) return res.status(500).json({ error: 'Missing SUPERSENDTX_API_KEY' }) const upstream = await fetch('https://api.supersendtx.com/emails', { method: 'POST', headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json', }, body: JSON.stringify(req.body), }) const data = await upstream.json() res.status(upstream.status).json(data) }) ``` ## Sandbox self-test Send to your SuperSend TX account email only, with `from: "noreply@mail.supersendtx.com"`, until your domain is verified. ## Production Verify your domain in SuperSend TX, then set `from` to `noreply@yourdomain.com` (or similar on that domain). ## Links - [Quickstart](../quickstart.md) - [Node.js](../frameworks/node.md) - [Errors](../errors.md) --- # SuperSend TX + Bolt.new Add transactional email to a Bolt-generated app with a `.env` secret and a chat prompt. Bolt often outputs Vite or React projects — keep sends on the server. ## When to use SuperSend TX - Bolt prototypes that need real password-reset or notification email - Moving from demo to production with your own sending domain - Replacing a `RESEND_API_KEY` pattern with SuperSend TX (`SUPERSENDTX_API_KEY`) ## 1. Add your API key 1. Get a key from [app.supersendtx.com](https://app.supersendtx.com). 2. In the Bolt project, add to **`.env`** (local) and your host’s env UI when you deploy: ```bash SUPERSENDTX_API_KEY=stx_your_key_here ``` 3. Ensure `.env` is in `.gitignore` — never commit `stx_` keys. If Bolt deploys to a platform with its own env panel (Netlify, Vercel, etc.), add the same variable there for production. ## 2. Paste this prompt in Bolt chat ```text Integrate SuperSend TX transactional email into this project. Docs: - https://docs.supersendtx.com/ai/agent-skill - https://docs.supersendtx.com/openapi.yaml - https://docs.supersendtx.com/builders/bolt Rules: 1. Use SUPERSENDTX_API_KEY from .env on the server only — never in client bundles or VITE_ prefixed vars. 2. POST https://api.supersendtx.com/emails with Authorization: Bearer and JSON body (from, to, subject, html). 3. Until domain verify: sandbox from "noreply@mail.supersendtx.com", to account email only. 4. Add a small API route or serverless function for transactional sends; do not call the API from the browser. 5. If this is Next.js, follow the App Router server pattern in https://docs.supersendtx.com/frameworks/nextjs After domain verify, use from on our verified domain. ``` ## 3. Server-only pattern Bolt may generate a Vite SPA. Add a server endpoint (or deploy a small API route) that proxies to SuperSend TX: ```ts // Example: server handler (adapt to your Bolt stack) export async function sendTransactionalEmail(payload: { to: string subject: string html: string }) { 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: process.env.MAIL_FROM ?? 'noreply@yourdomain.com', ...payload, }), }) if (!res.ok) throw new Error(await res.text()) return res.json() } ``` ## Sandbox Use `noreply@mail.supersendtx.com` and your account email for the first test — see [Quickstart](../quickstart.md). ## Links - [Migration from Resend](../migration.md) — field mapping if you started with Resend env names - [Next.js](../frameworks/nextjs.md) --- # SuperSend TX + Base44 Base44 apps can send email through built-in platform features. Use SuperSend TX when you need **your own domain**, higher control over deliverability, or the same transactional stack as the rest of your product. ## When Base44 built-in email is enough - Early prototypes and internal tools - Low volume without a custom domain requirement - Flows where Base44’s default sender is acceptable ## When to add SuperSend TX - Branded mail from `@yourdomain.com` after DNS verify - Password reset / auth mail you want on owned transactional infrastructure - Webhooks and delivery visibility via SuperSend TX dashboard - Consistent API across non-Base44 services (same `POST /emails` everywhere) ## 1. Add your API key 1. Create `stx_…` at [app.supersendtx.com](https://app.supersendtx.com). 2. In Base44, add a project secret or environment variable (exact UI varies by Base44 project type): ```text SUPERSENDTX_API_KEY=stx_your_key_here ``` Wire server-side code or automation steps to read that variable — never expose it in client-visible config. ## 2. Paste this prompt in Base44 ```text Add SuperSend TX for transactional email in this Base44 app (instead of or alongside built-in email). Docs: - https://docs.supersendtx.com/ai/agent-skill - https://docs.supersendtx.com/openapi.yaml - https://docs.supersendtx.com/builders/base44 Rules: 1. Use SUPERSENDTX_API_KEY from project secrets — server-side only. 2. POST https://api.supersendtx.com/emails with Bearer auth for transactional sends (reset, verify, receipts). 3. Sandbox until domain verify: from "noreply@mail.supersendtx.com", to SuperSend TX account email only. 4. Explain when built-in Base44 email is still fine vs when SuperSend TX is required (custom domain, production volume). 5. Use html/text; verify domain in SuperSend TX before production from addresses. Link users to https://app.supersendtx.com for domain setup. ``` ## 3. HTTP send ```json POST https://api.supersendtx.com/emails Authorization: Bearer stx_… Content-Type: application/json { "from": "noreply@yourdomain.com", "to": "user@example.com", "subject": "Your receipt", "html": "

Thanks 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

", "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": "Sender ", "subject": "Hello", "status": "received", "rcpt_to": "sales@inbound.example.com", "cc": [], "message_id": "", "in_reply_to": null, "references": [], "spam_status": "NotSpam", "attachment_count": 1, "attachments": [ { "filename": "invoice.pdf", "content_type": "application/pdf", "size": 48291 } ], "received_at": "2026-07-25T12:04:59.000Z" } } ``` For inbound events, attachment metadata is included but attachment bytes are not — fetch `/received-emails/{id}` for full bodies and base64 attachment data. For bounces, `type` is `email.bounced`, `status` is `bounced`, and `bounce_reason` may contain a provider reason string. ### Automation event example ```json { "type": "automation.step_completed", "created_at": "2026-07-26T12:05:00.000Z", "data": { "automation_id": "a1b2c3", "automation_name": "Welcome flow", "run_id": "r1s2t3", "status": "running", "event_name": "user.created", "step_index": 0, "step_type": "send_email", "error": null } } ``` --- ## Signature verification Each delivery includes: ```http SuperSendTX-Signature: t=1721908800,v1=abc123… ``` ### SDK helper (preferred) ```ts import { SuperSendTX, verifyWebhookSignature } from 'supersendtx' const ok = verifyWebhookSignature(secret, rawBody, request.headers.get('supersendtx-signature')) // or: const client = new SuperSendTX(process.env.SUPERSENDTX_API_KEY!) client.webhooks.verify(secret, rawBody, header) ``` Verify by: 1. Read the raw request body as a string (before JSON parsing). 2. Parse `t` (Unix timestamp) and `v1` (hex HMAC) from the header. 3. Reject if `t` is more than 5 minutes from your server clock. 4. Compute `HMAC-SHA256(secret, "${t}.${rawBody}")` and compare to `v1` (constant-time). Return `2xx` quickly from your handler. Failed deliveries are retried by Bull at **0s, 5s, 30s, 2m, 2m** (persisted in Redis via the `supersendtx:webhook-delivery` queue). Run the `worker:webhooks` process alongside the app. --- ## SDK ```ts import { SuperSendTX } from 'supersendtx' const client = new SuperSendTX(process.env.SUPERSENDTX_API_KEY!) const { webhook, secret } = await client.webhooks.create({ url: 'https://yourapp.com/webhooks/supersendtx', }) const { webhooks } = await client.webhooks.list() const one = await client.webhooks.get(webhooks[0].id) await client.webhooks.update(one.webhook.id, { enabled: false }) await client.webhooks.delete(webhooks[0].id) ``` --- ## CLI ```bash supersendtx webhooks list supersendtx webhooks create --url https://yourapp.com/hooks supersendtx webhooks delete --id clx… ``` Requires `SUPERSENDTX_API_KEY` or `--api-key`. --- ## OpenAPI Machine-readable spec: [`openapi/supersendtx.yaml`](../../openapi/supersendtx.yaml) --- # Templates Create reusable email templates with `{{variable}}` placeholders, then send with `POST /emails` using `template: { id, variables }`. Base URL: `https://api.supersendtx.com` --- ## Authentication ```http Authorization: Bearer stx_… ``` Requires a **full**-scope API key (or dashboard session). Sending-scoped keys cannot manage templates. --- ## Model | Field | Notes | |-------|--------| | `name` | Required; unique per account | | `alias` | Optional unique handle (not empty, not starting with `stx_`) | | `status` | `draft` (default) or `published` | | `subject` / `html` / `text` | Support `{{var}}` placeholders | | `variables` | Optional hint array of variable names | | `unsubscribe_enabled` | When `true`, sends using this template inherit managed unsubscribe unless overridden per send | | `warnings` | Non-blocking deliverability hints for `html` (e.g. SVG logos) | Placeholders in **HTML** bodies are HTML-escaped when interpolated. Subject and text are not. ### Images in HTML Use **PNG or JPG** logos at **public `https://` URLs** in `` tags. Many inboxes (including Gmail) do not render SVG images. SuperSend TX returns advisory `warnings` on template create/get/list when HTML may not render reliably — sends are not blocked. ```html Your product ``` --- ## List `GET /templates` Query: `limit`, `cursor`, optional `status=draft|published`. ```json { "data": [ { "id": "…", "name": "Welcome", "alias": "welcome", "status": "published", "subject": "Hello {{name}}", "html": "

Hi {{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 --id ``` --- # Suppressions Block sends to addresses that bounced, complained, or were added manually. Suppressions are **tenant-local** to your SuperSend TX account. Base URL: `https://api.supersendtx.com` --- ## Authentication ```http Authorization: Bearer stx_… ``` Requires a **full**-scope API key (or dashboard session). Sending-scoped keys cannot manage suppressions. --- ## Behavior - Emails are stored **normalized lowercase**. - Hard bounces, permanent SMTP delivery failures (e.g. invalid mailbox / 5xx), and complaint-like events auto-add suppressions (`source: bounce` / `complaint`). - Managed unsubscribe links add suppressions with `source: unsubscribe`. - `POST /emails` checks `to` / `cc` / `bcc` before sending. If any recipient is suppressed, the API returns **422** with `code: validation_error`, `details.suppressed`, and emits `email.suppressed` (a `suppressed` email record is created). --- ## List `GET /suppressions` Query: `limit`, `cursor`, optional `email`. ```json { "data": [ { "id": "…", "email": "bad@example.com", "reason": "550 user unknown", "source": "bounce", "created_at": "2026-07-26T12:00:00.000Z", "updated_at": "2026-07-26T12:00:00.000Z" } ], "has_more": false, "next_cursor": null } ``` --- ## Add `POST /suppressions` ```json { "email": "user@example.com", "reason": "manual opt-out" } ``` `source` is set to `api`. Upserts on `(account, email)`. --- ## Remove `DELETE /suppressions/{id}` or `DELETE /suppressions?email=user@example.com` ```json { "ok": true } ``` --- ## SDK ```ts import { SuperSendTX } from 'supersendtx' const client = new SuperSendTX(process.env.SUPERSENDTX_API_KEY!) await client.suppressions.create({ email: 'user@example.com', reason: 'opt-out' }) const { data } = await client.suppressions.list() await client.suppressions.remove('user@example.com') ``` --- ## CLI ```bash supersendtx suppressions list supersendtx suppressions add --email user@example.com --reason "opt-out" supersendtx suppressions remove --email user@example.com ``` --- ## OpenAPI [`openapi/supersendtx.yaml`](../../openapi/supersendtx.yaml) --- # Inbound email API Receive mail on a verified SuperSend TX domain, get `email.received` webhooks, and retrieve full inbound messages with attachments. Base URL: `https://api.supersendtx.com` Auth: ```http Authorization: Bearer stx_... ``` --- ## Overview Inbound receiving is configured on the existing **domain** resource: 1. Create a domain with `inbound_enabled: true` or enable it later with `PATCH /domains/{id}`. 2. Verify the domain (`POST /domains/{id}` with `{ "action": "verify" }`). 3. Publish the returned MX record so SuperSend TX can receive mail for that hostname. 4. Subscribe to `email.received` webhooks or poll `/received-emails`. SuperSend TX stores: - the inbound message headers/bodies - attachment metadata on list responses - full attachment base64 data on retrieve responses --- ## Important MX conflict note Inbound receiving requires changing the domain hostname's **MX** record to SuperSend TX. That means: - if `example.com` already receives mail at Google Workspace, Microsoft 365, Fastmail, etc, moving the MX record will stop that provider from receiving new mail for `example.com` - the safest pattern is usually a dedicated subdomain such as `inbound.example.com` Every domain detail/create response includes: - `inbound_records` — the MX record to publish - `inbound_note` — the same warning in machine-readable responses --- ## Create a receiving 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": "inbound.example.com", "inbound_enabled": true }' ``` Response: ```json { "domain": { "id": "d_123", "name": "inbound.example.com", "status": "pending", "created_at": "2026-07-26T00:00:00.000Z", "verified_at": null, "open_tracking": false, "click_tracking": false, "tls_mode": "opportunistic", "inbound_enabled": true, "inbound_status": "pending", "inbound_error": null }, "records": [ { "type": "TXT", "host": "_supersendtx.inbound.example.com", "value": "supersendtx-verify=...", "purpose": "Domain ownership" } ], "inbound_records": [ { "type": "MX", "host": "inbound.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." } ``` `inbound_status: "pending"` means inbound receiving finishes setup after verification succeeds. --- ## Enable inbound on an existing domain `PATCH /domains/{id}` ```bash curl -X PATCH https://api.supersendtx.com/domains/inbound.example.com \ -H "Authorization: Bearer $SUPERSENDTX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "inbound_enabled": true }' ``` If the domain is already verified, SuperSend TX immediately activates inbound receiving for that hostname. Relevant fields: - `domain.inbound_status = "active"` — inbound receiving is configured - `domain.inbound_status = "pending"` — waiting for verification - `domain.inbound_status = "error"` + `domain.inbound_error` — inbound setup failed and should be retried --- ## Verify the domain `POST /domains/{id}` ```json { "action": "verify" } ``` If `inbound_enabled` is already `true`, verification also activates inbound receiving and returns: - `inbound_configured` - `inbound_pending` - `inbound_error` --- ## List received emails `GET /received-emails` Optional query params: - `limit` - `cursor` - `domain` — receiving domain name ```bash curl https://api.supersendtx.com/received-emails?domain=inbound.example.com \ -H "Authorization: Bearer $SUPERSENDTX_API_KEY" ``` Response: ```json { "received_emails": [ { "id": "inb_abc123", "domain_id": "d_123", "domain_name": "inbound.example.com", "status": "received", "rcpt_to": "sales@inbound.example.com", "mail_from": "sender@example.org", "from": "Sender ", "to": ["sales@inbound.example.com"], "cc": [], "subject": "Question about pricing", "spam_status": "NotSpam", "bounced": false, "received_with_ssl": true, "message_id": "", "in_reply_to": null, "references": [], "attachment_count": 1, "attachments": [ { "filename": "invoice.pdf", "content_type": "application/pdf", "size": 48291 } ], "text_body": null, "html_body": null, "auto_submitted": null, "received_at": "2026-07-26T12:00:00.000Z", "created_at": "2026-07-26T12:00:00.000Z" } ], "has_more": false, "next_cursor": null } ``` List responses omit attachment `data` and null out message bodies to keep payloads smaller. --- ## Retrieve a received email `GET /received-emails/{id}` ```bash curl https://api.supersendtx.com/received-emails/inb_abc123 \ -H "Authorization: Bearer $SUPERSENDTX_API_KEY" ``` Response: ```json { "received_email": { "id": "inb_abc123", "domain_id": "d_123", "domain_name": "inbound.example.com", "status": "received", "rcpt_to": "sales@inbound.example.com", "mail_from": "sender@example.org", "from": "Sender ", "to": ["sales@inbound.example.com"], "cc": [], "subject": "Question about pricing", "spam_status": "NotSpam", "bounced": false, "received_with_ssl": true, "message_id": "", "in_reply_to": null, "references": [], "attachment_count": 1, "attachments": [ { "filename": "invoice.pdf", "content_type": "application/pdf", "size": 48291, "data": "JVBERi0xLjQKJ..." } ], "text_body": "Hello there!", "html_body": "

Hello 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": "Sender ", "subject": "Question about pricing", "status": "received", "rcpt_to": "sales@inbound.example.com", "cc": [], "message_id": "", "in_reply_to": null, "references": [], "spam_status": "NotSpam", "attachment_count": 1, "attachments": [ { "filename": "invoice.pdf", "content_type": "application/pdf", "size": 48291 } ], "received_at": "2026-07-26T12:00:00.000Z" } } ``` Retrieve the full message from `/received-emails/{id}` when you need bodies or attachment bytes. --- ## SDK ```ts import { SuperSendTX } from 'supersendtx' const client = new SuperSendTX(process.env.SUPERSENDTX_API_KEY!) await client.domains.create({ name: 'inbound.example.com', inbound_enabled: true, }) await client.domains.verify('inbound.example.com') const { received_emails } = await client.receivedEmails.list({ domain: 'inbound.example.com', }) const one = await client.receivedEmails.get(received_emails[0].id) ``` --- ## CLI ```bash supersendtx domains add inbound.example.com --inbound true supersendtx domains verify inbound.example.com supersendtx domains update inbound.example.com --inbound true supersendtx received-emails list --domain inbound.example.com supersendtx received-emails get inb_abc123 ``` --- ## OpenAPI Machine-readable spec: [`openapi/supersendtx.yaml`](../../openapi/supersendtx.yaml) --- # Deliverability API Best-effort deliverability insights computed from the email rows and webhook events SuperSend TX already stores. Base URL: `https://api.supersendtx.com` Auth: ```http Authorization: Bearer stx_... ``` --- ## Get insights `GET /deliverability?window=30d` Supported windows: - `7d` - `30d` (default) Example: ```bash curl -X GET "https://api.supersendtx.com/deliverability?window=7d" \ -H "Authorization: Bearer $SUPERSENDTX_API_KEY" ``` Response: ```json { "window": "7d", "window_start": "2026-07-19T00:00:00.000Z", "generated_at": "2026-07-26T00:00:00.000Z", "summary": { "total_emails": 10, "attempted": 9, "sent": 8, "delivered": 7, "bounced": 1, "failed": 1, "suppressed": 1, "scheduled": 0, "opened": 3, "clicked": 1, "bounce_rate": 0.1111, "delivery_rate": 0.7778, "open_rate": 0.4286, "click_rate": 0.1429 }, "by_domain": [], "top_bounce_reasons": [], "notes": [ "Best-effort metrics only" ] } ``` --- ## What this includes - attempted vs scheduled/suppressed counts - delivered and bounced counts - best-effort open/click counts from stored events - breakdown by sending domain - top recorded bounce reasons - optional `postal_relay` on top domains when Postal admin API access is configured (relay-side sent/bounce/fail counts) ## Roadmap These are not exposed in the API yet: - inbox placement / spam folder data - provider reputation and reputation trends - richer bounce classifications beyond stored events --- ## SDK ```ts const insights = await client.emails.insights('30d') ``` ## CLI ```bash supersendtx emails insights --window 7d ``` --- # SMTP relay Send mail through SuperSend TX using standard SMTP — for Supabase custom SMTP, Clerk, WordPress, Nodemailer, and other integrations that expect host, username, and password. The relay uses the **same account scoping, domain verification, sandbox rules, billing, suppressions, and webhooks** as `POST /emails`. --- ## Connection settings | Setting | Value | |---------|--------| | Host | `smtp.supersendtx.com` | | Port | `587` (STARTTLS) | | Username | `supersendtx` | | Password | Your SMTP credential (`stxsmtp_…`) | Create credentials in the dashboard under **SMTP** or via `POST /smtp-credentials` with a full-access API key. The password is shown **once** at creation — copy it immediately. --- ## Create a credential ```bash curl -X POST https://api.supersendtx.com/smtp-credentials \ -H "Authorization: Bearer $SUPERSENDTX_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name":"Supabase production"}' ``` Response includes `host`, `port`, `username`, and `password`. --- ## Supabase custom SMTP After you verify your domain in SuperSend TX: 1. Dashboard → **SMTP** → **Create SMTP credential** 2. Supabase → **Project Settings → Authentication → SMTP** 3. Paste host, port, username `supersendtx`, password, and your branded sender email For hook-based auth mail (Edge Functions), see [Supabase Auth email](/guides/supabase). --- ## Nodemailer example ```js import nodemailer from 'nodemailer' const transport = nodemailer.createTransport({ host: 'smtp.supersendtx.com', port: 587, secure: false, auth: { user: 'supersendtx', pass: process.env.SUPERSENDTX_SMTP_PASSWORD, }, }) await transport.sendMail({ from: 'noreply@yourdomain.com', to: 'user@example.com', subject: 'Hello', html: '

Hi

', }) ``` --- ## 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. ---