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

# Quote the price of a call

> What a minute of an AI call to a number would cost on your account, before you place it. It answers the way `POST /v1/calls` would: the number's zone and the price per minute, or the `reason` the call would be refused. Read-only: it dials nothing, holds no credit and creates no call. Pass `from`, one of your own numbers, to price a call that presents it: on your own carrier a call pays the AI part alone.



## OpenAPI

````yaml /api-reference/openapi.json get /v1/pricing/quote
openapi: 3.0.3
info:
  title: TopCalls Voice API
  description: |
    Place and manage AI phone calls, campaigns, leads and phone numbers.

    ## Authentication

    Send your API key as a bearer token on every request:

    ```
    Authorization: Bearer tc_live_xxxxx
    ```

    A missing or invalid key gets `401`. Keys carry scopes, and a key without
    the scope an endpoint needs gets `403`.

    ## Rate limits

    The first three limits are per account, so every API key on the account
    shares them. The last is per IP address.

    - All `/v1` endpoints: 120 requests per minute unless we've raised it for
      your account. Over it, you get `429` with `Retry-After` and a plain-text
      body. Responses carry `RateLimit-Limit`, `RateLimit-Remaining` and
      `RateLimit-Reset`.
    - `POST /v1/calls` also counts against your account's
      `max_calls_per_minute` (default 20) in a fixed 60-second window. Going
      over returns `429`, `Retry-After: 60` and `code: RATE_LIMITED`. A request
      counts once its body validates, even if it then fails (say, a `404` on an
      unknown `lead_id`).
    - A call placed while every concurrent-call slot is busy gets `429` with
      `code: concurrency_limit` and no `Retry-After`. Retry once a call ends.
    - Failed authentication: after 600 requests within a minute whose API key
      is refused with `401`, every `/v1` request from that IP address gets
      `429` with `Retry-After` until the minute is up, even one with a valid key.

    On a `429` with `Retry-After`, wait that many seconds, then retry. Back off
    longer on repeats.

    ## Error format

    Errors are RFC 7807 Problem+JSON (`application/problem+json`), except the
    plain-text 120-per-minute `429`. Branch on `status` and `code`:

    ```json
    {
      "status": 402,
      "title": "Insufficient Quota",
      "code": "insufficient_quota",
      "detail": "Not enough credit to place this call. Add credit in Billing (steps: https://docs.topcalls.ai/concepts/credit#adding-credit).",
      "available": 0.5,
      "requested": 2
    }
    ```
  version: 1.0.0
  contact:
    name: TopCalls Support
    url: https://topcalls.ai
  license:
    name: Proprietary
servers:
  - url: https://api.topcalls.ai
    description: Production
security: []
tags:
  - name: Calls
    description: Place and manage phone calls
  - name: Campaigns
    description: Create, run and test call campaigns
  - name: Phone Numbers
    description: Phone numbers and carriers
  - name: Account
    description: Credit balance, credit ledger, call price quotes and daily call analytics
  - name: Webhooks
    description: Webhook subscriptions and events
  - name: Configuration
    description: Available models, voices and platform capabilities
