---
title: "List your caller-ID pool, and why each number is or is not displayable"
method: GET
path: "/voice/caller-id/pool"
tags: ["voice"]
---

# List your caller-ID pool, and why each number is or is not displayable

`GET /voice/caller-id/pool`

## Request

- Base URL: `https://corebee.ai/api/v1`
- URL: `https://corebee.ai/api/v1/voice/caller-id/pool`
- Auth: HTTP bearer

The numbers your organization may display as the caller ID on an outbound bridge, and for each one whether the selector may actually use it, and if not, exactly which screen refused it. Requires the voice:bridge scope.

⛔ READ ONLY, AND THE MISSING WRITE HALF IS THE DESIGN RATHER THAN AN UNFINISHED PART. There is no POST, PATCH or DELETE on this path and there will not be one: every row here is a number somebody paid for that a stranger's handset will display, so adding one is a purchase and retiring one is a reputation decision. Both are operator actions, taken deliberately, out of band. This endpoint is how you and we SEE what was added and why it is or is not being used.

WHY THIS ENDPOINT EXISTS. The selector cannot fail a call: a pool that is broken and a pool that was never configured both end on your organization default number and both produce a working call. So "I added a San Antonio number and calls still come from Sacramento" has no symptom to look at. This endpoint is that symptom, in one request: read `refusal` on the row instead of placing a call to find out.

⛔ READ `pool_status` BEFORE YOU READ `numbers`, AND DO NOT TREAT AN EMPTY LIST AS AN ANSWER. `ok` with an empty array means you have no pool rows. `table_absent` means the table backing this feature is not in this database yet, that is the current state, the migration is applied by hand, and the empty list carries no information at all. `query_error` means the read failed right now and is a DIFFERENT event from "not shipped yet"; collapsing the two is how a broken pool spends a month looking like an unbuilt one. All three come back with HTTP 200, because a caller-ID feature must never be able to refuse a call, so a non-200 is never the way you learn the pool is unreadable.

⛔ `selectable: true` MEANS ELIGIBLE, NOT "WILL BE USED". Eligible rows still compete: the selector prefers a market match and breaks ties on the lowest row id, so the first number an operator added for a market keeps winning until they retire it. And three further refusals are decided per CALL, against the number being dialled, and therefore CANNOT appear in this response at all, displaying the very number we are about to dial, a row whose channel binding names a different number, and a row that has passed its daily dial ceiling (which is reported as an alert on the call and never reassigns the call to another number). If a number is selectable here and still was not used, those are where to look, in the session record for that call.

⛔ `refusal` REPORTS THE FIRST REASON, NOT ALL OF THEM. The screen is ordered and stops at the first failure, so a row that is retired AND unverified reports only `retired`. Fix what it names, read again, and expect a different refusal rather than a pass.

ONE REFUSAL IS ABOUT OUR DEPLOYMENT AND NOT ABOUT YOUR ROW. `callback_line_disarmed` fires when a row routes call-backs to our own answering line and that line is not armed on this deployment. Nothing you can change on the row clears it, and it is screened deliberately: a returning caller would otherwise reach dead air on a number already in circulation, which is worse than the default number the call would have used.

THE REACHABILITY STAMP IS NOT OPTIONAL AND NO FLAG OVERRIDES IT. A displayed number has to be one the person who sees it can dial back and reach something; two of the state statutes that permit substituting a number say so in as many words. Until an operator has verified out of band that calling the number reaches something, the row is inert and reports `callback_unverified`.

`default_did` IS WHERE A CALL LANDS WHEN NOTHING IN THE POOL WINS, your connected Telnyx number, or the first one we hold if none is marked connected. It is reported so you can see the fallback without placing a call to observe it. It is resolved from up to 50 of your Telnyx numbers, so an organization holding more than that should treat both this field and the `not_an_owned_telnyx_did` refusal as advisory rather than final.

`rotation_policy` IS THE CONSTANT STRING "none_automatic" AND IT IS ON THE WIRE ON PURPOSE. Nothing here rotates numbers under load, ever. Do not build a rotation client against this endpoint; a number is retired by a human, deliberately.

`expected_attestation` IS AN EXPECTATION, NOT A MEASUREMENT. It is what we believe the carrier will attest for this number and it has not been verified against live calls. `market_label` is derived from the number's own area code rather than from the stored `market_key`, so the two can describe different places on a mis-keyed row, and a `market_key` that this system does not recognise is refused outright (`market_key_unknown`) rather than quietly matching nothing.

## Response `200`

OK. Also the status when the pool could not be read, see pool_status.

