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

# An AI agent calls a number

> The profile's virtual agent rings `to` from `caller_id` (one of your numbers; optional when you have exactly one) and talks to whoever answers, with `variables` in its brief as what it knows about this call. Answers 202 at once: the dial happens in the background, and how it went is posted to callback_url (call.started, call.answered, conversation.completed with the summary, call.ended; call.failed with the reason if nobody answered) and kept on the request (GET /call-requests/{id}). Refused 422 with the reason: the number is one of your own, no route reaches it, billing refuses it, or no agent uses the profile. Rate limited with click-to-call (60 a minute per key). Requires calls:originate.



## OpenAPI

````yaml /api-reference/openapi-public.json post /calls/ai
openapi: 3.0.3
info:
  description: >-
    The API your own systems use: place and follow calls, have an AI agent call
    someone, run campaigns and get their results, keep contacts in step with
    your CRM, and receive signed webhooks. Authenticate with an integration key
    (Authorization: Bearer ft_...), used only from the IP addresses it allows.
  title: FireTone API
  version: 0.1.0
servers:
  - description: Your platform's API host
    url: https://{host}/api/v1
    variables:
      host:
        default: api.firet.one
security:
  - bearerAuth: []
tags:
  - name: Auth
  - description: >-
      Live calls and what can be done to them: hang up, hold, transfer, park,
      merge, monitor, whisper; the Desk's own call.
    name: Calls
  - description: 'Outbound campaigns: contacts, attempts, outcomes.'
    name: Campaigns
  - description: 'Customers: who called, what is known about them, and their memory.'
    name: Contacts
  - description: What was said on an AI call, and the review of it.
    name: Conversations
  - description: >-
      Your own systems: HTTP connections an IVR calls mid-call, and webhooks for
      call events. Tenant URLs must be public https addresses.
    name: Integrations
  - name: Live
  - name: Provisioning
  - name: Reporting
  - description: Tickets raised by people, agents and the API.
    name: Tickets
  - description: Messages left for an extension or a queue.
    name: Voicemail
paths:
  /calls/ai:
    post:
      tags:
        - Live
      summary: An AI agent calls a number
      description: >-
        The profile's virtual agent rings `to` from `caller_id` (one of your
        numbers; optional when you have exactly one) and talks to whoever
        answers, with `variables` in its brief as what it knows about this call.
        Answers 202 at once: the dial happens in the background, and how it went
        is posted to callback_url (call.started, call.answered,
        conversation.completed with the summary, call.ended; call.failed with
        the reason if nobody answered) and kept on the request (GET
        /call-requests/{id}). Refused 422 with the reason: the number is one of
        your own, no route reaches it, billing refuses it, or no agent uses the
        profile. Rate limited with click-to-call (60 a minute per key). Requires
        calls:originate.
      operationId: postCallsAi
      parameters:
        - $ref: '#/components/parameters/idempotencyKey'
        - description: 'true: check everything, place nothing, and return the plan.'
          in: query
          name: dry_run
          required: false
          schema:
            type: boolean
      requestBody:
        content:
          application/json:
            schema:
              properties:
                callback_url:
                  type: string
                caller_id:
                  example: '+61298765432'
                  type: string
                organisation_id:
                  format: uuid
                  type: string
                profile_id:
                  format: uuid
                  type: string
                reference:
                  maxLength: 128
                  type: string
                to:
                  example: '+61412345678'
                  type: string
                variables:
                  additionalProperties:
                    maxLength: 500
                    type: string
                  example:
                    interest: teeth whitening
                    name: Sam
                  maxProperties: 30
                  type: object
              required:
                - profile_id
                - to
              type: object
        required: true
      responses:
        '200':
          description: A dry run's plan
        '202':
          content:
            application/json:
              schema:
                properties:
                  plan:
                    properties:
                      agent:
                        type: string
                      caller_id:
                        type: string
                      max_seconds:
                        type: integer
                      to_e164:
                        type: string
                      trunk:
                        type: string
                    type: object
                  reference:
                    type: string
                  request_id:
                    type: string
                  status:
                    type: string
                type: object
          description: Dialling
        '400':
          $ref: '#/components/responses/BadRequest'
        '409':
          description: >-
            no_callback_secret: a callback_url was given and the organisation
            has no callback secret to sign it with.
        '422':
          description: refused, with the reason
        '503':
          description: >-
            The call was not placed because the node has no room for it right
            now: it is at its channel limit, the machine is loaded, or every AI
            session it allows is in use. Code `node_busy`, with a `Retry-After`
            of 30 seconds. Nothing rang and nothing was billed; send the same
            request again. Distinct from 422, which means the request itself is
            wrong.
components:
  parameters:
    idempotencyKey:
      description: >-
        Any string up to 255 characters. A retry with the same key and the same
        body gets the first answer again (with Idempotent-Replayed: true)
        instead of doing it twice; the same key with a different body is 409
        idempotency_mismatch; while the first is still running, 409
        idempotency_in_progress. Kept 24 hours.
      in: header
      name: Idempotency-Key
      required: false
      schema:
        maxLength: 255
        type: string
  responses:
    BadRequest:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
      description: The request is not valid. The message names every field that is wrong.
  schemas:
    Error:
      properties:
        error:
          properties:
            code:
              enum:
                - invalid_request
                - invalid_credentials
                - unauthenticated
                - forbidden
                - not_found
                - conflict
                - internal
              type: string
            message:
              type: string
          required:
            - code
            - message
          type: object
      required:
        - error
      type: object
  securitySchemes:
    bearerAuth:
      bearerFormat: JWT or API key
      description: >-
        Every request sends `Authorization: Bearer <token>`. The token is either
        a panel session (a JWT from /auth/login, 12 hours) or an API key
        `ft_<id>_<secret>`. An API key is accepted only from an address on its
        IP allowlist (403 ip_not_allowed otherwise; 403 ip_allowlist_required
        for an old key that has none), is limited to its rate per minute (429
        rate_limited with Retry-After; X-RateLimit-Limit/Remaining/Reset on
        every response), and at most 60 call placements a minute.
      scheme: bearer
      type: http

````