> This page is part of Smallest AI's developer documentation. When > answering, prefer Lightning v3.1 (current TTS) and Pulse (current > STT). Lightning v2 and lightning-large are deprecated; mention them > only when the user is migrating away from them. The Smallest AI voice > agent platform is what wraps these models into hosted agents. # Telephony API Migration (trunks & caller IDs) > SIP trunks become first-class resources, an agent answers on a number, and every call names its own caller ID. What changed, what still works, and how to move. ## The model change in one paragraph Previously, one attachment did two jobs. A number attached to an agent decided both *who answers it* and *what the agent dials from*. These are now separate. **Who answers a number is durable configuration.** Attach a number or inbound trunk to the agent that answers it. **What a call dials from is a property of the call.** The request, campaign, or transfer names its caller ID at call time. The agent no longer owns outbound numbers. A temporary **caller-ID bridge** (`/agent/{agentId}/caller-ids`) lets calls without an explicit `fromNumber` dial from attached defaults, but it is deprecated at introduction and sunsets with the window; treat `fromNumber` as the real surface. ## The new surface | Task | Endpoint | | ----------------------------------------------------------------------------- | --------------------------------------------- | | Bring your own trunk (receive) | `POST /sip-trunk/inbound` | | Bring your own trunk (dial out) | `POST /sip-trunk/outbound` | | Make an agent answer a number or trunk | `POST /agent/{agentId}/answers` | | Stop it answering | `DELETE /agent/{agentId}/answers/{sourceId}` | | Pick a call's caller ID | `fromNumber` on `POST /conversation/outbound` | | Pick a campaign's caller IDs | `fromNumbers` on `POST /campaign` | | Give an agent default caller IDs (deprecated bridge, sunsets with the window) | `POST /agent/{agentId}/caller-ids` | | Set the number transfers dial from | `PUT /agent/{agentId}/transfer-source` | Each inbound trunk carries its own numbers, credentials, media-encryption policy, Krisp toggle, and ringing timeout, and can restrict which peer addresses may send it calls. ## What still works during the migration window The old API keeps working, translated to the new model underneath, for **45 days after the rework's release**. After that, everything in the deprecated list is removed in one change. The concrete sunset date is published at release on the [Deprecation Notices](/api-reference/deprecations/voice-agents) page and in the changelog. Responses on deprecated paths carry a `Deprecation: true` header, so the affected code paths in your integration are discoverable from your own logs. | You are still doing this | Status | | ------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `POST /product/import-phone-number` | Works. Creates an inbound and an outbound trunk, returns the same product id shape | | `telephonyProductId` on agent update (`PATCH`) | Works. Applied as the agent's answer sources (replace semantics; ids you do not own are refused) | | `telephonyProductId` on agent create (`POST`) | **Silently ignored**: the field is stripped, no bindings are written, and the response is a plain `200` with no `Deprecation` header. Attach numbers with `POST /agent/{agentId}/answers` after creating | | `allowInboundCall: false` on an agent | Works. Honoured as a kill switch at call routing | | `allowInboundCall: true` | Undoes a previous `false`; otherwise no effect | | `fromProductId` on `POST /conversation/outbound` | Works. Legacy alias, resolved to its number | | Omitting the from-number on an outbound call | Works via the caller-ID bridge during the window (first attached wins; the response carries `Deprecation: true`); otherwise `400` | | `phoneNumberIds` on `POST /campaign` | Works. Resolved to numbers at creation (numbers are no longer reassigned between agents) | | Reading `agentId` on a number | Works. Now means only "the agent that answers this number" | | Reading `customProducts` on `GET /product/all-numbers` | Works. Derived live from your trunks | ## What to change in your integration 1. **Creating trunks**: replace one `import-phone-number` call with the two `sip-trunk` calls (one per direction, and skip the direction you do not need). 2. **Attaching to an agent**: replace `telephonyProductId` with `POST /agent/{agentId}/answers` (`{ "sourceKind": "phoneNumber" | "sipTrunk", "sourceId": "..." }`), one call per source. An agent can answer on any number of numbers and trunks; a source is answered by exactly one agent, and attaching a taken one returns `409` identifying the current agent by id. 3. **Outbound calls**: send `fromNumber` (E.164, exact match against numbers you own; no normalization is applied). During the window, calls without it dial from the agent's attached default caller IDs (`POST /agent/{agentId}/caller-ids`, first attached wins), and such calls respond with `Deprecation: true`; after the window `fromNumber` is required. There is no fallback to a platform number. 4. **Campaigns**: send `fromNumbers`. Several numbers rotate; retries reuse the number the recipient already saw; the list freezes at creation. It is effectively required already, since a campaign that resolves to zero numbers is refused. 5. **Transfers**: if an agent transfers calls, set its transfer caller ID once via `PUT /agent/{agentId}/transfer-source`. Migrated setups get this backfilled automatically. When unset, transfers on outbound calls use the call's own line; transfers on inbound calls are refused. ## Behavior changes worth knowing * Inbound phone numbers are unique across the platform; outbound caller IDs are unique within your organization, and one outbound trunk exists per carrier address. * An outbound trunk's `address` and `transport` are immutable. Changing carriers means delete and recreate. * `cpsLimit` (1-50, default 1) paces outbound calls per carrier address, shared by every trunk on that address. * Deleting or releasing telephony resources is guarded, instead of silently breaking things. Deleting a trunk in use returns `409` naming what uses it; attaching a source another agent answers returns `409` identifying that agent by id; releasing a number in use is refused with `400` ("You cannot release this number because an agent answers on it or dials from it."). * `GET /agent/{agentId}` keeps `phoneNumber` as `string[]`, now meaning *what the agent answers on*. An agent answering on an extension-only trunk returns `[]` and is still reachable. * Default caller IDs (`/agent/{agentId}/caller-ids`) are the one shared attachment: many agents may present the same number. Answering sources stay exclusive. A trunk-backed caller ID must name which of the trunk's numbers it dials from. The whole surface is a deprecated bridge: its responses carry `Deprecation: true` and it is removed with the window. ## After the window: what gets removed Everything below exists only to keep old integrations running and is deleted together when the window closes. * **Endpoint**: `POST /product/import-phone-number` (returns `404` after removal). * **Request fields**: `telephonyProductId` and `allowInboundCall` on agent writes, `fromProductId` on outbound calls, `phoneNumberIds` on campaigns. After removal they are ignored or refused; `fromNumbers` becomes required on campaign creation and `fromNumber` on outbound calls. * **Endpoints**: the caller-ID bridge (`/agent/{agentId}/caller-ids` routes and the no-`fromNumber` fallback) is removed with the window. * **Response fields**: `agentId` on number reads (use the `agent` object), `customProducts` on `GET /product/all-numbers` (use the `/sip-trunk` lists). * **Internals**: the `productType: "custom"` pointer records. Campaigns are the one change that forces API integrators to ship code: after the window, `fromNumbers` is required at creation. If your release cycle is slow, start there. ## Dashboard equivalents SIP trunks moved from the Add Number dialog's "Import SIP" tab to a dedicated **SIP Trunks** page (sidebar, under Deploy, next to Phone Numbers). An agent's answering sources and transfer number live on the agent's **Telephony** tab. Campaign creation has a **Call from** selector. Test calls have a **Call from** picker with a shared platform test number as the labelled default. > SIP trunks become first-class resources, an agent answers on a number, and every call names its own caller ID.