Skip to main content

API reference

Phone numbers

Owned and rented numbers.

Beta. Every endpoint on this page is live and documented as shipped. Shapes can still change before general availability.

Overview

The Phone Numbers API lists the numbers your organization owns, searches carrier inventory, rents new numbers and releases numbers you no longer need.

Base URL: https://api.hirefinn.ai/api/v1. Auth: Authorization: Bearer finn_live_.... See authentication.

Assigning a number to a Finn is done by deploying. There is no assign or unassign endpoint. To answer calls on a number, create an inbound deployment for the Finn and the number; to dial from a number, use it in an outbound deployment. The number is freed when you stop the deployment or when it ends as completed or error, and can then be deployed again. See api-deployments.

Renting and releasing have real effects:

  • Renting debits your wallet when the request is accepted, then provisions the number asynchronously.
  • Releasing gives no refund. The number goes back to the carrier and is deleted from your organization.

Endpoints

MethodPathRate limit (per API key)
GET/phone_numbers300 per minute, shared with GET /phone_numbers/{id}
GET/phone_numbers/{id}Same bucket
GET/phone_numbers/available30 per minute. Each search is a live carrier query.
POST/phone_numbers10 per minute, shared with DELETE /phone_numbers/{id}
DELETE/phone_numbers/{id}Same bucket

The phone number object

{
  "id": "6b1f0c2e-3d4a-4f5b-9c8d-2e7a1b9f4c03",
  "phone_number": "+918035731234",
  "status": "Live",
  "provider": "plivo",
  "country": "IN",
  "capabilities": { "voice": true, "sms": false, "mms": false },
  "allocation": {
    "finn_id": "8f14e45f-ceea-467a-9f6a-1c0e5b2a77d1",
    "call_type": "inbound"
  },
  "created_at": "2026-09-02T11:20:41.000Z",
  "updated_at": "2026-09-02T11:21:05.000Z"
}
FieldTypeNotes
idstringUUID. Use it as phone_number_id in api-deployments.
phone_numberstringThe number as stored, normally E.164.
statusstringAs reported by the carrier. Rented numbers are Live once provisioned. Compare case-insensitively; a number whose status is pending or cancelled cannot be deployed.
providerstring or nullCarrier: plivo, twilio or exotel.
countrystring or nullISO 3166-1 alpha-2 code.
capabilitiesobjectvoice, sms and mms, each true, false or null when unknown.
allocationobject or nullThe Finn the number is currently assigned to through a running deployment, with finn_id and call_type (inbound or outbound). null when unassigned. It can still name a Finn whose deployment has already ended; that number can be deployed again.
created_atstringISO 8601.
updated_atstringISO 8601.

List numbers

GET /phone_numbers

Returns numbers owned by your organization, newest first.

Query parameterTypeDefaultNotes
limitinteger501 to 200. Out-of-range values are clamped.
offsetinteger0Number of items to skip.
curl "https://api.hirefinn.ai/api/v1/phone_numbers?limit=50" \
  -H "Authorization: Bearer $FINN_API_KEY"
{
  "success": true,
  "data": [
    {
      "id": "6b1f0c2e-3d4a-4f5b-9c8d-2e7a1b9f4c03",
      "phone_number": "+918035731234",
      "status": "Live",
      "provider": "plivo",
      "country": "IN",
      "capabilities": { "voice": true, "sms": false, "mms": false },
      "allocation": null,
      "created_at": "2026-09-02T11:20:41.000Z",
      "updated_at": "2026-09-02T11:21:05.000Z"
    }
  ],
  "limit": 50,
  "offset": 0
}

There is no total count. Page with offset until a page returns fewer than limit items.

Retrieve a number

GET /phone_numbers/{id}

curl https://api.hirefinn.ai/api/v1/phone_numbers/6b1f0c2e-3d4a-4f5b-9c8d-2e7a1b9f4c03 \
  -H "Authorization: Bearer $FINN_API_KEY"

Returns { "success": true, "data": { ... } } with one phone number object.

Search available numbers

GET /phone_numbers/available

Query parameterTypeRequiredNotes
countrystringyes2-letter ISO country code, for example IN or US.
searchstringnoUp to 20 characters, passed to the carrier to filter numbers, for example by digits.
providerstringnoplivo, twilio or exotel. Only exotel changes the search: it searches Exotel inventory. plivo and twilio are accepted but don't pick the carrier: India (IN) is searched on Plivo and every other country on Twilio. When omitted, or set to plivo or twilio, the search follows that country rule, except that omitting provider searches Exotel when your organization's default carrier is Exotel.
curl "https://api.hirefinn.ai/api/v1/phone_numbers/available?country=US&search=415" \
  -H "Authorization: Bearer $FINN_API_KEY"
{
  "success": true,
  "data": [
    {
      "phone_number": "+14155550123",
      "country": "US",
      "region": "CA",
      "locality": "San Francisco",
      "number_type": "local",
      "capabilities": { "voice": true, "sms": true, "mms": false },
      "price": null,
      "currency": null
    }
  ]
}
FieldTypeNotes
phone_numberstringPass this unchanged to POST /phone_numbers.
countrystring or nullISO country code.
regionstring or nullRegion or state.
localitystring or nullCity.
number_typestring or nullCarrier number type, for example local.
capabilitiesobjectvoice, sms, mms: true, false or null.
pricenumber or nullRental price in currency. Set only for Exotel numbers, which are priced per number in INR. For other carriers it is null; the amount charged is returned by POST /phone_numbers.
currencystring or nullINR when price is set.

