Introduction

Sendridge is a transactional email platform for developers. You verify a sending domain, grab an API key, and send email through a simple HTTPS API — Sendridge handles queuing, delivery, retries, and tracking (opens, clicks, bounces, complaints).

There are two ways to integrate: the official Node.js SDK (recommended) or the REST API directly from any language.

Sendridge API keys are server-side secrets. Never use the SDK or your API key in browser code — anyone viewing your page could read the key and send email from your domain.

Quickstart

  1. 1Create an account and verify your sending domain (Dashboard → Domains). Sendridge gives you DNS records to add; verification usually completes in minutes.
  2. 2Create an API key (Dashboard → API Keys). Keys look like sr_… and are shown once — store yours securely.
  3. 3Install the SDK and send your first email:
bash
npm install sendridge
send.ts
import { Sendridge } from "sendridge";

const sendridge = new Sendridge(process.env.SENDRIDGE_API_KEY);

const { id } = await sendridge.emails.send({
  from: "you@yourdomain.com",
  to: "customer@example.com",
  subject: "Welcome aboard!",
  html: "<h1>Hello 👋</h1><p>Thanks for signing up.</p>",
});

console.log(`Queued email ${id}`);

Sending is asynchronous: the API responds immediately with status: "queued", then Sendridge delivers in the background. Use emails.get(id) to follow the delivery status.

Authentication

Every request is authenticated with your API key as a Bearer token. The SDK does this for you; for direct REST calls, send the header yourself:

bash
Authorization: Bearer sr_xxxxxxxxxxxxxxxx

Best practice: keep the key in an environment variable. The SDK automatically reads SENDRIDGE_API_KEY when you don't pass a key to the constructor.

Keys can be scoped with permissions (read, write, send), restricted to IP allowlists, given expiry dates and per-minute rate caps, and rotated at any time — all from the dashboard. A rotated or revoked key stops working immediately.

SDK — Installation

bash
npm install sendridge

Requires Node.js 18+. The package ships TypeScript types, works with both import (ESM) and require (CommonJS), and has zero runtime dependencies.

ts
// ESM / TypeScript
import { Sendridge } from "sendridge";

// CommonJS
const { Sendridge } = require("sendridge");

const sendridge = new Sendridge(); // reads SENDRIDGE_API_KEY

SDK — Send an email

ts
const result = await sendridge.emails.send({
  from: "billing@yourdomain.com",        // domain must be verified
  to: ["a@example.com", "b@example.com"], // string or array, max 50
  subject: "Your invoice",
  html: "<p>Invoice attached below.</p>",
  text: "Invoice attached below.",        // plain-text alternative
  replyTo: "support@yourdomain.com",
  tags: { type: "invoice" },
  metadata: { invoiceId: "INV-2026-0042" },
});

// result:
// {
//   id: "665f1c2e9b1d2a0012345678",
//   status: "queued",
//   to: ["a@example.com", "b@example.com"],
//   from: "billing@yourdomain.com",
//   subject: "Your invoice",
//   createdAt: "2026-07-15T10:30:00.000Z"
// }
FieldTypeRequiredDescription
fromstringYesSender address. Its domain must be verified in your dashboard.
tostring | string[]YesOne recipient, or up to 50.
subjectstringYesSubject line (max 998 chars).
htmlstringOne of html/textHTML body.
textstringOne of html/textPlain-text body.
replyTostringNoReply-To address.
tagsRecord<string, string>NoString tags for your own filtering.
metadataRecord<string, unknown>NoArbitrary JSON stored with the email.
The SDK never retries a failed send automatically — a retried POST could deliver the same email twice. If you retry sends yourself, make sure your logic is idempotent.

SDK — Retrieve an email

ts
const email = await sendridge.emails.get("665f1c2e9b1d2a0012345678");

// email.status is one of:
// "queued" | "sending" | "sent" | "delivered" | "bounced" | "failed" | "complained"

console.log(email.status, email.openCount, email.clickCount);

The returned object includes the full body (html/text), delivery status, open and click counts, your tags and metadata, and an errorMessage when delivery failed.

SDK — List emails

ts
const { data, pagination } = await sendridge.emails.list({ page: 1, limit: 20 });

for (const email of data) {
  console.log(email.id, email.subject, email.status);
}
// pagination: { page: 1, limit: 20, total: 132 }

