Skip to content
DocumentationAPI reference Build something worth sending.

Reference

Integration reference

The complete SendPanda integration guide, including sending, templates, marketing and MCP.

Interactive OpenAPI is served at /docs; the contract is at /openapi.json and exported to apps/docs/openapi.json. Base production URL: https://api.sendpanda.email/v1. Local base URL: http://localhost:4000/v1.

Send your first email

Verify your account, add a project sending domain, publish its DNS records, recheck readiness. Sending opens automatically once the account owner's email and a domain are verified; paid plans have no daily limit, and while a new domain warms up its mail is delivered in batches that grow each day of clean sending. Create a send API key. Use it only on your server.

ts
import { SendPanda } from "@sendpanda/sdk";

const panda = new SendPanda(process.env.SENDPANDA_API_KEY!, {
  baseUrl: process.env.SENDPANDA_API_URL ?? "https://api.sendpanda.email/v1",
  timeout: 10_000,
});

const email = await panda.emails.send(
  {
    from: "Your app <hello@your-verified-domain.com>",
    to: ["you@example.com"],
    subject: "Hello from SendPanda",
    text: "Your integration is working.",
  },
  { idempotencyKey: "welcome-account-123" },
);

console.log(email.id, email.status); // queued on acceptance

Install the official Node.js 22+ packages with npm install @sendpanda/sdk @sendpanda/webhooks. Both support ESM/CommonJS and TypeScript, have no runtime dependencies and use the MIT license. Replace the recipient with your own email address. Test sends count against the same sending quota and limits as other email.

Reuse one idempotency key for retries of the same business event. Different content with the same key returns 409. Keys are project-scoped and retained with message metadata; one key is not a reusable sending credential. A timeout may follow acceptance: retry with the same key to retrieve the stored ID. The SDK retries reads and keyed sends, and never automatically retries an unkeyed send.

Request constraints: max 50 total unique To/CC/BCC recipients, 500 KB JSON payload, a nonempty HTML/text body or published template, valid mailboxes, verified sender domain, approved account, rate limits, quota and suppressions. Tags use ASCII letters/numbers/underscore/dash; sendpanda_id is reserved. Executable HTML and unsafe URL destinations are rejected. full keys can administer their project, so prefer send keys for application integrations. Session access additionally needs X-Project-Id.

Delivery status

Acceptance reserves recipient quota and returns queued. Workers move through processing and submitted. Only provider delivery events produce delivered. Recipient records have separate status, so a mixed multi-recipient message may be submitted or bounced while another recipient delivered. needs_review means an uncertain submission requires operator reconciliation; do not resend blindly. Cancellation is possible only before worker claiming.

GET /emails/:id returns recipient outcomes and an immutable event timeline. Message body content is not returned by that endpoint. New domains need three sending records: signing TXT (also domain ownership proof), bounce MX and SPF TXT. Existing domains keep their original verification records. Domain readiness requires the exact claim key in DNS plus signing, identity and return-path checks. Deliverability to an inbox is not guaranteed by domain verification.

Open and click tracking are off for every domain by default. Turn them on per domain with PATCH /domains/:id and { "open_tracking": true, "click_tracking": true } (a Manage project key). Opens add an invisible image and clicks send links through a redirect, which some inboxes treat as marketing, so keep tracking off for receipts and password resets and use it for newsletters, ideally from their own subdomain. Open and click events appear in an email's timeline and in analytics only for tracked domains. tracking_available on a domain says whether this server supports tracking yet.

Search and pagination

GET /emails supports status, recipient, domain (domain ID), after/before (ISO UTC timestamps), and tag (tag name or value substring). Pages contain up to 50 messages plus next_cursor; pass that opaque value as cursor with the same filters to fetch older messages. Timestamp and message ID ordering preserves messages created together. before is exclusive.

GET /usage returns the organisation's UTC calendar-month recipient usage and a projects breakdown. Definitive failures before submission and queued cancellations release their reservations.

Webhook verification

Webhook headers are webhook-id, webhook-timestamp (Unix seconds), and webhook-signature containing space-separated v1=HEX signatures. Verify against the raw body before JSON parsing and use constant-time comparison:

ts
import { verifyWebhook } from "@sendpanda/webhooks";

const event = verifyWebhook(
  rawRequestBody, // exact string or bytes, before JSON parsing
  requestHeaders, // Headers or a header record
  process.env.SENDPANDA_WEBHOOK_SECRET!,
);

// Persist and deduplicate event.id before processing application side effects.

The helper checks the delivery timestamp (300-second tolerance by default), compares signatures in constant time, accepts rotation signatures and validates the event envelope. Invalid requests throw WebhookVerificationError. For Next.js, use the Node.js runtime and await request.text(); for Express, mount express.raw() on the webhook route before express.json(). See the package README for complete examples.

Deduplicate by event ID in a transaction. Respond 2xx after durable receipt; dispatch work asynchronously. Deliveries retry up to 8 attempts, with exponential jitter. Manual replay preserves event ID and refreshes timestamp/signature. During rotation both old and new secrets sign deliveries for 24 hours. Never log the signing secret. Endpoints require public HTTPS/443, public DNS for every resolved address and no redirects; the sender pins DNS per attempt to resist rebinding.

Templates

