Skip to content

Migrating from Resend

SpacePost implements the Resend API: same paths, same field names, same response shapes and the same error format. Most apps migrate by changing a base URL and an API key.

  1. Create a SpacePost API key in the dashboard. SpacePost keys start with sp_live_ (Resend keys start with re_).

  2. Add and verify your domain in SpacePost. DNS records differ from Resend’s, so add the new DKIM CNAMEs and the send MX/TXT records. You can keep Resend’s records in place while you cut over, because DKIM selectors do not collide. See Adding and verifying. Move your SPF/DMARC policy only if you changed the send subdomain.

  3. Switch the client. Pick one of the options below.

    Keep the official resend package. Set the base URL with an environment variable and use your SpacePost key:

    .env
    RESEND_API_KEY=sp_live_YOUR_API_KEY
    RESEND_BASE_URL=https://api.spacepost.dev
    import { Resend } from "resend";
    const resend = new Resend(process.env.RESEND_API_KEY);
    await resend.emails.send({ from: "Acme <hello@acme.com>", to: "you@example.com", subject: "Hi", html: "<p>Hi</p>" });

    Or pass it in code:

    const resend = new Resend("sp_live_YOUR_API_KEY", { baseUrl: "https://api.spacepost.dev" });
  4. Recreate your webhooks. Create each endpoint again in SpacePost (POST /webhooks) and store the new signing_secret. Verification code written for Resend or Svix keeps working because SpacePost sends the same Standard Webhooks headers (plus svix-* duplicates). See Verifying signatures.

  5. Move audiences and contacts. Create audiences and import contacts through POST /audiences/{id}/contacts. Placeholders such as {{{FIRST_NAME|fallback}}} and {{{RESEND_UNSUBSCRIBE_URL}}} work unchanged in broadcasts.

  6. Send a test, then cut over. Send to delivered@test.spacepost.dev, check the webhook arrives, then deploy.

Resend feature SpacePost Notes
POST /emails Supported to/cc/bcc/reply_to up to 50 each; camelCase aliases replyTo, scheduledAt accepted
POST /emails/batch Supported Up to 100 emails; attachments and scheduled_at are allowed per email; all-or-nothing
GET /emails/{id}, GET /emails Supported List omits bodies
PATCH /emails/{id} Supported Reschedule scheduled emails
POST /emails/{id}/cancel Supported Scheduled emails only
Attachments (content, path) Supported path must be https
Tags, custom headers Supported Same constraints on tag characters
Idempotency-Key Supported 24 hours, POST /emails and /emails/batch
Domains (create, get, list, verify, update, delete) Supported open_tracking, click_tracking
API keys Supported full_access, sending_access, optional domain_id
Webhooks, Standard Webhooks signing Supported Also svix-* headers
Audiences, contacts, broadcasts Supported Contacts live under /audiences/{id}/contacts
Suppressions API Supported Extra: list, add and remove entries
Tenants (platform mode) SpacePost only Isolated reputation per customer; see Platform mode. The Resend SDK drops tenant_id; use resend.post or tenant-owned domains
SMTP relay Supported smtp.spacepost.dev:25976 with STARTTLS (no implicit TLS on 465 yet)
Inbound email Not yet
Templates editor Not yet Use React Email or your own HTML
  • last_event values. Resend’s values (queued, scheduled, sent, delivered, delivery_delayed, bounced, complained, opened, clicked, canceled, failed) are all present. SpacePost adds suppressed, used when every recipient was on your suppression list. Status never moves backwards: an opened event arriving before delivered keeps the later state.
  • Extra webhook event. email.suppressed fires when a recipient is skipped because it is suppressed. Subscribe only to the events you handle. Payloads are otherwise identical to Resend’s; data.tenant_id is added for tenant mail.
  • Rate limit. 10 requests per second per team (25 on Scale) versus 2 on Resend, with the same ratelimit-* headers.
  • Pricing. Pro is €9 for 50,000 emails with €0.25 per extra 1,000, billed in EUR excluding VAT (Resend Pro: USD 20 with USD 0.90 per extra 1,000, Resend’s USD prices as of 23 October 2026). After the first 7 days every plan, including Free, has a daily cap that grows with your sending: the larger of 1,000 and twice your best day in the last 14 days, up to 50,000 per day. See Plans and quotas.
  • What counts as an email. Every recipient counts: one email to 3 recipients (to, cc and bcc together) counts 3 against your quota.
  • Test sender. onboarding@test.spacepost.dev replaces onboarding@resend.dev. Test inboxes live at test.spacepost.dev instead of resend.dev: delivered@, bounced@, complained@, delayed@, plus softbounced@ (SpacePost only).
  • New-account sandbox. The first 7 days are limited to 100 emails per day. See Verification and limits.
  • Automatic pausing. Teams with abnormal bounce or complaint rates are paused automatically. See Automatic pausing.
  • Base URL. https://api.spacepost.dev, with paths at the root. A /v1 prefix is also accepted (https://api.spacepost.dev/v1/emails).