Phone numbers

Buy a dedicated number, connect the one you already have, and decide which agent answers it.
View as Markdown

A phone number is the voice line your agents answer and call from. Each number belongs to exactly one workspace and is bound to one agent: calls to the number reach that agent, and calls the agent places show that number as caller ID. You can get a number three ways: buy one through Jelliu, connect a number you already own over your SIP trunk, or keep your existing line and forward its calls to a Jelliu number.

The Phone Numbers API lets you browse available inventory, provision numbers, connect your own, change which agent answers, configure a phone menu, and get the dialing codes to forward a line.

How it works

Getting a number

PathEndpointWhat happens
Buy the plan-included numberPOST /api/phone-numbers/provisionJelliu buys a voice-capable number in the US or Canada, registers it for voice and binds your agent, in one request.
Buy additional numbersDashboard, Settings → PlanA paid add-on. After payment the numbers are bought in the country you chose and appear in GET /api/phone-numbers without an agent; assign one with PATCH.
Connect a number you ownPOST /api/phone-numbers/connect-sipNothing is bought. Your number is connected over your SIP trunk, bound to the agent, and then answers and dials exactly like a purchased number.
Forward an existing lineGET /api/phone-numbers/{id}/forwarding-instructionsNothing changes on Jelliu’s side. Your carrier forwards the line to a Jelliu number, where its agent answers.

Inbound calls. The number you call is the routing key: it identifies the workspace and the agent. Before an agent answers, Jelliu checks that the workspace is not suspended, that a trialing workspace still has trial minutes, and that a concurrent-call slot is free. If the workspace is suspended or out of trial minutes, the caller hears a short message and the call ends; if every slot is busy, the caller is told that all agents are busy.

  • If the number has an agent, that agent answers. If that agent is paused, the call is not handed to a different agent.
  • If the phone menu is enabled, the caller hears the greeting and the options, and has 10 seconds to press one digit. The option’s agent answers; if it is unavailable, Jelliu tries the option’s department, then another agent in the workspace.

Outbound calls. When an agent places a call, the caller ID is the workspace’s active number bound to that agent, or otherwise its most recently updated active number. See Calls.

A workspace on an active paid plan with no active, registered number cannot place calls: they fail with 403 PHONE_NUMBER_REQUIRED. Provision or connect a number before starting a voice campaign.

The phone number object

Returned by every endpoint on this page except GET /available and GET /{id}/forwarding-instructions.

FieldTypeNullableDescription
idstring (uuid)NoIdentifier of the number in Jelliu.
phoneNumberstringNoThe number in E.164 format, for example +13055550142. A number can exist in only one Jelliu workspace.
labelstringYesDisplay name. Defaults to Jelliu +13055550142 for provisioned numbers and +573001234567 (own number) for connected ones.
isActivebooleanNoInactive numbers are never used as caller ID and do not count toward your plan’s number limit.
agentIdstring (uuid)YesThe agent that answers the number. null when none is assigned.
agentNamestringYesName of that agent.
agentProvisionedbooleanYesfalse when the assigned agent is still being set up, so calls will not reach it yet. null when no agent is assigned.
ivrEnabledbooleanNoWhether callers hear the phone menu before an agent answers.
ivrGreetingstringYesGreeting read before the menu options.
ivrOptionsobject[]NoMenu options, each { digit, label, agentId, department }. Empty array when there is no menu.
channelsstring[]NoWhat the number answers on: ["voice"], ["whatsapp"], or both. A WhatsApp line you connected also appears in this list.
whatsappStatusstringYesStatus of the WhatsApp sender on this number (CREATING, VERIFYING, ONLINE, OFFLINE, FAILED), or null when it is not a WhatsApp line.
providerstringNotwilio for a number bought through Jelliu, sip_trunk for your own number connected over SIP.
sipHoststringYesFor sip_trunk numbers, the outbound trunk address you supplied. null otherwise.
createdAtstring (date-time)NoWhen the number was added.
updatedAtstring (date-time)NoLast change.
{
"data": {
"id": "3f6a2c1e-8b4d-4e7a-9c2f-5d1b0a9e8c77",
"phoneNumber": "+13055550142",
"label": "Miami front desk",
"isActive": true,
"agentId": "7c1d9f30-5e2a-4a7e-9c8f-91a0b1c2d3e4",
"agentName": "Recepción",
"agentProvisioned": true,
"ivrEnabled": false,
"ivrGreeting": null,
"ivrOptions": [],
"channels": ["voice"],
"whatsappStatus": null,
"provider": "twilio",
"sipHost": null,
"createdAt": "2026-09-01T14:03:22.114Z",
"updatedAt": "2026-09-10T09:41:05.870Z"
}
}

Endpoints