The list is not paginated. When the carrier has nothing matching, data is an empty array.

Some searches require your organization's compliance application to be approved, otherwise the search returns 409 compliance_required: searching India (IN) inventory, searching with provider=exotel, and searching without provider when your organization's default carrier is Exotel. Organizations with an approved application, or that already have a carrier subaccount, can search. Compliance is completed in the dashboard under Settings → Compliance, not through the API; the error's action_url (...settings?tab=telephony-account) opens that tab.

Rent a number

POST /phone_numbers

FieldTypeRequiredNotes
phone_numberstringyesA number from GET /phone_numbers/available. 6 to 15 digits with an optional +; spaces, dashes and parentheses are stripped.
providerstringnoplivo, twilio or exotel. Pass exotel to rent an Exotel number. For other numbers the carrier is your organization's configured carrier, or Plivo for +91 and Twilio otherwise.
capabilitiesobjectno{ "voice": true, "sms": false, "mms": false }. Each value is a boolean; anything else is treated as unspecified.
curl -X POST https://api.hirefinn.ai/api/v1/phone_numbers \
  -H "Authorization: Bearer $FINN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "+14155550123",
    "capabilities": { "voice": true }
  }'

Response 202 Accepted:

{
  "success": true,
  "data": {
    "status": "provisioning",
    "phone_number": "+14155550123",
    "transaction_id": "txn_1759740062114_4f9c2a1e",
    "price": 2.5,
    "currency": "USD",
    "credits_debited": 25,
    "remaining_credits": 4175
  }
}
FieldNotes
statusAlways provisioning.
transaction_idReference for this purchase. Quote it to support.
price, currencyThe rental price charged.
credits_debitedCredits taken from the wallet. The ledger entry has type debit_phone_number; see api-wallet.
remaining_creditsWallet balance after the debit.

What happens:

  1. The wallet is debited immediately.
  2. The carrier purchase runs in the background. The response does not include the number's id.
  3. Poll GET /phone_numbers until the number appears, then use its id.
  4. If the carrier purchase fails, the debit is refunded (ledger type credit_refund_phone_number) and the number never appears in the list.

Requirements:

  • Your organization's compliance application must be approved, otherwise 403 compliance_required. Submit it in the dashboard under Settings → Compliance; the error's action_url opens that tab. See api-errors.
  • The rental is attributed to the user who created the API key. That user must still be a member of your organization, with an email on record, otherwise 409 api_key_owner_required; create a new key from the dashboard.
  • Organizations in proof-of-concept mode use numbers provided by Finn and cannot rent (403 rental_unavailable).

There is no idempotency key. Retrying a rental for the same number doesn't charge you twice: the wallet is debited only once per number for your organization. A retry does record another purchase and start the number's setup again, so check GET /phone_numbers before you retry.

Release a number

DELETE /phone_numbers/{id}

Query parameterTypeNotes
forcestringtrue removes the number's assignment records (current and past) before releasing.
curl -X DELETE "https://api.hirefinn.ai/api/v1/phone_numbers/6b1f0c2e-3d4a-4f5b-9c8d-2e7a1b9f4c03" \
  -H "Authorization: Bearer $FINN_API_KEY"
{
  "success": true,
  "data": { "id": "6b1f0c2e-3d4a-4f5b-9c8d-2e7a1b9f4c03", "released": true }
}

Releasing returns the number to the carrier and deletes it from your organization. There is no refund.

The API refuses to release:

  • a number used by a deployment that hasn't ended, whether it's the deployment's only number or one of the numbers in its number_pool: 409 number_in_use. Stop the deployment, then release the number.
  • a number that has ever been a deployment's phone_number_id, even if that deployment is stopped or completed: 409 number_in_use. Contact Finn support to release it. Parallel deployments (max_parallel_calls above 1) keep their number only in number_pool, so once one of them ends, it no longer blocks the release.
  • a number with assignment records, unless you pass force=true: 409 number_in_use.

Errors

StatuserrorEndpointWhen
400invalid_requestallid is not a UUID; country is not 2 letters; search is too long; provider is not a listed carrier; phone_number is malformed; or capabilities is not an object.
400price_currency_mismatchPOSTThe number is priced in a different currency from your wallet.
401api_key_requiredallNo Bearer finn_live_... key.
401invalid_api_keyallKey unknown or revoked.
402insufficient_creditsPOSTThe wallet cannot cover the rental. The body adds required_credits and available_credits.
403compliance_requiredPOSTYour organization's compliance application is not approved. Complete it at action_url.
403rental_unavailablePOSTYour organization is in proof-of-concept mode.
404phone_number_not_foundGET one, DELETENo number with that ID in your organization.
409compliance_requiredGET /availableIndia (IN) or Exotel inventory requested without an approved compliance application. Complete it at action_url.
409api_key_owner_requiredPOSTThe key's creator is no longer a member of your organization or has no email.
409number_in_useDELETEUsed by a deployment that hasn't ended (as its number or in its number_pool), ever used as a deployment's phone_number_id, or has assignment records and force was not true.
429rate_limitedallOver the endpoint's per-minute limit.
500rent_failedPOSTThe number's setup couldn't be started. The debit was refunded; the body includes transaction_id.
500internal_errorallUnexpected server error.
502provider_unavailableGET /available, DELETEThe carrier could not be reached. Retry later.
502price_unavailablePOSTThe rental price could not be confirmed with the carrier. Nothing was charged. Retry later.

Error bodies have the shape { "error": "...", "message": "..." }; internal_error has no message. See api-errors.