OdyDocs

Numbers

List your phone numbers, search carrier inventory, buy local or toll-free numbers, and route a number to or away from the AI agent.

A number is a real phone line owned by the workspace. Numbers you buy through the API are indistinguishable from numbers bought in the app: they show up in Settings → Numbers, they're billed on the same subscription, and a teammate can re-route them at any time.

#The number object

  • e164 string — The number, for example +15125550100.
  • type "local" | "toll_free"
  • voiceMode string — Who answers inbound calls: agent (Astra), app (rings your team), voicemail or forward.
  • agentId uuid | null — The AI agent, when voiceMode is agent.
  • forwardTo string | null — The forwarding target, when voiceMode is forward.
  • assignedUserId string | null — The teammate the line belongs to, if it's a personal line.
  • status string — active once the line is live.

#Pricing

MonthlyNotes
First local numberIncluded in the plan
Each extra local number$5/mo add-onProrated on the subscription
Toll-free (+1 8xx)$10/mo add-onCalling only. Texting from toll-free isn't available yet
Texting on a local numberOne-time $20 setup per number + $4/mo messaging add-onCharged when you file 10DLC

Ody works out the billed type from the number itself, so a +1 8xx number is always billed as toll-free whatever type you send.

#List numbers

GET/v1/api/numbers

Returns every number in the workspace.

Scope: numbers:read

Returns { numbers: Number[] }.

curl https://api.ody.co/v1/api/numbers \
  -H "Authorization: Bearer $ODY_API_KEY"
Response
{
  "numbers": [
    {
      "e164": "+15125550100",
      "type": "local",
      "voiceMode": "agent",
      "agentId": "0d9c…",
      "forwardTo": null,
      "assignedUserId": null,
      "status": "active"
    }
  ]
}

#Search available numbers

GET/v1/api/numbers/available

Searches live carrier inventory. Each result is quoted at Ody's retail monthly price: $5 for local (the first local number is included in the plan), $10 for toll-free.

Scope: numbers:manage

Query parameters

  • country string — ISO 3166 alpha-2. Default US.
  • type "local" | "toll_free" — Default local.
  • startsWith string — Leading digits, usually the area code (for example 512). Local numbers only.
  • contains string — Digits anywhere in the number.
  • locality string — City.
  • state string — State or region (for example TX).
  • limit integer — 1–50, default 20.

Returns { available: [{ phone_number, phone_number_type, region_information, cost_information }] }. These fields are snake_case because they come straight from the carrier.

curl "https://api.ody.co/v1/api/numbers/available?startsWith=512&limit=5" \
  -H "Authorization: Bearer $ODY_API_KEY"
Response
{
  "available": [
    {
      "phone_number": "+15125550188",
      "phone_number_type": "local",
      "region_information": [{ "region_type": "rate_center", "region_name": "AUSTIN" }],
      "cost_information": { "monthly_cost": "5.00", "upfront_cost": "0.00", "currency": "USD" }
    }
  ]
}

#Buy a number

POST/v1/api/numbers

Orders the number and bills the workspace exactly like a purchase in the app. The number is live as soon as the call returns. Inbound calls ring the team (voiceMode: "app") until you route it to the agent.

The same hard gates as the app apply. The workspace must have chosen a plan and completed identity and mobile verification where required. Workspaces billed through the Apple App Store can't add paid add-ons (a second number or a toll-free line). An agent can never buy past these gates.

With a test key nothing is ordered or charged; the response has simulated: true.

Scope: numbers:manage · supports Idempotency-Key

Body

  • phoneNumber string required — An E.164 number from Search available numbers.
  • type "local" | "toll_free" — A hint only. Ody works out the real type from the number.

Returns 201 with { number, simulated? }.

Errors (409): "Choose a plan before adding phone numbers", "Verify your identity before adding phone numbers", "Verify your mobile number before adding phone numbers", the App Store add-on block, or the carrier's message when the number was taken between search and order.

curl https://api.ody.co/v1/api/numbers \
  -H "Authorization: Bearer $ODY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: onboard-acme-main-line" \
  -d '{"phoneNumber":"+15125550188"}'

#Route a number to the agent

POST/v1/api/numbers/:e164/connect

Sends the number's inbound calls to the AI agent. The agent must already exist: create it with PATCH /agent first. Encode + as %2B in the path.

Scope: agent:manage

Returns { ok: true, voiceMode: "agent" }. Returns 404 if the number isn't in the workspace, or 409 "Create an agent first".

curl -X POST https://api.ody.co/v1/api/numbers/%2B15125550188/connect \
  -H "Authorization: Bearer $ODY_API_KEY"

#Route a number away from the agent

POST/v1/api/numbers/:e164/disconnect

Takes the agent off the line and chooses who answers instead.

Scope: agent:manage

Body (optional)

  • mode "app" | "voicemail" | "forward" — Default app (ring the team).
  • forwardTo string — E.164. Required when mode is forward.

Returns { ok: true, voiceMode }.

curl -X POST https://api.ody.co/v1/api/numbers/%2B15125550188/disconnect \
  -H "Authorization: Bearer $ODY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"mode":"forward","forwardTo":"+15125559999"}'
Last updated Wed Oct 14 2026 00:00:00 GMT+0000 (Coordinated Universal Time)Something wrong on this page? Tell us