Migrate from Resend

Step-by-step guide to migrate from Resend to Postflare.

Overview

Postflare is a Resend-compatible email platform built on Cloudflare infrastructure. The API is designed to be a drop-in replacement for Resend, so migration typically requires minimal code changes.

Key advantages:

  • Resend SDK compatible — keep the official Resend SDK and point it at https://api.postflare.dev

Step 1: Create a Postflare Account

Sign up at app.postflare.dev and create an organization.

Step 2: Configure Your Domain

Add your sending domain in the Postflare dashboard. If you already have SPF, DKIM, and DMARC records configured for Resend, you will need to update them to point to Postflare.

  1. Go to Domains in the dashboard
  2. Click Add Domain and enter your domain name
  3. Update your DNS records as shown in the dashboard
  4. Click Verify to confirm the records are correct

Step 3: Create an API Key

Create a new API key in the Postflare dashboard. Postflare keys start with sk_, not Resend's re_: your Resend key does not carry over.

Step 4: Update Your SDK Configuration

Keep the Resend SDK and change two things: the key, and where the SDK sends. Nothing tells you when the second one is wrong — the SDK sends to https://api.resend.com, which answers.

Node.js / TypeScript

Start your process with RESEND_BASE_URL in its environment:

RESEND_BASE_URL=https://api.postflare.dev

It has to be there before the process starts. Before resend 6.12.4 the SDK reads it once, when the module is imported, so setting process.env.RESEND_BASE_URL in code after the import changes nothing. For the same reason the constructor option new Resend(key, { baseUrl }) only works from 6.12.4 on; older versions ignore it without an error.

+ // Set RESEND_BASE_URL=https://api.postflare.dev in the environment before
+ // the process starts. Without it the SDK sends to api.resend.com, silently.
  import { Resend } from 'resend';

- const resend = new Resend('re_your_resend_key');
+ const resend = new Resend('sk_your_postflare_key');

  // All SDK methods work the same
  const { data, error } = await resend.emails.send({
    from: 'hello@yourdomain.com',
    to: 'user@example.com',
    subject: 'Hello from Postflare',
    html: '<p>It works!</p>',
  });

Python

The Python SDK builds every request from resend.api_url:

  import resend

- resend.api_key = "re_your_resend_key"
+ resend.api_key = "sk_your_postflare_key"
+ resend.api_url = "https://api.postflare.dev"

  params: resend.Emails.SendParams = {
      "from": "hello@yourdomain.com",
      "to": ["user@example.com"],
      "subject": "Hello from Postflare",
      "html": "<p>It works!</p>",
  }

  email = resend.Emails.send(params)

cURL

- curl -X POST 'https://api.resend.com/emails' \
+ curl -X POST 'https://api.postflare.dev/emails' \
-   -H 'Authorization: Bearer re_your_resend_key' \
+   -H 'Authorization: Bearer sk_your_postflare_key' \
    -H 'Content-Type: application/json' \
    -d '{
      "from": "hello@yourdomain.com",
      "to": "user@example.com",
      "subject": "Hello from Postflare",
      "html": "<p>It works!</p>"
    }'

Step 5: Migrate Webhooks

If you use webhooks, create new webhook endpoints in Postflare. The webhook event format is compatible with Resend.

Postflare also supports additional event types not available in Resend:

Event TypeDescription
domain.createdDomain was added
domain.updatedDomain status changed
domain.deletedDomain was removed
contact.createdContact was created
contact.updatedContact was updated
contact.deletedContact was deleted

Step 6: Test

Send a test email to verify everything works:

const { data, error } = await resend.emails.send({
  from: 'hello@yourdomain.com',
  to: 'test@example.com',
  subject: 'Migration Test',
  html: '<p>Postflare is working!</p>',
});

if (error) {
  console.error('Error:', error);
} else {
  console.log('Email sent:', data.id);
}

API Compatibility Reference

The following table lists all Postflare API endpoints and their Resend compatibility status.

Emails

EndpointMethodResend Compatible
/emailsPOSTCompatible
/emails/batchPOSTCompatible
/emailsGETCompatible
/emails/{id}GETCompatible
/emails/{id}PATCHCompatible
/emails/{id}/cancelPOSTCompatible

Domains

EndpointMethodResend Compatible
/domainsPOSTCompatible
/domainsGETCompatible
/domains/{id}GETCompatible
/domains/{id}/verifyPOSTCompatible
/domains/{id}DELETECompatible

Contacts

EndpointMethodResend Compatible
/contactsPOSTPartial -- adds properties, segments, topics fields
/contactsGETPartial -- organization-level instead of audience-scoped
/contacts/{id}GETPartial -- supports lookup by email address
/contacts/{id}PATCHPartial -- adds properties, topics fields
/contacts/{id}DELETEPartial -- supports lookup by email address
/audiences/{audience_id}/contactsPOSTLegacy -- creates the contact in that segment
/audiences/{audience_id}/contacts/{id}GET, PATCH, DELETELegacy -- same as /contacts/{id}

Contacts belong to the organization, and an audience is what Resend now calls a segment. The SDK marks the audienceId argument deprecated; prefer segments on create and segmentId on list. Code that still passes it keeps working: on create, get, update or remove the SDK requests /audiences/{audience_id}/contacts, where create adds the new contact to that segment and the other three act on the contact named by ID or email, whichever audience you pass. On list, the SDK requests /segments/{audience_id}/contacts: the contacts of the segment with that ID, not all of your contacts. On broadcasts.create and broadcasts.update, audienceId is read as segmentId.

API Keys

EndpointMethodResend Compatible
/api-keysPOSTCompatible
/api-keysGETCompatible
/api-keys/{id}DELETECompatible

Webhooks

EndpointMethodResend Compatible
/webhooksPOSTPartial -- additional event types
/webhooksGETCompatible
/webhooks/{id}GETCompatible
/webhooks/{id}PATCHCompatible
/webhooks/{id}DELETECompatible

Additional Postflare Endpoints

Postflare includes additional endpoints not available in Resend:

EndpointMethodDescription
/segmentsPOST/GETSegment management
/segments/{id}GET/DELETESegment operations
/topicsPOST/GETTopic management
/topics/{id}GET/PATCH/DELETETopic operations
/contacts/{id}/segmentsGET/POST/DELETEContact segment membership
/contacts/{id}/topicsGET/PATCHContact topic subscriptions
/broadcastsPOST/GETBroadcast management
/broadcasts/{id}GET/PATCH/DELETEBroadcast operations
/broadcasts/{id}/sendPOSTSend a broadcast
/templatesPOST/GETTemplate management
/templates/{id}GET/PATCH/DELETETemplate operations
/templates/{id}/publishPOSTPublish a template
/templates/{id}/duplicatePOSTDuplicate a template

On this page