Sendr Docs
SDKs

TypeScript SDK

Official TypeScript/Node.js SDK for the Sendr email API.

Installation

npm install sendr
# or
bun add sendr
# or
pnpm add sendr

The SDK is written in TypeScript and works with Node.js 18+, Bun, Deno, and edge runtimes.

Initialization

import { Sendr } from "sendr";

// Simple initialization with API key string
const sendr = new Sendr("sndr_live_your_api_key");

// Or with configuration options
const sendr = new Sendr({
  apiKey: process.env.SENDR_API_KEY!,
  baseUrl: "https://api.sendr.dev", // Override base URL
  timeout: 30000,                    // Request timeout in ms (default: 30s)
  retries: 2,                        // Retry count for 5xx errors (default: 2)
  headers: { "X-App-Version": "1.0" }, // Extra headers on every request
});

Emails

// Send a single email
const { id, status } = await sendr.emails.send({
  from: "Acme <hello@acme.com>",
  to: "user@example.com",
  subject: "Welcome!",
  html: "<h1>Welcome to Acme!</h1>",
});

// Send to multiple recipients
await sendr.emails.send({
  from: "hello@acme.com",
  to: ["alice@example.com", "bob@example.com"],
  subject: "Team announcement",
  html: "<p>Big news...</p>",
});

// Send with attachments
await sendr.emails.send({
  from: "billing@acme.com",
  to: "user@example.com",
  subject: "Your invoice",
  html: "<p>Please find your invoice attached.</p>",
  attachments: [
    {
      filename: "invoice.pdf",
      content: Buffer.from(pdfBytes).toString("base64"),
      content_type: "application/pdf",
    },
  ],
});

// Schedule a future send
await sendr.emails.send({
  from: "hello@acme.com",
  to: "user@example.com",
  subject: "Reminder",
  html: "<p>Don't forget your appointment tomorrow.</p>",
  scheduled_at: "2025-03-15T09:00:00Z",
});

// Send using a template
await sendr.emails.send({
  from: "hello@acme.com",
  to: "user@example.com",
  template_id: "tmpl_abc123",
  variables: { name: "Alice", plan: "Pro" },
});

// Send up to 100 emails in one request
const { data } = await sendr.emails.sendBatch({
  from: "hello@acme.com",
  subject: "Order update",
  emails: [
    { to: "alice@example.com", html: "<p>Alice, your order shipped!</p>" },
    { to: "bob@example.com", html: "<p>Bob, your order shipped!</p>" },
  ],
});

// Send marketing email (includes List-Unsubscribe)
await sendr.emails.sendMarketing({
  from: "Newsletter <news@acme.com>",
  to: "user@example.com",
  subject: "March Update",
  html: "<p>Here's what happened this month...</p>",
  unsubscribe_url: "https://acme.com/unsubscribe?id=abc123",
});

// Get email status
const email = await sendr.emails.get("em_abc123");
console.log(email.status); // "delivered"

// List emails with filtering
const { data, has_more, next_cursor } = await sendr.emails.list({
  limit: 25,
  status: "delivered",
});

// Paginate
if (has_more) {
  const nextPage = await sendr.emails.list({ cursor: next_cursor! });
}

// Cancel a scheduled/queued email
await sendr.emails.cancel("em_abc123");

Domains

// Add a domain (returns DNS records to configure)
const domain = await sendr.domains.create({ name: "acme.com" });
console.log(domain.dns_records); // Array of DNS records to add

// Verify a domain after DNS propagation
const result = await sendr.domains.verify("dom_abc123");
console.log(result.status); // "verified"
console.log(result.spf_verified, result.dkim_verified, result.dmarc_verified);

// List all domains
const { data } = await sendr.domains.list();

// Delete a domain
await sendr.domains.remove("dom_abc123");

Templates

// Create a template
const template = await sendr.templates.create({
  name: "Welcome Email",
  subject: "Welcome, {{name}}!",
  html: "<h1>Hi {{name}},</h1><p>Welcome to {{company}}!</p>",
});

// Render a preview
const preview = await sendr.templates.render("tmpl_abc123", {
  variables: { name: "Alice", company: "Acme" },
});
console.log(preview.subject); // "Welcome, Alice!"

// List, get, update, delete
await sendr.templates.list();
await sendr.templates.get("tmpl_abc123");
await sendr.templates.update("tmpl_abc123", { subject: "New subject" });
await sendr.templates.remove("tmpl_abc123");

API keys

// Create a new API key (raw key only returned once)
const { key, id } = await sendr.apiKeys.create({
  name: "Production Sender",
  scope: "sending_access",
});
console.log(key); // "sndr_live_..." — save this!

// List all keys (secrets not included)
const { data } = await sendr.apiKeys.list();

// Delete a key
await sendr.apiKeys.remove("ak_abc123");

Webhooks

// Create a webhook
const webhook = await sendr.webhooks.create({
  url: "https://yourapp.com/webhooks/sendr",
  events: ["email.delivered", "email.bounced"],
});
console.log(webhook.secret); // Save this for verification!

// Manage webhooks
await sendr.webhooks.list();
await sendr.webhooks.get("wh_abc123");
await sendr.webhooks.update("wh_abc123", { active: false });
await sendr.webhooks.remove("wh_abc123");

Analytics

const { summary, timeseries } = await sendr.analytics.stats({
  from: "2025-01-01",
  to: "2025-01-31",
  granularity: "week",
});

const logs = await sendr.analytics.logs({
  email_id: "em_abc123",
  type: "bounced",
});

Suppression

await sendr.suppression.list();
await sendr.suppression.add({ email: "bad@example.com", reason: "hard_bounce" });
await sendr.suppression.remove("bad@example.com");

Error handling

import { Sendr, ApiError, AuthenticationError, RateLimitError, ValidationError } from "sendr";

try {
  await sendr.emails.send({ ... });
} catch (error) {
  if (error instanceof AuthenticationError) {
    // 401 — invalid or expired API key
    console.error("Check your SENDR_API_KEY");
  } else if (error instanceof RateLimitError) {
    // 429 — back off and retry
    const retryAfter = error.retryAfter; // seconds to wait
    await sleep(retryAfter * 1000);
  } else if (error instanceof ValidationError) {
    // 422 — request body failed validation
    console.error(error.details);
  } else if (error instanceof ApiError) {
    // All other API errors
    console.error(error.statusCode, error.code, error.message);
  }
}

See Error Codes for the full list of error codes.

TypeScript types

All request and response types are exported:

import type {
  SendEmailRequest,
  BatchEmailRequest,
  EmailItem,
  DomainItem,
  WebhookItem,
  AnalyticsStats,
} from "sendr";

On this page