Migrating from Subscriptions v1 to v2
This guide walks you through migrating your existing Subscriptions v1 configurations to the modern Subscriptions v2 platform. Both versions are supported simultaneously, so you can migrate at your own pace without disrupting existing integrations.
Why migrate?
Subscriptions v2 offers several improvements over the legacy v1 platform:
| Feature | Subscriptions v1 | Subscriptions v2 |
|---|---|---|
| API format | XML | JSON |
| Security | Basic authentication | Basic authentication + HMAC payload signing |
| Filtering | Order ID only | Multiple fields (order type, event type, order ID, phone number, group, etc.) |
| Subscription model | Per order type | Predefined subscription definitions with flexible filters |
Key concept changes
From order types to subscription definitions
In v1, you created one subscription per OrderType (e.g., orders, portins, disconnects). In v2, a subscription definition is a named category of events. A single subscription definition can cover multiple order types, and you use filters to narrow down which events you receive.
The two subscription definitions currently available in v2 are:
| v2 Subscription Definition | Covers |
|---|---|
Bandwidth_App_Order_Update | Order status changes and notes for all order types (replaces v1 OrderType subscriptions) |
Number_Reputation_Management_Monitoring_Update | Number reputation monitoring state changes |
From XML to JSON
v1 uses an XML request/response body. v2 uses JSON throughout.
From polling-style expiry to persistent subscriptions
v1 required you to set an Expiry in seconds (e.g., 3122064000 for ~99 years). v2 subscriptions do not use a time-based expiry field — subscriptions persist until explicitly deleted.
New: HMAC signature verification
v2 includes an X-Bandwidth-Signature-SHA-256 header on every webhook delivery. You can use this to cryptographically verify that payloads originate from Bandwidth. See HMAC Signature Implementation for details.
Migration steps
Step 1 — Audit your existing v1 subscriptions
Retrieve your current v1 subscriptions:
GET https://api.bandwidth.com/api/accounts/{accountId}/subscriptions HTTP/1.1
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
Note each subscription's OrderType or EventType, URL, and any CallbackCredentials. You will recreate these in v2.
Step 2 — Map your v1 order types to v2 subscription definitions
Use the table below to identify which v2 subscription definition covers each of your v1 order type subscriptions.
v1 OrderType | v2 Subscription Definition | v2 filters array element value |
|---|---|---|
orders | Bandwidth_App_Order_Update | {"field": "orderType", "operator": "EQ", "value": "orders"} |
portins | Bandwidth_App_Order_Update | {"field": "orderType", "operator": "EQ", "value": "portins"} |
portouts | Bandwidth_App_Order_Update | {"field": "orderType", "operator": "EQ", "value": "portouts"} |
disconnects | Bandwidth_App_Order_Update | {"field": "orderType", "operator": "EQ", "value": "disconnects"} |
dldas | Bandwidth_App_Order_Update | {"field": "orderType", "operator": "EQ", "value": "dldas"} |
lsrorders | Bandwidth_App_Order_Update | {"field": "orderType", "operator": "EQ", "value": "lsrorders"} |
e911s | Bandwidth_App_Order_Update | {"field": "orderType", "operator": "EQ", "value": "e911s"} |
tnoptions | Bandwidth_App_Order_Update | {"field": "orderType", "operator": "EQ", "value": "tnoptions"} |
externalTns | Bandwidth_App_Order_Update | {"field": "orderType", "operator": "EQ", "value": "externalTns"} |
lidb | Bandwidth_App_Order_Update | {"field": "orderType", "operator": "EQ", "value": "lidb"} |
bulkPortins | Bandwidth_App_Order_Update | {"field": "orderType", "operator": "EQ", "value": "bulkPortins"} |
importtnorders | Bandwidth_App_Order_Update | {"field": "orderType", "operator": "EQ", "value": "importtnorders"} |
removeImportedTnOrders | Bandwidth_App_Order_Update | {"field": "orderType", "operator": "EQ", "value": "removeImportedTnOrders"} |
importVoiceTnOrders | Bandwidth_App_Order_Update | {"field": "orderType", "operator": "EQ", "value": "importVoiceTnOrders"} |
removeImportedVoiceTnOrders | Bandwidth_App_Order_Update | {"field": "orderType", "operator": "EQ", "value": "removeImportedVoiceTnOrders"} |
csrs | Bandwidth_App_Order_Update | {"field": "orderType", "operator": "EQ", "value": "csrs"} |
emergencyNotificationGroup | Bandwidth_App_Order_Update | {"field": "orderType", "operator": "EQ", "value": "emergencyNotificationGroup"} |
emergencyEndpointGroup | Bandwidth_App_Order_Update | {"field": "orderType", "operator": "EQ", "value": "emergencyEndpointGroup"} |
The v1 MESSAGING_LOST event type does not have a direct v2 equivalent at this time. If you rely on MESSAGING_LOST callbacks, keep your v1 subscription in place until a corresponding v2 definition becomes available.
Step 3 — Create equivalent v2 subscriptions
Use the v2 API or the Bandwidth App to recreate each subscription. Refer to the Subscriptions v2 API reference for the full request schema.
The Bandwidth App has a dedicated migration path built in. The subscriptions table shows badges on every row:
- Deprecated (red) — legacy subscription that has a v2 equivalent available
- Deprecated (partially migrated) (yellow) — v2 has been created for this recipient, legacy not yet deleted
- v2 (blue) — already a v2 subscription
The examples below show how to recreate common v1 subscriptions in v2.
- General Order Subscription
- Single Order Subscription
- Multiple Order Types
- Bandwidth App (UI)
v1 — Subscribe to all orders events
POST https://api.bandwidth.com/api/accounts/{accountId}/subscriptions HTTP/1.1
Content-Type: application/xml; charset=utf-8
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
<Subscription>
<OrderType>orders</OrderType>
<CallbackSubscription>
<URL>https://your-domain.com/webhooks/orders</URL>
<Expiry>3122064000</Expiry>
<CallbackCredentials>
<BasicAuthentication>
<Username>username</Username>
<Password>password</Password>
</BasicAuthentication>
</CallbackCredentials>
</CallbackSubscription>
</Subscription>
v2 — Equivalent subscription
POST https://api.bandwidth.com/v2/subscriptions HTTP/1.1
Content-Type: application/json
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
{
"accountId": "{accountId}",
"customName": "orders-webhook",
"subscriptionDefinitionName": "Bandwidth_App_Order_Update",
"deliveryType": "WEBHOOK",
"filters": [
{ "field": "orderType", "operator": "EQ", "value": "orders" }
],
"webhookSubscription": {
"url": "https://your-domain.com/webhooks/orders",
"authentication": {
"basicAuthentication": {
"username": "username",
"password": "password"
}
}
}
}
v1 — Subscribe to a specific portin order
POST https://api.bandwidth.com/api/accounts/{accountId}/subscriptions HTTP/1.1
Content-Type: application/xml; charset=utf-8
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
<Subscription>
<OrderType>portins</OrderType>
<OrderId>ee456cfb-d237-4adc-b3f8-9db03d2e62a2</OrderId>
<CallbackSubscription>
<URL>https://your-domain.com/webhooks/portins</URL>
<Expiry>3122064000</Expiry>
<CallbackCredentials>
<BasicAuthentication>
<Username>username</Username>
<Password>password</Password>
</BasicAuthentication>
</CallbackCredentials>
</CallbackSubscription>
</Subscription>
v2 — Equivalent subscription (filter by order ID)
POST https://api.bandwidth.com/v2/subscriptions HTTP/1.1
Content-Type: application/json
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
{
"accountId": "{accountId}",
"customName": "portins-order-webhook",
"subscriptionDefinitionName": "Bandwidth_App_Order_Update",
"deliveryType": "WEBHOOK",
"filters": [
{ "field": "orderType", "operator": "EQ", "value": "portins" },
{ "field": "orderId", "operator": "EQ", "value": "ee456cfb-d237-4adc-b3f8-9db03d2e62a2" }
],
"webhookSubscription": {
"url": "https://your-domain.com/webhooks/portins",
"authentication": {
"basicAuthentication": {
"username": "username",
"password": "password"
}
}
}
}
v1 — Requires one subscription per order type
<!-- Subscription 1: orders -->
<Subscription>
<OrderType>orders</OrderType>
<CallbackSubscription>
<URL>https://your-domain.com/webhooks/orders</URL>
<Expiry>3122064000</Expiry>
</CallbackSubscription>
</Subscription>
<!-- Subscription 2: disconnects -->
<Subscription>
<OrderType>disconnects</OrderType>
<CallbackSubscription>
<URL>https://your-domain.com/webhooks/orders</URL>
<Expiry>3122064000</Expiry>
</CallbackSubscription>
</Subscription>
v2 — A single subscription with no order type filter receives all order types
POST https://api.bandwidth.com/v2/subscriptions HTTP/1.1
Content-Type: application/json
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
{
"accountId": "{accountId}",
"subscriptionDefinitionName": "Bandwidth_App_Order_Update",
"deliveryType": "WEBHOOK",
"webhookSubscription": {
"url": "https://your-domain.com/webhooks/orders"
}
}
Navigate to Account → Notifications.
Your existing v1 subscriptions appear in the table with a Deprecated badge on the Event Type column.
- Locate the legacy subscription you want to migrate.
- Click the Actions menu (⋮) for that row.
- Select Create v2.
- If a v2 subscription for that recipient already exists, a warning alert appears. Click Edit current subscription to add an
Order Typefilter to the existing v2 subscription instead of creating a duplicate. - If no v2 subscription exists for that recipient, the Add subscription modal opens pre-set to Bandwidth App Order Update (v2).
- If a v2 subscription for that recipient already exists, a warning alert appears. Click Edit current subscription to add an
- In the modal:
- Choose your Delivery type (Email or Webhook).
- Enter the recipient email address or webhook URL.
- (Optional) Add Filters — for example, set Order Type → is →
portinsto limit notifications to a specific order type. - (Optional) Set a Custom name for the subscription.
- Click Add subscription.
The legacy row now shows a Deprecated (partially migrated) badge, confirming the v2 subscription was created but the legacy one is still active.
Webhook subscriptions deliver JSON payloads. Update your webhook handler to parse JSON before switching traffic. See Step 4 for payload details.
Step 4 — Update your webhook handler for the new payload format
v1 delivers XML payloads. v2 delivers JSON payloads. Update your webhook endpoint to parse JSON instead of XML.
Refer to Order Change Events and Note Events for the full field reference.
v1 example payload (XML)
<?xml version="1.0"?>
<Notification>
<SubscriptionId>c01a23e3-eb99-4174-9598-77d5beadebcf</SubscriptionId>
<OrderType>orders</OrderType>
<OrderId>9cf8daa0-89a4-46aa-a1aa-8b5cf621f218</OrderId>
<Status>COMPLETE</Status>
<Message>Created a new number order for 1 number from RALEIGH, NC</Message>
</Notification>
v2 example payload (JSON)
{
"completedPhoneNumbers": ["+19195555298"],
"lastModifiedDate": "2025-05-05T14:08:26.103Z",
"message": "Created a new number order for 1 number from RALEIGH, NC",
"orderId": "9cf8daa0-89a4-46aa-a1aa-8b5cf621f218",
"orderType": "orders",
"status": "COMPLETE"
}
Step 5 — (Optional) Add HMAC signature verification
v2 includes an X-Bandwidth-Signature-SHA-256 header you can use to verify webhook authenticity. This is strongly recommended before decommissioning v1 subscriptions.
See HMAC Signature Implementation for implementation details and example code.
Step 6 — Validate and decommission v1 subscriptions
- API
- Bandwidth App (UI)
Once your v2 subscriptions are confirmed working:
- Run both v1 and v2 subscriptions in parallel for a validation period.
- Confirm your v2 webhook handler correctly processes all expected event types.
- Delete each v1 subscription via the v1 DELETE endpoint:
DELETE https://api.bandwidth.com/api/accounts/{accountId}/subscriptions/{subscriptionId} HTTP/1.1
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
Once your v2 subscriptions are confirmed working:
- From the Actions menu on your v2 subscription row, select Test subscription.
- In the confirmation modal, click Send. A test notification is dispatched immediately.
- Click Notification history in the success alert (or select View history from the Actions menu) to confirm delivery status.
- Run both subscriptions in parallel until you are satisfied with v2 coverage.
- To remove the legacy subscription, open its Actions menu and select Delete. Confirm deletion in the modal.
If your v1 integration used the PublicKey field (mTLS client certificate verification), note that v2 does not present a client certificate. Remove any mTLS enforcement on your webhook endpoint and use HMAC verification instead.
Summary checklist
- List all existing v1 subscriptions
- Map each v1
OrderTypeto the corresponding v2 subscription definition and filter - Create v2 subscriptions via the Subscriptions v2 API or Bandwidth app UI
- Update webhook handler(s) to parse JSON payloads
- (Recommended) Implement HMAC signature verification
- Run v1 and v2 subscriptions in parallel and validate
- Delete decommissioned v1 subscriptions