PristineSend
Get started
Guides

Node / TypeScript SDK

The official pristinesend package is the fastest way to call the API from Node or TypeScript. It encodes the whole contract — typed methods and errors, an auto-paginating cursor iterator, automatic idempotency on sends, retry/backoff, and a react: convenience for React Email. ESM + CJS, no required dependencies.

Install

npm install pristinesend
# optional — only if you use the react: convenience
npm install @react"color:#ff7b72">-email/render react

Initialize

Pass your API key. A ps_test_ key runs in the sandbox (captured, not delivered).

"color:#ff7b72">import { PristineSend } "color:#ff7b72">from "pristinesend"

"color:#ff7b72">const ps = "color:#ff7b72">new PristineSend(process.env.PRISTINESEND_API_KEY!) // ps_live_… or ps_test_…

// Options:
"color:#ff7b72">const client = "color:#ff7b72">new PristineSend({
  apiKey: process.env.PRISTINESEND_API_KEY!,
  maxRetries: 4,   // default 2
  timeout: 30_000, // ms, default 60000
})

Sending email

"color:#ff7b72">const { id } = "color:#ff7b72">await ps.emails.send({
  to: "customer@example.com",
  "color:#ff7b72">from: "you@yourdomain.com", // omit to use your workspace default sender
  subject: "Welcome!",
  html: "<h1>Hello</h1>",
})

// Batch (up to 100) — partial success, one bad recipient never fails the rest:
"color:#ff7b72">const batch = "color:#ff7b72">await ps.emails.sendBatch({
  emails: [
    { to: "a@example.com", subject: "Hi", html: "<p>1</p>" },
    { to: "b@example.com", subject: "Hi", html: "<p>2</p>" },
  ],
})
console.log(batch.summary) // { total, sent, failed }

Idempotency is automatic:

// An Idempotency-Key is sent automatically (auto-generated unless you pass one),
// so a network retry never double-sends — the server replays the original result.
"color:#ff7b72">await ps.emails.send({ to, subject, html, idempotencyKey: "order-1234-receipt" })

React Email

Pass a React Email component as react; the SDK lazily imports @react-email/render and sends the rendered HTML.

"color:#ff7b72">import { WelcomeEmail } "color:#ff7b72">from "./emails/welcome"

"color:#ff7b72">await ps.emails.send({
  to: "customer@example.com",
  subject: "Welcome!",
  react: <WelcomeEmail name="Sam" />, // rendered to html via @react-email/render
})

HTML-only for now: the API has no text field yet, so React Email's plaintext alternative is dropped. The SDK will send it automatically once the field lands.

Pagination

Every list() returns a page that auto-paginates when iterated — see Pagination.

// The returned page is "color:#ff7b72">async-iterable and fetches the next page on demand:
for "color:#ff7b72">await ("color:#ff7b72">const contact of "color:#ff7b72">await ps.contacts.list({ limit: 100 })) {
  console.log(contact.email)
}

// Or one page at a time:
"color:#ff7b72">const page = "color:#ff7b72">await ps.contacts.list()
console.log(page.data, page.has_more, page.next_cursor)
"color:#ff7b72">const next = "color:#ff7b72">await page.nextPage()

Errors

Every failure is a typed subclass of PristineSendError carrying the API's code, the offending param, and the requestId to quote to support. See Error codes.

"color:#ff7b72">import { PristineSendError, RateLimitError } "color:#ff7b72">from "pristinesend"

try {
  "color:#ff7b72">await ps.emails.send({ to, subject, html })
} catch (err) {
  if (err instanceof RateLimitError) {
    console.log("retry after", err.retryAfter, "seconds")
  } else if (err instanceof PristineSendError) {
    console.error(err.code, err.message, "request:", err.requestId)
  }
}

Retries & rate limits

The client retries up to maxRetries times (default 2) on 429, 502, 503, and network errors, honoring Retry-After with exponential backoff. See Rate limits.

Method reference

MethodDescription
emails.send(params)Send one email. Pass html or react:.
emails.sendBatch(params)Send up to 100 (207 per-item result).
emails.get(id)Retrieve one sent email.
emails.list(params?)List sent emails (auto-paginating).
contacts.create(params)Create a contact.
contacts.get(id)Retrieve a contact.
contacts.update(id, params)Update a contact (merges properties).
contacts.delete(id)Delete a contact.
contacts.list(params?)List contacts (auto-paginating).
domains.list(params?)List verified sending domains.
suppressions.create(params)Add an email to the do-not-send list.
suppressions.delete(params)Remove an email (pass force to lift a bounce/complaint).
suppressions.list(params?)List suppressions.
events.list(params?)List the webhook delivery log.