MethodPathRequired
GET/api/phone-numbersread key
GET/api/phone-numbers/{id}read key
GET/api/phone-numbers/availableread key
GET/api/phone-numbers/{id}/forwarding-instructionsread key
PATCH/api/phone-numbers/{id}write key
POST/api/phone-numbers/provisionfull key
POST/api/phone-numbers/connect-sipfull key

GET /api/phone-numbers returns every number in the workspace, oldest first, in { "data": [ ... ] }. It takes no paging parameters.

The API has no endpoint to release or delete a number.

Common tasks

Buy a number

1

Browse available numbers

Search the inventory for a country. Nothing is bought.

curl -sS "https://api.jelliu.co/api/phone-numbers/available?country=US&type=local&areaCode=305&limit=5" \
-H "Authorization: Bearer $JELLIU_API_KEY"
{
"data": [
{
"phoneNumber": "+13055550142",
"friendlyName": "(305) 555-0142",
"locality": "Miami",
"region": "FL",
"isoCountry": "US",
"type": "local",
"capabilities": { "voice": true, "sms": true },
"addressRequired": false
}
]
}
country
stringRequired

ISO 3166-1 alpha-2 code, case-insensitive. Must be a country where Jelliu can provision numbers (see Countries).

type
string

local, mobile or tollfree. When omitted, all three types are searched and combined.

areaCode
string

Three-digit area code. Applied only in the US and Canada; ignored elsewhere.

contains
string

Pattern the number must contain: 1 to 15 digits, letters or *.

limit
integerDefaults to 10

1 to 30. Applies per type, so a search without type can return up to three times this many numbers.

Only voice-capable numbers are returned. A country with no stock of the requested type returns an empty list. addressRequired: true means the number is subject to a local regulatory address requirement.

2

Provision it for an agent

Buy the number and bind the agent that answers it. The agent must belong to your workspace and have finished provisioning.

curl -sS -X POST "https://api.jelliu.co/api/phone-numbers/provision" \
-H "Authorization: Bearer $JELLIU_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agentId": "7c1d9f30-5e2a-4a7e-9c8f-91a0b1c2d3e4",
"country": "US",
"phoneNumber": "+13055550142",
"label": "Miami front desk"
}'

The response is 201 Created with the phone number object in data.

agentId
string (uuid)Required

The agent that answers the number.

country
stringDefaults to US

US or CA. Any other serviceable country returns 402 BILLING_ERROR: numbers elsewhere are paid add-ons bought under Settings → Plan.

phoneNumber
string

Exact E.164 number to buy, taken from GET /available. Without it, Jelliu picks the first available number, trying local and then mobile.

areaCode
string

Three-digit area code to prefer when Jelliu picks the number.

type
string

local, mobile or tollfree when Jelliu picks the number.

label
string

1 to 120 characters.

Provisioning is safe to retry. If the agent already has an active number, the request buys nothing and returns that number with 201, even if you pass a different country or phoneNumber. A second request for the same agent while the first is still running returns 409 CALL_ALREADY_IN_PROGRESS.

If registering the number or binding the agent fails after the number was bought, Jelliu releases the number and the request fails, so a failed request does not leave a half-configured number in your workspace.

Assign or change the agent

Send only the fields you want to change. null clears a nullable field; an omitted field is left untouched.

curl -sS -X PATCH "https://api.jelliu.co/api/phone-numbers/3f6a2c1e-8b4d-4e7a-9c2f-5d1b0a9e8c77" \
-H "Authorization: Bearer $JELLIU_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "agentId": "b2e4d6f8-1a3c-4e5f-8a9b-0c1d2e3f4a5b", "label": "Soporte Bogotá" }'

The response is 200 with the updated number in data. Changes apply to the next call.

agentId
string (uuid) | null

The agent that answers. It must serve every channel in the number’s channels: a WhatsApp line needs an agent that answers WhatsApp. null unassigns the agent.

label
string | null

Up to 120 characters.

isActive
boolean

Deactivate or reactivate the number.

ivrEnabled
boolean

Turn the phone menu on or off. See Configure a phone menu.

ivrGreeting
string | null

Up to 1000 characters.

ivrOptions
object[]

Up to 20 options with unique digits. [] clears the menu.

If a number is currently answered by an agent that was configured outside Jelliu, assigning a different agent returns 409 VALIDATION_FAILED so the line is not taken over by accident. Send { "agentId": null } first, then assign the new agent.

Numbers bought as plan add-ons arrive with agentId: null. Assigning an agent is what registers them for voice, so do it before you rely on the number.

Configure a phone menu

A phone menu lets callers choose where their call goes. Each option routes to a specific agent or to a department; when a department is given, the oldest available agent in that department answers.

