Blue Reacher
Migrating from another platform8 / 50

Migrating from another platform

Move an existing iMessage program onto Blue Reacher without losing conversation history, suppression records, or line health.

Migrations fail in one of two ways: the suppression list does not come across, or the new lines get treated like the old mature ones and burn out in week one. Both are avoidable.

Step 1: export before you cancel

Get these out of the old platform while you still have access, because most providers cut API access at cancellation and support-ticket exports take days:

  1. Contacts, with phone numbers in E.164 and whatever record IDs you used.
  2. The complete suppression and opt-out list, with timestamps. This is the one that matters most.
  3. Message history, at minimum for contacts with open conversations.
  4. Consent records, if the old platform held them rather than your CRM.

Step 2: import suppression first, before anything else

Load every opt-out into Blue Reacher before you import a single contact and before you send anything. Messaging someone who opted out on your old platform is a compliance violation that carries over with you; the obligation attached to your company, not to the vendor.

for (const record of oldOptOuts) {
  // Contact must exist first; opt-out writes never auto-create.
  await fetch("https://api.bluereacher.com/v1/contacts", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.BLUEREACHER_API_KEY}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({ phone_number: record.phone })
  });
  await fetch("https://api.bluereacher.com/v1/opt-out", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.BLUEREACHER_API_KEY}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({ phone: record.phone, opted_out: true })
  });
}

Opt-out writes are idempotent: re-running the import returns already_opted_out: true rather than creating duplicates. The suppression model is documented in contacts and opt-out.

Step 3: import contacts with your CRM IDs

Contact upserts key on phone_number, so re-imports update rather than duplicate. Carry your CRM record ID in custom_fields (for example { "crm_id": "..." }); the old platform's contact IDs stop being useful the day you finish the migration. Bulk import is in contacts.

Step 4: treat new lines as new lines

This is where migrations go wrong. Your old lines were mature and sending at full volume. Your Blue Reacher lines are new, and they ramp from a handful of new contacts a day up to the full policy caps (50 opted-in / 30 cold) over roughly four weeks of active days, per rate limits. Remember what is not capped: contacts who ever replied, and anyone you have messaged before, are unlimited from day one, so an engaged book migrates at full speed even while cold outreach ramps.

Two ways to handle the gap:

  1. Run both platforms in parallel for the ramp period, shifting volume across as capacity comes online. More expensive for a month, no drop in output.
  2. Provision enough lines to cover your target volume at week-one capacity, then keep them as headroom afterwards. More lines, no parallel running.

What does not work is pushing new lines at your old volume. The pacing is enforced, so excess cold sends queue for later days rather than burning the line, but a program built on the assumption of day-one full cold volume will still miss its numbers.

Step 5: rewire the integration

Outbound: point your automation at POST /v1/messages, per the send reference. Inbound: register your webhook endpoint and verify the X-BlueReacher-Signature HMAC, per webhooks.

Differences worth checking against your old provider's shape:

  • Auth is a bearer token in the Authorization header, prefixed brk_. Some platforms use a raw key with no prefix, so a copied header pattern will fail with 401.
  • Numbers must be E.164. Platforms that accepted loose formatting will have left non-normalized numbers in your export.
  • Webhook events are message.received, message.sent, message.delivered, message.failed, contact.opted_out, and device.status_changed. Map these to your old event names explicitly rather than assuming a match.
  • Errors branch on a stable error_code, not on the message text. The full list is in errors and status codes.

Step 6: cut over on a slice

Move one segment, one campaign, or one rep first. Run it for a week. Confirm sends land, replies arrive on the right records, opt-outs propagate, and the reply queue works with the new notification path. Then move the rest.

Migration checklist

  • Everything exported before cancelling the old account
  • Suppression list imported first and verified with a spot check
  • Contacts imported with CRM IDs in custom_fields
  • Line capacity planned for the ramp, with parallel running or extra lines
  • Outbound automation repointed and tested end to end
  • Webhook endpoint registered, signature verification confirmed
  • One slice cut over and observed for a week
  • Old platform cancelled only after the slice ran clean

On this page