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.
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
| Method | Description |
|---|
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. |