paths:
  /v1/pricing/quote:
    get:
      tags:
        - Account
      summary: Quote the price of a call
      description: >-
        What a minute of an AI call to a number would cost on your account,
        before you place it. It answers the way `POST /v1/calls` would: the
        number's zone and the price per minute, or the `reason` the call would
        be refused. Read-only: it dials nothing, holds no credit and creates no
        call. Pass `from`, one of your own numbers, to price a call that
        presents it: on your own carrier a call pays the AI part alone.
      operationId: getPriceQuote
      parameters:
        - name: to
          in: query
          required: true
          description: The number to call, in E.164. In a URL, write the `+` as `%2B`.
          schema:
            type: string
            pattern: ^\+[1-9]\d{1,14}$
          example: '+14155551234'
        - name: from
          in: query
          required: false
          description: >-
            The caller ID you would present, one of your own numbers, in E.164.
            Without it the call is priced from the default number.
          schema:
            type: string
            pattern: ^\+[1-9]\d{1,14}$
          example: '+18005551234'
      responses:
        '200':
          description: >-
            The quote. A number that can't be called is a `200` with `allowed:
            false` and a `reason`, so you can check before dialing.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PriceQuote'
              examples:
                allowed:
                  summary: A number that can be called
                  value:
                    to: '+14155551234'
                    allowed: true
                    zone: 1
                    price_per_minute_usd: '0.25'
                    reason: null
                refused:
                  summary: A country TopCalls does not call
                  value:
                    to: '+6777412345'
                    allowed: false
                    zone: null
                    price_per_minute_usd: null
                    reason: not_available
        '400':
          description: '`to` is missing, or `to` or `from` is not in E.164 format.'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          description: >-
            `from` isn't an active or verified number on your account
            (`from_number_not_owned`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/FromNumberNotOwnedProblem'
        '500':
          description: >-
            The price could not be read. Nothing is dialed or held. Retry
            shortly.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '503':
          description: The destination check is briefly unavailable. Retry shortly.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/DestinationPolicyUnavailableProblem'
      security:
        - bearerAuth: []
components:
  schemas:
    PriceQuote:
      type: object
      required:
        - to
        - allowed
        - zone
        - price_per_minute_usd
        - reason
      description: >-
        What a minute of an AI call to `to` costs on this account, or why the
        number can't be called. Nothing is dialed, held or saved.
      properties:
        to:
          type: string
          description: The number you asked about, in E.164.
          example: '+14155551234'
        allowed:
          type: boolean
          description: >-
            True when a call to this number would be placed. False when it would
            be refused with `422 destination_not_allowed`.
          example: true
        zone:
          type: integer
          enum:
            - 1
            - 2
            - 3
            - null
          nullable: true
          description: >-
            The destination's zone, from 1 (cheapest line) to 3. A number in a
            dearer range than its country is quoted at the zone of the range.
            Null when `allowed` is false.
          example: 1
        price_per_minute_usd:
          type: string
          nullable: true
          description: >-
            What one minute costs in US dollars, as an exact decimal string. The
            AI part plus the line of the zone, the AI part alone when `from` is
            a number on your own carrier, or your negotiated price. Null when
            `allowed` is false.
          example: '0.25'
        reason:
          type: string
          nullable: true
          enum:
            - invalid_number
            - short_code
            - number_type
            - country_not_enabled
            - not_available
            - range_above_cap
            - null
          description: >-
            Why the number can't be called; the same value `POST /v1/calls`
            returns in `reason` (see `DestinationRefusalReason` for what each
            means). Null when `allowed` is true.
    Problem:
      type: object
      required:
        - status
        - title
      properties:
        type:
          type: string
          format: uri
          description: Error type URI. Not every error sets it.
        title:
          type: string
          description: Short summary of the error.
        status:
          type: integer
          description: HTTP status code.
        detail:
          type: string
          description: What went wrong, in plain words.
        code:
          type: string
          description: >-
            Stable code to branch on, sent on errors that have one (such as
            `insufficient_quota` or `PROMPT_SAFETY_FRAUD`). Each endpoint's
            examples show its values.
        instance:
          type: string
          description: >-
            Request id, sent on some errors. It's your `X-Request-Id` header
            when you sent one.
        errors:
          type: array
          description: Field-level validation failures, on `400`.
          items:
            type: object
            properties:
              path:
                type: string
                description: Field path, such as `phone_number`.
              message:
                type: string
                description: What's wrong with the field.
              code:
                type: string
                description: Validation code, such as `invalid_string` or `custom`.
    FromNumberNotOwnedProblem:
      description: >-
        A call's `from_number`, or a campaign's `config.from_number`, isn't an
        active or verified number on the account. Nothing is placed, held or
        saved.
      allOf:
        - $ref: '#/components/schemas/Problem'
        - type: object
          properties:
            code:
              type: string
              description: The caller ID isn't one of the account's numbers.
              enum:
                - from_number_not_owned
              example: from_number_not_owned
      example:
        type: https://api.topcalls.ai/errors/from_number_not_owned
        title: Caller ID Not Allowed
        status: 422
        code: from_number_not_owned
        detail: >-
          from_number must be an active or verified number on your account. Use
          one of your numbers, or omit from_number to call from the default
          number.
    DestinationPolicyUnavailableProblem:
      description: >-
        The destination check can't run right now. No call is placed and no
        credit is held. Retry the same request shortly.
      allOf:
        - $ref: '#/components/schemas/Problem'
        - type: object
          properties:
            code:
              type: string
              description: The destination check is briefly unavailable.
              enum:
                - destination_policy_unavailable
              example: destination_policy_unavailable
      example:
        type: https://api.topcalls.ai/errors/destination_policy_unavailable
        title: Service Unavailable
        status: 503
        code: destination_policy_unavailable
        detail: >-
          The destination check is temporarily unavailable. No call was placed.
          Retry shortly.
  responses:
    Unauthorized:
      description: Missing or invalid API key
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            status: 401
            title: Unauthorized
            detail: Invalid API key
    Forbidden:
      description: The API key lacks a scope this endpoint needs
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            status: 403
            title: Forbidden
            detail: 'Missing required scope(s): calls:write'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: |
        Use `Authorization: Bearer tc_live_xxxxx`

````

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