SDK — Error handling

Every failure throws a typed subclass of SendridgeError, so you can branch on the exact failure mode:

ts
import {
  SendridgeError,
  ValidationError,     // 400 — bad payload; err.details has field errors
  AuthenticationError, // 401 — missing / invalid / revoked / expired key
  PermissionError,     // 403 — e.g. unverified domain, plan restriction
  NotFoundError,       // 404 — unknown email id
  RateLimitError,      // 429 — rate limit or quota exceeded
  ServerError,         // 5xx — Sendridge-side problem
  TimeoutError,        // request exceeded the timeout
  NetworkError,        // DNS / connection failure
} from "sendridge";

try {
  await sendridge.emails.send({ /* ... */ });
} catch (err) {
  if (err instanceof RateLimitError) {
    // back off, then try again
  } else if (err instanceof ValidationError) {
    console.error(err.message, err.details);
  } else if (err instanceof SendridgeError) {
    console.error(err.statusCode, err.message);
  } else {
    throw err;
  }
}

Idempotent reads (get, list) automatically retry up to twice on network failures and 5xx/429 responses, with exponential backoff. Sends are never retried.

SDK — Configuration

ts
const sendridge = new Sendridge("sr_...", {
  baseUrl: "https://api.sendridge.com", // override for self-hosted / local dev
  timeoutMs: 30_000,                    // per-request timeout (default 30s)
  maxRetries: 2,                        // GET-only automatic retries (default 2)
});

REST API — Overview

Prefer another language? The REST API is the same surface the SDK wraps. All endpoints accept and return JSON.

text
Base URL:  https://api.sendridge.com
Auth:      Authorization: Bearer sr_xxxxxxxxxxxxxxxx

Successful responses wrap the payload in a data field; errors return { error, message, details? }.

POST /v1/emails/send

Queues an email for delivery. Responds 202 Accepted.

bash
curl -X POST https://api.sendridge.com/v1/emails/send \
  -H "Authorization: Bearer $SENDRIDGE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "you@yourdomain.com",
    "to": "customer@example.com",
    "subject": "Welcome!",
    "html": "<h1>Hello</h1>"
  }'
202 Accepted
{
  "data": {
    "id": "665f1c2e9b1d2a0012345678",
    "status": "queued",
    "to": ["customer@example.com"],
    "from": "you@yourdomain.com",
    "subject": "Welcome!",
    "createdAt": "2026-07-15T10:30:00.000Z"
  },
  "message": "Email queued for delivery"
}

GET /v1/emails/:id

Returns a single email you own, including delivery status and engagement counts.

bash
curl https://api.sendridge.com/v1/emails/665f1c2e9b1d2a0012345678 \
  -H "Authorization: Bearer $SENDRIDGE_API_KEY"
200 OK
{
  "data": {
    "_id": "665f1c2e9b1d2a0012345678",
    "to": ["customer@example.com"],
    "from": "you@yourdomain.com",
    "subject": "Welcome!",
    "status": "delivered",
    "openCount": 2,
    "clickCount": 1,
    "createdAt": "2026-07-15T10:30:00.000Z",
    "updatedAt": "2026-07-15T10:30:04.000Z"
  }
}

GET /v1/emails

Paginated list of your emails, newest first. Query params: page (default 1) and limit (default 20).

bash
curl "https://api.sendridge.com/v1/emails?page=1&limit=20" \
  -H "Authorization: Bearer $SENDRIDGE_API_KEY"

REST API — Errors

StatusMeaningTypical causes
400Validation errorMissing/invalid fields; details lists per-field errors
401UnauthorizedMissing, invalid, revoked, or expired API key
403ForbiddenUnverified sending domain, key permissions, IP allowlist, plan restrictions
404Not foundUnknown email id
429Too many requestsPer-minute/hour rate limit or monthly quota exceeded
5xxServer errorSendridge-side problem — safe to retry idempotent requests
Example error
{
  "error": "Validation Error",
  "message": "Invalid request data",
  "details": { "from": ["Invalid email"] }
}

Rate limits

Sending limits depend on your plan (per-minute, per-hour, and monthly quotas), and individual API keys can carry an extra per-minute cap set in the dashboard. When you hit a limit the API returns 429 with a message describing which limit was exceeded — back off and retry after a short delay.