- object
  - `data` object, required
    - `pool_status` 'ok' | 'table_absent' | 'query_error', required: ok, the pool was read. table_absent, the backing table is not in this database yet, and the empty numbers array means nothing. query_error, the read failed right now. Never infer any of the three from the length of numbers.
    - `default_did` string, nullable, required: The number a call falls back to when no pool row is selected. Null when your organization holds no usable Telnyx number.
    - `rotation_policy` 'none_automatic', required: Constant. Stated on the wire so nobody builds a rotation client against a system that does not rotate.
    - `numbers` CallerIdPoolNumber[], required: Up to 200 pool rows, INCLUDING retired ones, a retired row is reported with refusal "retired" rather than omitted, so a number that stopped being used looks different from a number that was never added.
      - `e164` string, required: The number as it would be displayed.
      - `kind` 'owned' | 'dealer_verified', required: owned, a Telnyx number we hold. dealer_verified, a DEALERSHIP's own number we have permission to display on their behalf. Any other value is refused as unknown_kind rather than ignored.
      - `market_key` string, nullable: The market this row was filed under. Optional, a row may be region-only. A key this system does not recognise is refused (market_key_unknown), because it could never match anything and is almost always a typo.
      - `market_label` string, nullable: ⛔ DERIVED FROM THE NUMBER'S OWN AREA CODE, NOT FROM market_key. So it can disagree with market_key on a mis-keyed row, and it can be present on a row whose market_key is null. Display only.
      - `npa` string, nullable: The area code recorded on the row. When present it must equal the number's ACTUAL area code or the row is refused (npa_mismatch), pasting the consumer's area code here would otherwise create a row that matches confidently and displays the wrong number.
      - `region_code` string, nullable: Two-letter state the row was filed under. Informational.
      - `expected_attestation` string, nullable: What we EXPECT the carrier to attest for this display. An expectation carried forward from how the number was obtained, not a measurement, and not verified against live calls.
      - `verification_method` string, nullable: How a dealer_verified row was verified. Required together with verified_at for that kind; missing either is refused (dealer_verification_incomplete), an unstamped row is not "not yet recorded", it is a number we have no permission to display.
      - `verified_at` string, date-time, nullable
      - `business_e164` string, nullable: For dealer_verified: the DEALERSHIP LINE this display is bound to. A dealership has many lines and a verification covers one of them, so without this binding the only available scope would be organization-wide, which would show one dealership's number on another's call. Missing or malformed is refused (dealer_binding_missing).
      - `callback_handling` 'staffed' | 'ivr_dnc' | 'null', nullable: What happens when somebody calls the displayed number back. staffed, it rings the dealership. ivr_dnc, it lands on our own answering line. Unset, or any other value, is refused (callback_handling_unset).
      - `callback_reachable_verified_at` string, date-time, nullable: When an operator verified OUT OF BAND that calling this number reaches something. Absent stamp, absent from the pool (callback_unverified). There is no flag that overrides this.
      - `daily_dial_ceiling` integer, nullable: ⛔ REPORTED HERE, ENFORCED ELSEWHERE. Passing this ceiling does NOT make a row unselectable and never reassigns a call to a different number; it raises an alert on the call so an operator can add capacity or retire the number. A row at its ceiling still reads selectable:true here, correctly.
      - `retired_at` string, date-time, nullable: When an operator retired the row. Set means refusal "retired".
      - `selectable` boolean, required: May the selector display this number? True means ELIGIBLE, not chosen, see the path description for the three per-call refusals that cannot appear here.
      - `refusal` 'retired' | 'malformed_e164' | 'unknown_kind' | 'no_channel_binding' | 'callback_unverified' | 'callback_handling_unset' | 'callback_line_disarmed' | 'dealer_verification_incomplete' | 'dealer_binding_missing' | 'market_key_unknown' | 'npa_mismatch' | 'not_an_owned_telnyx_did' | 'null', nullable, required: Null when selectable. Otherwise the FIRST screen that refused, in screen order: retired (an operator retired it); malformed_e164 (not a valid E.164 number); unknown_kind (kind is neither owned nor dealer_verified); no_channel_binding (the row names no channel, so a call would originate from this number while reading another number's voice and spoken lines, a call that works and is wrong); callback_unverified (nobody has verified that calling it back reaches anything); callback_handling_unset (it does not say what happens on a call-back); callback_line_disarmed (it routes call-backs to our answering line and that line is not armed on this deployment, a property of OUR deployment, not of your row); dealer_verification_incomplete (a dealer_verified row missing its verification stamp or method); dealer_binding_missing (a dealer_verified row with no valid dealership line bound to it); market_key_unknown (a market key this system does not recognise); npa_mismatch (the recorded area code is not the number's own); not_an_owned_telnyx_did (kind is owned but the number is not among the Telnyx numbers we hold for you, checked against up to 50 of them, so treat it as advisory if you hold more).

## Other responses

- `401`: Invalid or missing credential
- `403`: Forbidden (missing scope, or resource not owned by the credential org)
- `429`: Rate limit exceeded (code rate_limit_exceeded). The ceiling is 100 requests per minute per API key. The response carries Retry-After (seconds) plus X-RateLimit-Limit / X-RateLimit-Remaining / X-RateLimit-Reset, and repeats the seconds in the body as retry_after.
- `500`: Error

---

[API](https://skmtc.dev/corebee/apis/corebee-api.md) · [All operations](https://skmtc.dev/corebee/apis/corebee-api/llms.txt) · [OpenAPI document](https://skmtc.dev/corebee/apis/corebee-api/revisions/a48ea543b4dc?raw)
