This is a young category built on arrangements Apple has not sanctioned. Vendors get acquired, change pricing, or stop working. Assume you will switch at least once and the cost of switching drops enormously — and read what happens if Apple shuts this down for the version of this risk nobody selling you an API wants to discuss.
Build behind your own interface from day one
Never call a vendor SDK from your application code. One thin adapter, one interface, and the vendor becomes a swappable detail rather than a dependency threaded through forty files.
// Your app only ever knows about this shape.export type Messenger = { send(to: string, text: string, opts?: SendOptions): Promise<{ id: string }>; parseInbound(rawBody: string, headers: Headers): InboundEvent | null;}; // Swapping vendors becomes a one-line change here.import { sendblue } from "./adapters/sendblue";import { blooio } from "./adapters/blooio"; export const messenger: Messenger = process.env.MESSAGING_VENDOR === "blooio" ? blooio : sendblue;Own your consent and opt-out data
This is the one that hurts. If opt-out state lives only in a vendor dashboard, switching resurrects people who unsubscribed — a compliance failure and an unforced insult. Keep the consent table in your own database, always.
What to export before you leave
- The full opt-out list, with timestamps.
- Message history per customer, if you do not already mirror it locally.
- Delivery-status history, if you use it for reporting or reconciliation.
- Your number — this is a port, not an export, and it takes the longest. Start here.
Run both in parallel
Do not cut over on a Friday. Stand the new vendor up alongside the old one, route a small share of low-stakes traffic through it — internal alerts, then non-urgent confirmations — and watch delivery rates for a week before you move anything that matters.
// Deterministic split so a given customer stays on one vendor// throughout the migration rather than flapping between them.export function vendorFor(customerId: string, newVendorPct: number) { const bucket = hashToPercent(customerId); return bucket < newVendorPct ? blooio : sendblue;} // Ramp 5% → 25% → 50% → 100%, watching delivery rate at each step.Watch the right metric during cutover
Not send success — that is nearly always 100%. Watch delivered rate from webhooks, and watch reply rate. A new vendor with an unwarmed number will show a healthy send rate and a quietly terrible delivered rate, and only the webhook data will tell you. See deliverability.
Next step
Generate a tagged link for whatever you send next with the UTM builder, see what this looks like in your industry, or compare the services that can send it on the providers page.