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

# List phone numbers

> The numbers assigned to your workspace.

<Note>
  `status` is `inactive` when the number is no longer present in its carrier account - a call placed
  from it will fail. Buying, releasing and assigning numbers are dashboard-only actions.
</Note>

## Where the number came from

Two fields answer this, and they mean different things:

|            |                                                                                                             |
| ---------- | ----------------------------------------------------------------------------------------------------------- |
| `source`   | `vocily` - you rent it from us. `byoc` - it sits on a carrier account you connected yourself.               |
| `provider` | `vocily` for a number you rent from us. For a BYOC number, the carrier carrying it (`plivo`, `vobiz`, ...). |

`rental` is populated only for `source: "vocily"` and carries `monthly_price`, `renewal_date` and
`rented_at`. It is `null` for a BYOC number, where your own carrier bills you directly.

`provider_sid` and `connection_id` identify the number and the account inside **your** carrier
account, so they are populated for BYOC and `null` for a number you rent from us.

`connection_id` is what tells two of your own carrier accounts apart - `provider` cannot, since
both would read `plivo`. It is **opaque**: no endpoint resolves it to a name, so group numbers by
it rather than trying to look it up.

<Note>
  `provider`, `number_type` and `lifecycle_status` are open sets - new values will be added. Treat
  them as strings, not as an exhaustive list.
</Note>


## OpenAPI

````yaml developers/openapi.json GET /v1/numbers
openapi: 3.1.0
info:
  title: Vocily API
  description: >-
    Public REST API for Vocily. Build and configure an agent, publish a version
    and put it live, place outbound calls, and read back calls, chats and what
    the agent remembered. Authenticate with a workspace API key as a Bearer
    token.


    Some things stay in the dashboard, by design: creating an API key, buying or
    connecting a phone number, setting an agent's webhook URL, connecting
    WhatsApp and its templates, building HTTP tools, and running batch
    campaigns.
  version: v1
servers:
  - url: https://api.vocily.ai
    description: Production
security: []
paths:
  /v1/numbers:
    get:
      tags:
        - numbers
      summary: List Numbers
      description: >-
        List the numbers assigned to this workspace. Carrier status is computed
        from the

        org's connected accounts, so a number whose account has gone shows as
        inactive.
      operationId: list_numbers_v1_numbers_get
      parameters: []
      responses:
        '200':
          description: The numbers assigned to this workspace.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/PublicNumberRead'
              example:
                - id: 00000003-0000-4000-8000-000000000003
                  number: '+919876500000'
                  carrier_status: active
                  source: byoc
                  provider: plivo
                  provider_sid: null
                  connection_id: 00000004-0000-4000-8000-000000000004
                  lifecycle_status: active
                  country_iso: null
                  number_type: null
                  inbound_agent:
                    id: 00000002-0000-4000-8000-000000000002
                    name: zdfbdhjfbdkfbdkjfbkdjfb
                  outbound_agents:
                    - id: 00000002-0000-4000-8000-000000000002
                      name: zdfbdhjfbdkfbdkjfbkdjfb
                  rental: null
                  created_at: '2026-09-12T22:45:02.810506Z'
                  updated_at: '2026-09-12T23:02:43.014234Z'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
              example:
                detail: Invalid API key
                code: UNAUTHORIZED
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '429':
          description: Rate limit exceeded — honor `Retry-After`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
              example:
                code: rate_limited
      security:
        - bearerAuth: []
