Migration API

The Migration API is a read-only export of an entire channel. It exists to move a channel, or a whole installation, to another Broadcast server: it returns everything needed to rebuild the channel elsewhere, including the secrets the regular API never returns.

It lives under /api/migration/v1, separate from the regular /api/v1 API, and nothing in it writes data.

Warning

Treat a token used here like a database backup. The Migration API returns email server credentials (SMTP passwords, AWS secret keys, provider API keys) and channel API token values in plain text, and lists every user on the installation with their sudo flag. It accepts any channel ID. Use a dedicated admin API token for a migration, keep it out of logs and shared tools, and delete it when the migration is done.

Authentication

Every request needs an admin API token in the Authorization header. Channel tokens are rejected, because the export reaches across channels. Create admin API tokens under Application → Admin API Tokens, see API Authentication.

curl https://broadcast.example.com/api/migration/v1/manifest?broadcast_channel_id=1 \
  -H "Authorization: Bearer YOUR_ADMIN_API_TOKEN"

Any valid, unexpired admin API token can read the Migration API; its resource permissions do not narrow it. The whole API is switched off in demo mode and answers 403.

Every endpoint except channels and users needs a broadcast_channel_id query parameter naming the channel to export. Start with channels to find the IDs.

Status Meaning
400 Bad Request broadcast_channel_id is missing
401 Unauthorized No token, an unknown token, a channel token, or an expired admin token
403 Forbidden The installation is in demo mode
404 Not Found The channel or file asset does not exist

Manifest

GET /api/migration/v1/manifest?broadcast_channel_id=1

Sizes the export before you start: how many of each record the channel has, so you can check the import afterwards.

{
  "export_format_version": 1,
  "exported_at": "2026-10-03T14:30:00Z",
  "broadcast_channel": { "id": 1, "name": "Newsletter", "slug": "newsletter" },
  "counts": {
    "subscribers": 12840,
    "templates": 14,
    "segments": 6,
    "sequences": 3,
    "email_servers": 2,
    "opt_in_forms": 4,
    "broadcasts": 11,
    "webhook_endpoints": 1,
    "tokens": 2,
    "global_suppressions": 37,
    "unsubscribed_emails": 412,
    "tags": 18,
    "link_redirects": 230,
    "file_assets": 41
  },
  "recent_history": {
    "days": 90,
    "broadcasts": 11,
    "outbound_receipts": 98412
  }
}

broadcasts and recent_history cover only the last days_history days (see below). global_suppressions counts the installation-wide list plus anything recorded against this channel.

Note

unsubscribed_emails is the channel’s own suppression list, exported by /unsubscribed_emails (Broadcast 2.40.0 or later). global_suppressions is the installation-wide list, exported by /suppressions. A complete export needs both.

Resources

Each resource is a GET that returns { "data": [...] }.

Endpoint Returns Paginated
/channels Every channel on the installation No
/users Every user, with their sudo flag, system permissions and channel permissions No
/subscribers The channel’s subscribers, including custom data and tags Yes
/tags Subscriber tags used in the channel No
/subscriber_histories Subscriber history entries Yes
/suppressions Global suppressions, plus any recorded against this channel Yes
/unsubscribed_emails The channel’s own suppression list (2.40.0 or later) Yes
/templates Templates Yes
/segments Segments with their rule groups and rules No
/sequences Sequences with their steps No
/email_servers Email servers, including credentials No
/opt_in_forms Opt-in forms No
/webhook_endpoints Webhook endpoints No
/tokens Channel API tokens, including their values No
/broadcasts Broadcasts from the last days_history days Yes
/outbound_receipts Delivery receipts for those broadcasts Yes
/link_redirects Tracked links Yes
/link_clicks Link clicks from the last days_history days Yes
/file_assets File asset metadata Yes

All paths are relative to /api/migration/v1.

Pagination

Paginated endpoints take limit (1 to 250, default 250) and offset (default 0), and return a pagination object next to data:

{
  "data": [ ... ],
  "pagination": { "total": 12840, "limit": 250, "offset": 0, "has_more": true }
}

Keep requesting with offset increased by the limit in the response until has_more is false. Advance by the returned limit, not the one you asked for: a limit above 250 is reduced to 250.

Recent history

broadcasts, outbound_receipts, link_clicks and the manifest accept days_history (1 to 365, default 90). Older sends are left out so an export of a busy channel stays a manageable size.

The channel suppression list

GET /api/migration/v1/unsubscribed_emails?broadcast_channel_id=1

Returns every address on the channel’s own suppression list, paginated like the other resources. Its pagination.total matches counts.unsubscribed_emails in the manifest, so you can check that nothing was missed.

{
  "data": [
    {
      "id": 88,
      "email": "former.subscriber@example.com",
      "broadcast_channel_id": 1,
      "created_at": "2026-03-14T09:12:00Z",
      "updated_at": "2026-03-14T09:12:00Z"
    }
  ],
  "pagination": { "total": 412, "limit": 250, "offset": 0, "has_more": true }
}

This is a different list from /suppressions, which holds the installation-wide global list. Export both. On the new server, add these addresses to the channel with the bulk endpoint of the Suppressions API.

Before 2.40.0 this endpoint did not exist. On an older server, read the channel list with GET /api/v1/suppressions instead.

Downloading file assets

GET /api/migration/v1/file_assets/:id/download?broadcast_channel_id=1

Returns the original file’s bytes, for re-uploading on the new server. A file asset whose file is missing answers 404.

Using an SDK

The official SDKs wrap the Migration API, handling pagination for you: client.migration.manifest and client.migration.each_record in the Ruby SDK, with the same methods in the Node, Python and PHP SDKs. See SDKs & Client Libraries.

SDK Channel suppression list
Ruby client.migration.each_record(:unsubscribed_emails)
Node client.migration.eachRecord('unsubscribedEmails')
Python client.migration.each_record("unsubscribed_emails")
PHP $client->migration->eachRecord('unsubscribedEmails')

These collections need Ruby 0.6.0, Node 0.3.0, Python 0.3.0 or PHP 0.4.0 or later, and Broadcast 2.40.0 or later.

Last updated

Was this page helpful?

Thanks for your feedback!

Thanks for letting us know. We'll work on improving this page.