#Recipe: Switch carriers
Carriers are configuration. Nothing in the CRM integration refers to a carrier type: agents, softphones, numbers, inbound rules, calls, webhooks and events are identical for every carrier. Several carriers can be active at once; outbound calls use the carrier of the caller ID, with an optional failover carrier, so you can migrate number by number.
#TypeScript (SDK)
// Switching carriers is configuration only: connect the new carrier, move numbers, revoke the old one.
// Agents, softphones, inbound rules, webhooks and every call/number endpoint stay exactly the same.
import { createVoiceClient } from '@voice/sdk';
const voice = createVoiceClient({ baseUrl: process.env.VOICE_API_URL!, apiKey: process.env.VOICE_API_KEY! });
const oldCarrierId = process.env.CARRIER_ID!;
// 1. Connect the new carrier next to the old one (both active = parallel running).
const { data: next, error } = await voice.POST('/v1/carriers', {
body: { type: 'mock', name: 'New carrier', settings: { authMode: 'ip_auth' }, credentials: { apiKey: 'mock_docs_new_carrier' } },
});
if (error) throw new Error(error.error.message);
// 2. Optional during migration: fail over from the old carrier to the new one.
await voice.PATCH('/v1/carriers/{id}', { params: { path: { id: oldCarrierId } }, body: { failover_carrier_id: next.id } });
// 3. Numbers belong to one carrier. Port them (outside the platform) or order new ones at the new
// carrier; outbound calls use the carrier of the caller ID you choose, so you control the switch
// per number. When everything runs on the new carrier, revoke the old one:
const { data: numbers } = await voice.GET('/v1/numbers', { params: { query: { carrier_id: oldCarrierId } } });
console.log('numbers still on the old carrier:', numbers!.data.length);
console.log('new carrier', next.id, next.type, next.capabilities.auth_mode);
await voice.POST('/v1/carriers/{id}/revoke', { params: { path: { id: next.id } } });
#Notes
- Porting numbers between carriers happens outside the platform; afterwards register the number at the new carrier (
POST /v1/numbersor import withPOST /v1/numbers/sync). - Revoking removes the gateway and wipes stored credentials; call history is kept.
This example is executed against the sandbox in CI (tests/e2e/specs/m6-docs.spec.ts).