Use the visual Email studio in Templates or Marketing to drag in headings, text, images, buttons, columns, hero sections, product cards, social links, lists and discount codes. Edit text on the canvas; change colours, spacing and fonts in the settings. Desktop/mobile previews, starter layouts and undo/redo are included. Save your draft to preserve its editable design. Images use your hosted HTTPS URLs. Existing HTML emails open in HTML mode. Marketing automatically adds the sender address and personal unsubscribe footer.

Create a template, save versions and publish one. Use template_id and variables instead of html/text. A published template supplies the subject; you can omit it from template-based sends. Variables use {{name}}, with HTML escaping; customer code is never executed. Use POST /templates/:id/preview with a variables object and optional version to render through the same escaping rules. The dashboard displays this in a sandboxed iframe. Duplicate creates a draft copy. Test sends use the latest version and a recipient email you choose, with all normal approval, sender, suppression, quota and rate checks. Review template output and links before publishing.

In SDK 0.3.0, use panda.templates.test(id, { from, to, variables }) or panda.campaigns.test(id, to). Each requires a chosen recipient; neither silently picks an infrastructure address. Both accept an optional { idempotencyKey } argument. In MCP 0.3.0, templates_test and campaigns_test require to and explicit send confirmation. Previewing alone sends no email and uses no sending quota.

Error shape

json
{
  "error": {
    "code": "quota_exceeded",
    "message": "Monthly recipient quota exhausted"
  },
  "request_id": "req-123"
}

400 invalid payload, 401 invalid credentials, 403 role/account/domain restriction, 404 inaccessible resource, 409 idempotency conflict, 422 suppressed/unsafe message, 429 quota/rate limit, 503 disabled or unconfigured service. Bodies and credentials never belong in application logs.

API key permissions

Choose Send emails (send) for your application server: submit/cancel emails, read delivery history and usage, and invoke gated template test sends. It cannot manage resources. Choose Manage project (full) for trusted server administration of domains, templates, webhooks, suppressions and keys. Emails and project resources stay restricted to their project; usage and suppression lists are shared across its account. Neither key can change account membership, bypass review or raise quotas. Creating/renaming/deleting projects requires a verified owner/admin session. Projects with resources or history cannot be deleted.

Marketing broadcasts

Marketing uses a project management key. Broadcasts open automatically once the account has a record of clean transactional sending. Create an audience, add subscribers with recorded explicit permission, create a broadcast, preview, then schedule. Unsubscribe preferences apply to marketing within the project; essential transactional mail remains separate.

typescript
const audience = await panda.audiences.create("Product updates");
await panda.audiences.addContacts(
  audience.id,
  [
    {
      email: "subscriber@example.com",
      consent: {
        at: "2026-10-01T12:00:00Z",
        source: "signup",
        evidence: "Product update form v1; explicit marketing opt-in",
      },
    },
  ],
  { permissionConfirmed: true },
);
const broadcast = await panda.campaigns.create({
  name: "October update",
  audience_id: audience.id,
  from: "Your product <hello@yourdomain.com>",
  subject: "Here’s what’s new",
  text: "Your update goes here.",
  postal_address: "Your actual business postal address",
});
await panda.campaigns.preview(broadcast.id);
// Review the message and audience before scheduling.
await panda.campaigns.schedule(broadcast.id, { permissionConfirmed: true });
const report = await panda.campaigns.get(broadcast.id);

These methods are in SDK 0.2.0. REST resources: /v1/audiences, /v1/contacts and /v1/campaigns; use the interactive API reference for schemas. Each recipient gets a personal unsubscribe footer and one-click headers. Scheduled broadcasts retain a fixed audience and content; later opt-outs and suppressions are still checked before submission. Pause/resume/cancel are available; messages already in flight cannot be recalled. Reports distinguish provider submission from recipient delivery.

AI and MCP connections

Add https://api.sendpanda.email/mcp as a Streamable HTTP MCP server. OAuth-capable clients open SendPanda to choose a project and approve sending or project-management access. Connections expire after 30 days; revoke them in Settings → Connections. OAuth credentials cannot access other projects, mint permanent API keys, change account-wide safeguards or manage billing. Team permissions remain enforced.

For local stdio clients, use command npx, arguments ["-y", "@sendpanda/mcp"], and securely set SENDPANDA_API_KEY to a dedicated project key. Revoke that key in API keys to disconnect it. Never paste keys into prompts or URLs.

Tools cover transactional email and actual delivery status, domains and DNS, templates, webhooks, audiences and permission history, broadcasts and reports, and project teams. Sending keys expose sending/history/usage tools; management access adds project administration. Human approval is required before sending, scheduling, invitations or destructive changes. Marketing approval and recipient consent are still required. The prompts onboard_project and prepare_broadcast guide these workflows.

Visual editing through MCP

Connect an agent to https://api.sendpanda.email/mcp with project management access, or use @sendpanda/mcp@0.3.0 locally. Agents can edit the same saved visual designs as Email studio, create template versions and update marketing drafts. email_design_starter provides one of four complete starters; email_design_preview shows unsaved work. templates_preview applies sample variables; campaigns_preview includes the final mandatory marketing footer.

Preview results include a private web link and a sandboxed HTML resource for clients that support visual resources. The customer can inspect desktop, mobile or plain-text views after signing in to the project. These fixed snapshots expire after 15 minutes; links contain no credentials or sample variables. Templates remain unpublished and broadcasts remain drafts until explicitly published or scheduled. See sendpanda://docs/email-design, sendpanda://schemas/email-design and the design_email prompt.

↑↓ to navigate↵ to openesc to close