phone numbers
Provision managed numbers, import SIP trunk numbers, and manage phone-number business verification.
speko.phoneNumbers manages caller IDs and inbound numbers for the authenticated organization.
const numbers = await speko.phoneNumbers.list();
const imported = await speko.phoneNumbers.importSipTrunk({
e164: '+12015550199',
sipConnectionInstallationId: '00000000-0000-4000-8000-000000000010',
direction: 'both',
agentId: 'agent_123',
});Managed number purchase is the US-number path and requires phone-number business verification plus sufficient credits. For numbers you already own, or non-US carrier paths, import a SIP trunk number and link it to an agent.
Inbound routing is controlled by direction, agentId, and dispatchMetadataTemplate. A number that allows inbound calls must have either a linked agent or a dispatch metadata template. Linked agents hydrate the call prompt, routing intent, provider preferences, and tools; organization webhook endpoints resolve separately by the linked agent. Templates add static or token-substituted metadata.
Methods
| Method | Description |
|---|---|
list() | List all organization phone numbers. |
searchAvailable(params?) | Search platform-managed numbers available to buy. |
get(id) | Fetch one phone-number row. |
create(params) | Buy a managed number. Requires business verification and sufficient credits. |
importSipTrunk(params) | Register a customer-owned SIP-trunk number. |
update(id, params) | Update direction, metadata template, label, or linked agent. |
delete(id) | Release or unregister a phone number. |
getKyb() | Read business verification state. |
saveKybDraft(params) | Save a business verification draft. |
submitKyb(params) | Submit business verification for review. |
PhoneNumberRow
| Field | Type | Description |
|---|---|---|
id | string | Speko phone-number id. |
e164 | string | E.164 phone number. |
source | 'managed' | 'sip_trunk' | Platform-managed number or customer SIP-trunk number. |
providerResourceId | string | null | Platform-neutral managed provider id. |
sipConnectionInstallationId | string | null | Installed SIP connection used for productized SIP imports. |
sipProviderName | string | null | Display label for the SIP provider/account. |
direction | 'inbound' | 'outbound' | 'both' | Allowed call direction. |
agentId | string | null | Agent linked for inbound calls. |
dispatchMetadataTemplate | Record<string, unknown> | null | Optional template merged into inbound session metadata. Supports tokens such as {{callerNumber}}, {{dialedNumber}}, and {{forwardedFromNumber}}. |
setupStatus | PhoneNumberSetupStatus | Readiness state for inbound/outbound use. forwardingSipUri is the SIP URI your carrier must forward inbound calls to when forwardingRequired is true. |
sms10dlcProfileId, smsCampaignId, smsAssignmentStatus | nullable | SMS assignment state when applicable. |
Pass null to update() for label, dispatchMetadataTemplate, or agentId to clear them.
Connect Twilio
To bring Twilio numbers without building a SIP trunk by hand, connect the Twilio account in the dashboard. In Phone numbers → Import number → Add carrier connection, choose Twilio and keep API key selected. Enter the Account SID and an API key SID and secret, or leave the key SID blank and use the Auth Token.
Speko then creates, inside your Twilio account:
- an Elastic SIP trunk (
speko-….pstn.twilio.com) with call transfers enabled, - a credential list that Speko's outbound calls authenticate with,
- an origination URI that sends the trunk's inbound calls to Speko.
The import dialog then lists the numbers in that account. Importing a number that takes inbound calls attaches it to the Speko trunk, so there is no forwarding step. Attaching replaces the number's current voice configuration in Twilio. A number already on a different SIP trunk is refused instead of moved. Releasing the number in Speko detaches it from the trunk, and disconnecting the connection deletes the trunk and credential list.
Inbound forwarding
A carrier-imported number (source: 'sip_trunk') reaches its agent only after your carrier forwards inbound calls to Speko. Speko provisions the inbound SIP trunk and dispatch rule for the number at import time; the one step left is on the carrier side. When setupStatus.forwardingRequired is true, setupStatus.forwardingSipUri is the authoritative target — read it from the API or copy it from the number's page or the import dialog in the dashboard. It has the form:
sip:<E.164>@<speko-sip-host>On the hosted Speko platform (api.speko.dev) the host is 3ik7edxlm4p.sip.livekit.cloud; a self-hosted deployment has its own. Use the full international number with the leading +; no custom headers are needed because the dialed number selects the agent. UDP or TCP on port 5060 and TLS on 5061 all work.
For example, in Twilio Programmable Voice on the hosted platform:
<Response>
<Dial>
<Sip>sip:+33162044473@3ik7edxlm4p.sip.livekit.cloud</Sip>
</Dial>
</Response>or set the same host as the origination URI of a Twilio Elastic SIP trunk (see the authentication note below).
Authentication depends on the carrier connection the number was imported with:
- Telnyx connections accept calls from Telnyx's SIP signaling addresses; no credentials are needed.
- Connect Twilio connections accept calls from Twilio's SIP signaling addresses; Speko attaches the number to its trunk, so there is nothing to forward.
- Twilio and other connections you entered by hand require SIP digest credentials only when you stored a carrier username and password on the connection. Twilio sends them as
<Sip username="..." password="...">. An Elastic SIP trunk's origination cannot present credentials, so for trunk-based inbound either store no credentials or use Connect Twilio. Without stored credentials, calls are matched by the dialed number alone.
Do not derive the host from a LiveKit WebSocket URL you may see elsewhere. Any *.sip.livekit.cloud name resolves, but a guessed one is answered with 404 Not Found before any session is created, so nothing appears in your workspace.
Forwarded-from number
When a carrier forwards a call, Speko attempts to normalize the original forwarding source from provider fields and SIP headers. The value is available as forwardedFromNumber in call metadata and as forwarded_from_number in pre-call webhooks.
Business verification
Managed phone-number purchases are gated by phone-number KYB.
const kyb = await speko.phoneNumbers.getKyb();
await speko.phoneNumbers.submitKyb({
businessProfile: {
legalName: 'Acme Inc.',
displayName: 'Acme',
entityType: 'Corporation',
country: 'US',
website: 'https://example.com',
address: {
street: '1 Market St',
city: 'San Francisco',
state: 'CA',
postalCode: '94105',
country: 'US',
},
useCase: 'Customer support calls and appointment reminders.',
expectedUsage: '500 calls per month in the US.',
},
authorizedRepresentative: {
name: 'Ava Martinez',
title: 'Operations Lead',
email: 'ava@example.com',
phone: '+12015551234',
},
attestationAccepted: true,
});