curl -sS -X PATCH "https://api.jelliu.co/api/phone-numbers/3f6a2c1e-8b4d-4e7a-9c2f-5d1b0a9e8c77" \
-H "Authorization: Bearer $JELLIU_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ivrEnabled": true,
"ivrGreeting": "Gracias por llamar a Clínica Aurora.",
"ivrOptions": [
{ "digit": "1", "label": "citas", "agentId": "7c1d9f30-5e2a-4a7e-9c8f-91a0b1c2d3e4" },
{ "digit": "2", "label": "facturación", "department": "billing" }
]
}'

Each option in ivrOptions:

FieldTypeRequiredDescription
digitstringYesOne of 0-9, * or #. Unique within the menu.
labelstringYes1 to 120 characters, read to the caller.
agentIdstring (uuid) or nullNoAgent that answers this option. Must belong to your workspace.
departmentstring or nullNo1 to 80 characters. Routes to an agent in this department.

The phone menu exists only on numbers bought through Jelliu (provider: "twilio"). Enabling it on a number connected over your SIP trunk, or on a WhatsApp-only line, returns 400 VALIDATION_FAILED. A menu also needs at least one option: ivrEnabled: true with no options is refused.

Connect a number you already own

Bring your number over your SIP trunk. Give inbound so the agent answers calls on the number, outbound so it can call from it, or both.

curl -sS -X POST "https://api.jelliu.co/api/phone-numbers/connect-sip" \
-H "Authorization: Bearer $JELLIU_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agentId": "7c1d9f30-5e2a-4a7e-9c8f-91a0b1c2d3e4",
"phoneNumber": "+576015550199",
"label": "Línea principal",
"inbound": {
"allowedAddresses": ["203.0.113.10/32"],
"mediaEncryption": "allowed"
},
"outbound": {
"address": "sip.carrier.example.com:5061",
"transport": "tls",
"credentials": { "username": "jelliu-trunk", "password": "s3cr3t-trunk-pass" },
"enabledCodecs": ["PCMU/8000", "PCMA/8000"]
}
}'

The response is 201 Created with the number in data, provider: "sip_trunk" and sipHost set to the outbound address.

Top-level fields

FieldTypeRequiredDescription
agentIdstring (uuid)YesA provisioned agent in your workspace that answers voice calls.
phoneNumberstringYesYour number in E.164 format.
labelstringNo1 to 120 characters.
inboundobjectOne of the twoWhat your PBX or carrier sends to Jelliu.
outboundobjectOne of the twoWhere Jelliu sends calls placed from this number.

inbound: must include allowedAddresses or credentials, so the trunk does not accept calls from anyone.

FieldTypeDescription
allowedAddressesstring[]Up to 50 IP addresses or CIDR blocks allowed to send calls.
allowedNumbersstring[]Up to 200 E.164 numbers.
credentialsobject{ username, password } for digest authentication. Username 1 to 120 characters, password 1 to 256.
mediaEncryptionstringdisabled, allowed or required.
remoteDomainsstring[]Up to 20 domains, each 1 to 253 characters.

outbound

FieldTypeDescription
addressstringRequired. Hostname or IP address, optionally with :port. Not a URL: https:// is rejected.
transportstringauto, udp, tcp or tls.
mediaEncryptionstringdisabled, allowed or required.
credentialsobject{ username, password }, same bounds as inbound.
headersobjectCustom SIP headers: names up to 64 characters, values up to 512.
enabledCodecsstring[]Up to 3 of G722/8000, PCMU/8000, PCMA/8000.

Trunk credentials are passed to the voice platform and are not stored by Jelliu. The only trunk detail kept is sipHost, so you can see where the number lives.

If the number is already your workspace’s WhatsApp line, connecting it over SIP adds voice to that same number instead of failing as a duplicate. Because one number is answered by one agent, the agent must serve both voice and WhatsApp; otherwise the request returns 400 VALIDATION_FAILED.

Unknown fields in the body are ignored rather than rejected. Double-check field names such as allowedAddresses and enabledCodecs: a misspelled one is dropped silently.

Forward an existing line

If your business line cannot connect over SIP, forward it to a Jelliu number. Fetch the dialing codes for that number; they are standard mobile call-forwarding codes, dialed from the phone the line is on.

