Switch from Resend
Point your existing Resend code at PadiMail by changing two environment variables. Switch back the same way.
PadiMail has a Resend-compatible API. It accepts Resend's request shapes and returns Resend's response and error shapes, so the Resend SDK and your existing code keep working. Underneath it's the same as our own API: the same verification, scanning, suppressions, limits and billing.
1. Change two variables
RESEND_BASE_URL=https://api.padimail.app/resend
RESEND_API_KEY=pm_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxResend's Node SDK reads RESEND_BASE_URL when you don't pass a base URL in code, and so do its Go and Rust SDKs. If your code passes a base URL to the constructor, change that one value instead.
Your code doesn't change:
import { Resend } from "resend";
const resend = new Resend(process.env.RESEND_API_KEY);
const { data, error } = await resend.emails.send({
from: "Acme Store <hello@acme.ng>",
to: ["ada@example.com"],
subject: "Your receipt #1042",
react: <ReceiptEmail orderNo="1042" />,
});The same with cURL:
curl -X POST https://api.padimail.app/resend/emails \
-H "Authorization: Bearer $RESEND_API_KEY" -H "Content-Type: application/json" \
-d '{"from": "Acme Store <hello@acme.ng>", "to": "ada@example.com", "subject": "Your receipt #1042", "html": "<p>Thanks.</p>"}'2. Bring your domains across
Add each sending domain under Domains (or with the API). We show the DNS records to add. Your Resend records can stay in place while you switch, so you can move back at any time.
3. Point your webhooks at us
Create a webhook endpoint with the Resend payload format. We then send Resend's event names and payload shape, signed with the same svix-* headers, so your existing verification code keeps working. Use the new signing secret we show you. Resend has no account.* events, so an endpoint in the Resend format never receives them; to get usage alerts (account.usage_threshold, account.usage_spike) by webhook, add a second endpoint in the PadiMail format.
What's covered
| Area | Endpoints |
|---|---|
| Emails | Send, batch, get, update the schedule, cancel |
| Domains | Create, list, get, verify, delete |
| API keys | Create, list, delete |
Anything else returns 501 with a link to the equivalent in our own API. Audiences and contacts come later.
Differences to know about
- Errors use Resend's shape (
statusCode,message,name). Our own error code is added aspm_code, and explained on the Errors page. - Extras: you can pass our fields
quota_behavior,streamandfallbackin a Resend send call. Over a limit, emails wait by default instead of failing; passquota_behavior: "reject"for login codes. - Test keys:
pm_test_keys work through the Resend SDK too, and never deliver real email. - SMTP: if you use Resend's SMTP, change the host to
smtp.padimail.appand the password to your PadiMail key. The usernameresendis accepted.
Switch back
Set RESEND_BASE_URL and RESEND_API_KEY back to Resend's values and redeploy. Nothing else changes.
Or use our SDK
Our own Node SDK covers every endpoint, retries for you and verifies webhooks:
import { PadiMail } from "@padimail/node";
const pm = new PadiMail(process.env.PADIMAIL_API_KEY);
await pm.emails.send({ from: "Acme Store <hello@acme.ng>", to: "ada@example.com", subject: "Your receipt", react: <ReceiptEmail orderNo="1042" /> });