Numbers
Local and toll-free US numbers in the area codes you call. Each call picks a caller ID by the lead's area code and state, and each lead sees the same number every time.
Search and buy numbers
Search by area code, state or city, then buy with one request. New numbers are registered with the call analytics engines before their first call. Numbers are billed monthly from the day you buy them. Every call is signed for STIR/SHAKEN at no charge.
GET/v1/numbers/available
| Query | Type | Description |
|---|---|---|
type | local | toll_free | Default local. |
area_code | string | Three digits. For toll-free, a prefix such as 833. |
state | string | Two-letter state. |
city | string | City name. Matched to the rate centers that serve it. |
contains | string | Digits the number must contain, for example 7663. |
limit | integer | 1 to 100, default 20. |
curl "https://api.liveleg.dev/v1/numbers/available?area_code=512&limit=5" \
-H "Authorization: Bearer $LIVELEG_API_KEY"const res = await fetch('https://api.liveleg.dev/v1/numbers/available?area_code=512&limit=5', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.LIVELEG_API_KEY}`,
},
});
const data = await res.json();import os, requests
data = requests.get(
"https://api.liveleg.dev/v1/numbers/available",
headers={"Authorization": f"Bearer {os.environ['LIVELEG_API_KEY']}"},
params={
"area_code": "512",
"limit": 5,
},
).json() {
"object": "list",
"data": [
{
"phone_number": "+15125550199",
"type": "local",
"state": "TX",
"rate_center": "AUSTIN"
},
{
"phone_number": "+15125550142",
"type": "local",
"state": "TX",
"rate_center": "AUSTIN"
}
],
"has_more": true
} POST/v1/numbers
| Parameters | Type | Description |
|---|---|---|
type | local | toll_free | Default local. Used with area_code. |
phone_number | string | A number from the search results. Or send area_code and quantity to take the first available. |
area_code | string | Buy in this area code. |
quantity | integer | How many numbers to buy with area_code. Up to 50. |
pool_id | string | Adds the numbers to this caller ID pool. |
caller_name | string | Caller name (CNAM), up to 15 characters. Needs number reputation. |
curl https://api.liveleg.dev/v1/numbers \
-H "Authorization: Bearer $LIVELEG_API_KEY" \
-H "Idempotency-Key: buy-5125550199" \
-d phone_number=+15125550199 \
-d pool_id=pool_local_presence \
-d caller_name="RIDGELINE ROOF"const res = await fetch('https://api.liveleg.dev/v1/numbers', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.LIVELEG_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': 'buy-5125550199',
},
body: JSON.stringify({
phone_number: '+15125550199',
pool_id: 'pool_local_presence',
caller_name: 'RIDGELINE ROOF',
}),
});
const number = await res.json();import os, requests
number = requests.post(
"https://api.liveleg.dev/v1/numbers",
headers={
"Authorization": f"Bearer {os.environ['LIVELEG_API_KEY']}",
"Idempotency-Key": "buy-5125550199",
},
json={
"phone_number": "+15125550199",
"pool_id": "pool_local_presence",
"caller_name": "RIDGELINE ROOF",
},
).json() {
"id": "num_5Tq81",
"object": "number",
"phone_number": "+15125550199",
"type": "local",
"state": "TX",
"rate_center": "AUSTIN",
"pool_id": "pool_local_presence",
"caller_name": "RIDGELINE ROOF",
"stir_shaken": "A",
"daily_call_cap": 100,
"status": "active"
} | Local number | $3/ number / month |
| Toll-free number | $6/ number / month |
List your numbers with GET /v1/numbers, filtered by pool, state or status.
Toll-free numbers
Toll-free numbers use the 800, 833, 844, 855, 866, 877 and 888 prefixes. Search with type=toll_free and buy the same way as local numbers. They suit ads, websites and callbacks from leads in many states.
curl https://api.liveleg.dev/v1/numbers \
-H "Authorization: Bearer $LIVELEG_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "toll_free",
"area_code": "833",
"quantity": 1,
"caller_name": "RIDGELINE ROOF"
}'const res = await fetch('https://api.liveleg.dev/v1/numbers', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.LIVELEG_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
type: "toll_free",
area_code: "833",
quantity: 1,
caller_name: "RIDGELINE ROOF"
}),
});
const data = await res.json();import os, requests
data = requests.post(
"https://api.liveleg.dev/v1/numbers",
headers={"Authorization": f"Bearer {os.environ['LIVELEG_API_KEY']}"},
json={
"type": "toll_free",
"area_code": "833",
"quantity": 1,
"caller_name": "RIDGELINE ROOF",
},
).json() Local presence does not pick toll-free numbers. To call from one, set from on the call. Calls to a toll-free number are billed at the toll-free inbound rate.
| Inbound call to a toll-free numberRouting to the right agent, agent phone line and Smart Recording included. | $0.08/ min |
Retire and release numbers
Retiring a number stops it dialing out right away. It keeps taking callbacks for 90 days, routed to the lead's last agent, and is then released. Leads who saw it get another number in the same area code on their next call.
POST/v1/numbers/{id}/retire
curl -X POST https://api.liveleg.dev/v1/numbers/num_5Tq81/retire \
-H "Authorization: Bearer $LIVELEG_API_KEY"const res = await fetch('https://api.liveleg.dev/v1/numbers/num_5Tq81/retire', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.LIVELEG_API_KEY}`,
},
});
const data = await res.json();import os, requests
data = requests.post(
"https://api.liveleg.dev/v1/numbers/num_5Tq81/retire",
headers={"Authorization": f"Bearer {os.environ['LIVELEG_API_KEY']}"},
).json() Release a number with DELETE /v1/numbers/{id}. It stops dialing out and taking calls right away. A released number is kept out of use for at least 90 days before it goes to anyone else.
Caller ID pools
A pool is a group of numbers that a dial session picks caller IDs from. Each pool sets a daily call cap per number, 100 by default. A number that reaches its cap sits out until the next day in its own time zone. Inbound routing is also set on the pool; see Routing settings.
curl https://api.liveleg.dev/v1/caller_id_pools \
-H "Authorization: Bearer $LIVELEG_API_KEY" \
-d name="Local presence" \
-d id=pool_local_presence \
-d daily_call_cap=100 Caller ID selection
Each call picks the number the lead saw before. A new lead gets a number in their area code, then their state, then the nearest area code. Each lead keeps seeing the same number. The full order, caller name, branded caller ID and STIR/SHAKEN attestation are in Caller ID.
Porting
Bring the numbers you already have. Send the details from your current carrier's bill and the person who signs the letter of authorization (LOA). We send the LOA for e-signature, file the port and post the confirmed cutover date (FOC date) when the current carrier accepts it. Your numbers keep working at the current carrier until the cutover. Porting your existing numbers is part of setup.
POST/v1/ports
| Parameters | Type | Description |
|---|---|---|
numbersrequired | string[] | The numbers to port, E.164. All from one account at the current carrier. |
account_namerequired | string | The name on the current carrier account, exactly as on the bill. |
account_numberrequired | string | The account number at the current carrier. |
pin | string | The port-out PIN. Most mobile carriers and many VoIP providers require one. |
billing_telephone_number | string | The main number on the account, if it differs from the numbers being ported. |
service_addressrequired | object | The service address on the account: line1, city, state, postal_code. |
authorized_byrequired | string | The name of the person who signs the letter of authorization. They must be allowed to act for the account. |
authorized_emailrequired | string | Where the letter of authorization is sent for e-signature. |
authorized_title | string | Their title at the business. |
requested_date | string | The earliest cutover date you want. Default the first date the carrier offers. |
partial | boolean | True when other numbers stay on the account at the current carrier. |
pool_id | string | Adds the numbers to this caller ID pool after cutover. |
curl https://api.liveleg.dev/v1/ports \
-H "Authorization: Bearer $LIVELEG_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"numbers": [
"+16025550190",
"+16025550191"
],
"account_name": "Ridgeline Roofing LLC",
"account_number": "88213-01",
"pin": "4417",
"service_address": {
"line1": "1400 Industrial Blvd",
"city": "Phoenix",
"state": "AZ",
"postal_code": "85004"
},
"authorized_by": "Dana Ruiz",
"authorized_email": "dana@ridgeline.example",
"authorized_title": "Owner",
"pool_id": "pool_local_presence"
}'const res = await fetch('https://api.liveleg.dev/v1/ports', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.LIVELEG_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
numbers: [
"+16025550190",
"+16025550191"
],
account_name: "Ridgeline Roofing LLC",
account_number: "88213-01",
pin: "4417",
service_address: {
line1: "1400 Industrial Blvd",
city: "Phoenix",
state: "AZ",
postal_code: "85004"
},
authorized_by: "Dana Ruiz",
authorized_email: "dana@ridgeline.example",
authorized_title: "Owner",
pool_id: "pool_local_presence"
}),
});
const data = await res.json();import os, requests
data = requests.post(
"https://api.liveleg.dev/v1/ports",
headers={"Authorization": f"Bearer {os.environ['LIVELEG_API_KEY']}"},
json={
"numbers": ["+16025550190", "+16025550191"],
"account_name": "Ridgeline Roofing LLC",
"account_number": "88213-01",
"pin": "4417",
"service_address": {
"line1": "1400 Industrial Blvd",
"city": "Phoenix",
"state": "AZ",
"postal_code": "85004",
},
"authorized_by": "Dana Ruiz",
"authorized_email": "dana@ridgeline.example",
"authorized_title": "Owner",
"pool_id": "pool_local_presence",
},
).json() {
"id": "prt_6Gw20Lc",
"object": "port",
"status": "awaiting_signature",
"numbers": [
"+16025550190",
"+16025550191"
],
"loa_url": "https://sign.liveleg.dev/loa/prt_6Gw20Lc",
"foc_date": null,
"rejection": null,
"created_at": "2026-11-03T16:20:00Z"
} Each status change sends number.port_updated. Local numbers take 1 to 2 weeks from signature to cutover. Toll-free numbers take 2 to 4 weeks. A rejection adds the time it takes to fix the details.
| status | What happens | Typical time |
|---|---|---|
awaiting_signature | We email the letter of authorization to authorized_email for e-signature. | Until signed |
submitted | The signed port is filed with the current carrier. | Same business day |
foc_confirmed | The current carrier accepted the port. foc_date is the cutover date. | 1 to 5 business days after filing |
completed | The numbers are live on Liveleg and in the pool. Calls get A attestation. | On foc_date |
rejected | The carrier rejected the details. rejection.reason says which field. Fix it with PATCH /v1/ports/{id} and the port is filed again. | |
canceled | You canceled the port before cutover. |
{
"id": "evt_2Pr55Dn6",
"type": "number.port_updated",
"created_at": "2026-11-05T17:02:41.115Z",
"livemode": true,
"data": {
"port_id": "prt_6Gw20Lc",
"status": "foc_confirmed",
"numbers": [
"+16025550190",
"+16025550191"
],
"foc_date": "2026-11-12"
}
} You can port numbers out to another provider at any time. We do not hold numbers back over a dispute. Your account engineer gives you the account number and PIN the new carrier asks for.
Numbers per subaccount
Each subaccount has its own numbers and caller ID pools. Calls in a subaccount use only its numbers, and caller name is the client's business name. Buy numbers for a subaccount with the parent key and the Liveleg-Account header, or with the subaccount's own key.
curl https://api.liveleg.dev/v1/numbers \
-H "Authorization: Bearer $LIVELEG_API_KEY" \
-H "Liveleg-Account: acc_hollis_dental" \
-d area_code=720 \
-d quantity=3 \
-d pool_id=pool_local_presence \
-d caller_name="HOLLIS DENTAL" When a client leaves your platform, it can port its numbers out or move them to its own Liveleg account. See Subaccounts.
Number lookup
Every number is looked up for line type and line status before each dial, and disconnected numbers are skipped. To check numbers yourself, one at a time or 1,000 per batch, see Number Lookup.