curl -sS "https://api.jelliu.co/api/phone-numbers/3f6a2c1e-8b4d-4e7a-9c2f-5d1b0a9e8c77/forwarding-instructions" \
-H "Authorization: Bearer $JELLIU_API_KEY" \
-H "Accept-Language: en"
{
"data": {
"forwardTo": "+13055550142",
"agentName": "Recepción",
"codes": {
"activateAll": "**21*+13055550142#",
"activateWhenBusy": "**67*+13055550142#",
"activateWhenUnanswered": "**61*+13055550142#",
"activateWhenUnreachable": "**62*+13055550142#",
"deactivateAll": "##002#",
"check": "*#21#"
},
"notes": [
"Dial the code from the phone the line is on, then press call. The carrier confirms on screen.",
"Every call to your number then lands on +13055550142, where Recepción answers. Your customers keep dialling the number they always have.",
"Forwarding is a service of YOUR carrier: some block forwarding to a number abroad, and the forwarded leg is billed by them at their rate. Check with the carrier if the code is refused.",
"This covers INCOMING calls. Calls the agent places still show the Jelliu number as caller ID; showing your own number on outbound needs a SIP trunk (Connect own number) or porting.",
"Fixed lines and PBXs use their own forwarding menus — the codes above are for mobile lines."
]
}
}

notes is written for the person dialing the code: in Spanish when Accept-Language starts with es, in English otherwise. The codes are the same in both.

The number must be a voice number, have an agent assigned and be active; otherwise the request returns 400 VALIDATION_FAILED.

Countries

Numbers can be searched and bought in these countries:

RegionCountries
North AmericaUS, CA, PR, MX, PA
South AmericaAR, BR, CL, CO
EuropeDE, FR, GB
OceaniaAU

Any other country code returns 400 VALIDATION_FAILED with the list of available countries in the message.

  • Plan-included number (POST /provision): US and CA only.
  • Add-on numbers (dashboard, Settings → Plan): any country above, priced by country.
  • Connected numbers (POST /connect-sip): not limited by this list; any E.164 number your trunk carries.

Some countries sell mostly mobile numbers, which is why provisioning without type falls back from local to mobile.

Errors

Every error uses the standard error envelope. Validation failures on these endpoints return details as a field map (formErrors, fieldErrors).

CodeStatusWhen
VALIDATION_FAILED400The body or query failed validation: bad UUID, non-E.164 number, an unsupported country, connect-sip without inbound or outbound, an inbound block without allowedAddresses or credentials, or a PATCH with no fields.
VALIDATION_FAILED400The request conflicts with the number or agent: the agent does not serve the number’s channels (or does not answer voice, on connect-sip), a phone menu enabled without options or on a SIP or WhatsApp-only number, or forwarding instructions for a number that is inactive, has no agent or is WhatsApp-only.
VALIDATION_FAILED409connect-sip: the number already exists as a voice number in your workspace, or in another Jelliu workspace. PATCH: the number is answered by an agent configured outside Jelliu; clear agentId first.
BILLING_ERROR402provision: a country other than US or CA, or the workspace already holds all the numbers it is entitled to. connect-sip: the plan’s number limit is reached. On the limit errors, metadata.tier names the current plan.
AGENT_NOT_FOUND404The agent, or an agent in ivrOptions, does not exist in your workspace.
AGENT_PROVISIONING409The agent is still being set up. Retry after Retry-After (5 seconds).
CALL_ALREADY_IN_PROGRESS409A number is already being provisioned for this agent, or this number is already being connected. Retry shortly.
NOT_FOUND404No number with this id in your workspace.
FORBIDDEN403The key’s scope does not cover the request; provision and connect-sip need full.
TELEPHONY_ERROR502Searching or buying numbers failed upstream: no stock for the request, the requested phoneNumber was taken, or the country requires regulatory documents before purchase.
VOICE_AI_ERROR502Registering the number for voice, or binding the agent, failed upstream. On connect-sip this includes a trunk configuration the voice platform rejects.
INTERNAL_ERROR503Provisioning is temporarily unavailable. Nothing was bought; retry in a moment.

5xx responses carry the generic message Internal server error, including TELEPHONY_ERROR for a number that needs regulatory documents. If a purchase in a specific country keeps failing with 502, try another type or number, or contact support.

Limits

Rate limits. All /api/phone-numbers routes use the general API limit for your plan.

Scopes. Reads need a read key, PATCH needs write, and provision and connect-sip need full because they spend money or register numbers. See Authentication.

Numbers per plan. The limit counts active voice numbers: purchased and connected numbers alike. Inactive numbers and WhatsApp-only lines do not count.

PlanNumbers
No active plan0
Starter1
Growth3
Business10
Enterprise9,999

On Starter, Growth and Business, the plan includes one number. Each additional purchased number is a paid add-on, so POST /provision can only buy a number while the workspace holds fewer than 1 plus its paid add-ons. On Enterprise the plan limit applies directly. Connecting your own number over SIP needs no add-on: it is limited only by the plan’s number limit.

Webhooks

There are no phone-number events. Calls answered on or placed from your numbers are reported with the call events, call.completed and call.failed. See Webhooks and Calls.