> ## Documentation Index
> Fetch the complete documentation index at: https://docs.verbeo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# List phone numbers

> Page through the phone numbers in your workspace, newest first, with an optional search on the number or its nickname.

Returns the phone numbers in the workspace your API key belongs to, newest first.

<Note>
  This read is a `POST` because a list query is a document: `page`, `size` and `search` arrive typed as themselves instead of being coerced from a query string. It changes nothing.
</Note>

## Body

<ParamField body="page" type="number" default="1">
  1-based page number. Pass back `pagination.next_cursor` from the previous response.
</ParamField>

<ParamField body="size" type="number" default="10">
  Page size, between `1` and `100`.
</ParamField>

<ParamField body="search" type="string">
  Case-insensitive substring of `phone_number` or `nickname`, 1–255 characters. Leave it out for no filter: an empty string is rejected.
</ParamField>

## Request

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.verbeo.ai/v1/phone-number/list" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{ "page": 1, "size": 20 }'
  ```

  ```javascript Node.js theme={null}
  const res = await fetch("https://api.verbeo.ai/v1/phone-number/list", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.VERBEO_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ page: 1, size: 20 }),
  });
  const { data, pagination } = await res.json();
  ```

  ```python Python theme={null}
  import os, requests

  res = requests.post(
      "https://api.verbeo.ai/v1/phone-number/list",
      headers={"Authorization": f"Bearer {os.environ['VERBEO_API_KEY']}"},
      json={"page": 1, "size": 20},
  )
  body = res.json()
  numbers, pagination = body["data"], body["pagination"]
  ```
</CodeGroup>

## Response

`200 OK`. Standard envelope plus pagination — see [Responses](/api-reference/responses#list-responses-and-pagination). Each item is a whole [phone number object](/api-reference/phone-numbers/overview#the-phone-number-object). `next_cursor` is the next **page number**, or `null` on the last page. Stop there: a page past the last one is not an empty list. It answers `500 INTERNAL_ERROR`, and sending it again does not help.

```json theme={null}
{
  "success": true,
  "data": [
    {
      "id": "7d9f3b52-4c1e-4a8e-9b1a-2f6c0d4e8a11",
      "workspace_id": "123e4567-e89b-12d3-a456-426614174000",
      "phone_number": "+14155550123",
      "nickname": "Main line",
      "provider": "livekit_sip",
      "is_active": true,
      "max_cps": 1,
      "inbound_agent_id": "550e8400-e29b-41d4-a716-446655440000",
      "outbound_agent_id": null,
      "inbound_webhook_url": null,
      "created_at": "2026-01-15T10:30:00.123456+00:00",
      "updated_at": "2026-01-22T14:00:00.654321+00:00",
      "inbound_agent_name": "Customer Support",
      "outbound_agent_name": null
    }
  ],
  "pagination": { "total": 1, "count": 1, "next_cursor": null }
}
```

## Errors

| Code | Status | When |
| - | - | - |
| `VALIDATION_FAILED` | 422 | `page` below `1`, `size` outside `1`–`100`, or a `search` that is empty or longer than 255 characters. |
| `UNAUTHORIZED` | 401 | Invalid, inactive or expired key. A request with no `Authorization: Bearer vbr_…` header is a `401` too, but [outside the envelope](/api-reference/errors): check the status first. |
| `FORBIDDEN` | 403 | A public (`vbr_pub_…`) key. |
| `INTERNAL_ERROR` | 500 | A page past the last one. It fails the same way every time: do not retry it. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.