components:
  schemas:
    PublicNumberRead:
      description: >-
        One phone number.


        Two fields say where it comes from: `source` is who you get it from —
        `vocily` for a number you rent from us, `byoc` for one on your own
        carrier account — and `provider` is the carrier that actually carries
        it.
      properties:
        id:
          description: >-
            Our stable id for this number. Prefer it over `number` as a key: an
            E.164 is re-rentable and a released number keeps its row.
          title: Id
          type: string
        number:
          description: The number itself, E.164.
          title: Number
          type: string
        carrier_status:
          description: >-
            `active` or `inactive` — whether the number is still present in its
            own carrier account. An `inactive` number will fail if you dial from
            it. A different question from `lifecycle_status`: a number you still
            rent reads `active` here only while the carrier lists it, and a
            carrier outage never changes its rental state.
          title: Carrier Status
          type: string
        source:
          description: >-
            `vocily` if you rent it from us, `byoc` if you brought your own
            carrier account.
          title: Source
          type: string
        provider:
          description: >-
            The carrier your number runs on. `vocily` for a number you rent from
            us. Your own carrier is named (`plivo`, `vobiz`) when `source` is
            `byoc`. **Unstable enum: it grows as we support more carriers, so
            never switch exhaustively on it.**
          title: Provider
          type: string
        provider_sid:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            The carrier's own identifier. `null` for a number you rent from us,
            where the id lives in our account.
          title: Provider Sid
        connection_id:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            Which of your own carrier accounts this number is attached to, when
            `source` is `byoc` — it tells two of your accounts apart, which
            `provider` alone cannot. **Opaque**: no endpoint resolves it to a
            name, so group by it rather than looking it up. `null` for a number
            you rent from us.
          title: Connection Id
        lifecycle_status:
          description: >-
            Where the number is in its rental life with us — `pending`,
            `active`, `failed`, `releasing`, `released`. A `released` number
            keeps its row as a billing record. **Open set.** A different
            question from `status`, which is carrier presence.
          title: Lifecycle Status
          type: string
        country_iso:
          anyOf:
            - type: string
            - type: 'null'
          description: ISO country code the number belongs to.
          title: Country Iso
        number_type:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            How the carrier classified it at purchase — `local`, `mobile`,
            `tollfree`. **Unstable enum**: never switch exhaustively on it.
          title: Number Type
        inbound_agent:
          anyOf:
            - $ref: '#/components/schemas/PublicNumberAgent'
            - type: 'null'
          description: The agent answering INBOUND on this number, if any.
        outbound_agents:
          description: >-
            Agents that dial OUT from this number, read from each agent's LIVE
            version — an unpublished draft never appears here.
          items:
            $ref: '#/components/schemas/PublicNumberAgent'
          title: Outbound Agents
          type: array
        rental:
          anyOf:
            - $ref: '#/components/schemas/PublicNumberRental'
            - type: 'null'
          description: >-
            Billing detail for a number you rent from us. `null` for BYOC, which
            you pay your own carrier for.
        created_at:
          description: When the number was added to your workspace (UTC, ISO 8601).
          format: date-time
          title: Created At
          type: string
        updated_at:
          description: When its record last changed (UTC, ISO 8601).
          format: date-time
          title: Updated At
          type: string
      required:
        - id
        - number
        - carrier_status
        - source
        - provider
        - provider_sid
        - connection_id
        - lifecycle_status
        - country_iso
        - number_type
        - inbound_agent
        - outbound_agents
        - rental
        - created_at
        - updated_at
      title: PublicNumberRead
      type: object
    ApiError:
      type: object
      description: >-
        Error envelope. `code` is derived from the HTTP status, so branch on it
        for the CLASS of failure; the specific reason is `detail.code`. Every
        public refusal carries both.
      properties:
        detail:
          type: object
          description: >-
            The reason. `code` is the domain reason (e.g. `call_not_found`) and
            `message` is a sentence safe to log. On a `422` it also carries
            `errors[]`, one entry per rejected field — see
            `HTTPValidationError`.
          properties:
            code:
              type: string
              example: call_not_found
            message:
              type: string
              example: Call not found
          required:
            - code
            - message
        code:
          type: string
          description: Derived from the HTTP status, not the domain reason.
          example: NOT_FOUND
    HTTPValidationError:
      type: object
      title: HTTPValidationError
      description: >-
        A request the API could not read: a field of the wrong type, out of
        range, missing, or one we do not accept. Same envelope as every other
        error.
      properties:
        detail:
          type: object
          description: >-
            What was wrong, as `code`, a one-line `message`, and every offending
            field in `errors`.
          required:
            - code
            - message
            - errors
          properties:
            code:
              type: string
              enum:
                - validation_error
            message:
              type: string
              description: >-
                The first problem in one line, with a count of the rest — e.g.
                `model.temperature: Input should be less than or equal to 2 (and
                1 more)`.
            errors:
              type: array
              items:
                $ref: '#/components/schemas/ValidationError'
              description: >-
                One entry per offending field. **Every problem is reported at
                once**, not just the first, so a malformed body needs one round
                trip to fix rather than one per field.
        code:
          type: string
          enum:
            - VALIDATION_ERROR
          description: Derived from the HTTP status, as on every error.
    PublicNumberAgent:
      description: >-
        An agent bound to a number. `id` + `name` only — the same minimal agent
        shape

        `GET /v1/agents` publishes, for the same reason: an agent's config is
        not a public contract.
      properties:
        id:
          description: The agent's id.
          title: Id
          type: string
        name:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: The agent's name.
          title: Name
      required:
        - id
      title: PublicNumberAgent
      type: object
    PublicNumberRental:
      description: >-
        Rental terms. Present only for a number you rent from Vocily (`source:
        "vocily"`), and `null` for a number on your own carrier account, where
        your carrier bills you directly.


        `monthly_price` is in major units of `currency` and is fixed at
        purchase: it is what YOU pay, so a change to our list price never
        reprices a rental you already hold.
      properties:
        currency:
          type: string
          title: Currency
          description: ISO currency code.
          default: USD
        monthly_price:
          anyOf:
            - type: number
            - type: 'null'
          default: null
          description: What this number costs per month.
          title: Monthly Price
        renewal_date:
          anyOf:
            - format: date
              type: string
            - type: 'null'
          default: null
          description: When it next renews.
          title: Renewal Date
        rented_at:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          default: null
          description: When you started renting it.
          title: Rented At
        released_at:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          default: null
          description: When you gave it up. `null` while you still hold it.
          title: Released At
      title: PublicNumberRental
      type: object
    ValidationError:
      type: object
      title: ValidationError
      required:
        - field
        - message
        - type
      properties:
        field:
          type: string
          description: >-
            The offending field as a path from the root of your request —
            `voice.speed`, `variables[0].key`, or `query.limit` for a query
            parameter. **This is the field to read.**
        message:
          type: string
          description: What is wrong with it, in plain language.
        type:
          type: string
          description: >-
            A stable machine code for the kind of failure, e.g.
            `extra_forbidden` for a field we do not accept, `missing` for a
            required one, or `less_than_equal` for a number out of range. Switch
            on this rather than on `message`, which may be reworded.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: 'Your API key as a Bearer token, e.g. `Authorization: Bearer vk_…`.'

````