PadiMail Docs
SDKs

Node.js SDK

@padimail/node: every endpoint, typed, with retries, React Email and webhook verification.

NeedsAny accountTest keys work as soon as you sign up. Nothing is delivered.
npm install @padimail/node

The SDK uses only fetch and Web Crypto, so it runs in Node 20+, Bun, Deno, Cloudflare Workers, Vercel Edge and Supabase Edge Functions. It's typed from the API's OpenAPI document: your editor knows every field and response.

Server only

The SDK refuses to start in a browser, because anyone who opens the page could read your key. Call PadiMail from your server.

Set up

import { PadiMail } from "@padimail/node";

const pm = new PadiMail(process.env.PADIMAIL_API_KEY, {
  maxRetries: 2, // extra attempts on 429, 5xx and network errors; 0 turns retries off
  timeout: 30_000, // per attempt, in milliseconds
  baseUrl: "https://api.padimail.app", // or set PADIMAIL_BASE_URL
});

With no arguments, new PadiMail() reads PADIMAIL_API_KEY.

Methods

ResourceMethods
pm.emailssend, batch, list, get, events, content, update, cancel
pm.domainscreate, list, get, verify, update, remove
pm.apiKeyscreate, list, remove
pm.suppressionslist, create, remove
pm.webhookscreate, list, get, update, remove, rotateSecret, test, deliveries.list, deliveries.retry, verify
pm.templatescreate, list, get, update, remove, publish, render, versions
pm.accountget, usage
pm.health()Is the API up?

Each method matches an endpoint in the API reference, which shows the SDK call next to cURL and Python. Every method takes a last options argument: { idempotencyKey, maxRetries, timeout, signal, headers }.

Errors

Every failure throws a PadiMailError with the API's error fields:

import { PadiMailError } from "@padimail/node";

try {
  await pm.emails.send(email);
} catch (err) {
  if (err instanceof PadiMailError) {
    console.log(err.status, err.code, err.message, err.fields, err.docUrl, err.requestId);
  }
}

Branch on err.code (see Errors). Network failures and timeouts have status: 0 and code connection_error or timeout.

Retries and idempotency

The SDK retries network errors, 429 and 5xx (except 501), backing off from half a second and honouring Retry-After up to 60 seconds. It doesn't retry quota limits. Every POST gets an Idempotency-Key, the same across retries, so a retry can't send twice. Pass your own to also cover your app's retries:

await pm.emails.send(receipt, { idempotencyKey: `receipt-${order.id}` });

The same request with cURL:

curl -X POST https://api.padimail.app/v1/emails -H "Authorization: Bearer $PADIMAIL_API_KEY" -H "Idempotency-Key: receipt-1042" -H "Content-Type: application/json" -d @receipt.json

Pagination

List methods return one page, { data, has_more, next }. To walk every item:

for await (const email of pm.paginate(pm.emails.list, { status: "bounced" })) {
  console.log(email.id, email.to);
}

React Email

Install @react-email/render, then pass a component as react. See React Email.

await pm.emails.send({ from, to, subject: "Your receipt", react: <ReceiptEmail orderNo="1042" /> });

Webhooks

import { verifyWebhook } from "@padimail/node";

const event = await verifyWebhook({ payload: rawBody, headers: req.headers, secret: process.env.PADIMAIL_WEBHOOK_SECRET! });

See Verify signatures. WEBHOOK_EVENT_TYPES lists every event type, and signWebhookHeaders signs a test body the way we do, for testing your handler.

Types

Request and response types are exported:

import type { Email, EmailSummary, Domain, SendEmailRequest, WebhookEvent } from "@padimail/node";
Was this page helpful?

On this page