> ## 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.

# Click to call

> Answers once the agent has picked up (up to 30 seconds); ?dry_run=true checks instead -- the extension has a phone registered to ring, the number resolves, an outside number has a route and credit -- and returns the plan, placing nothing. Rings the agent first, then dials the destination when they answer. Dialling the destination first would leave the called party waiting in silence, and if no agent answered they were called for nothing.\n\nThe answered leg enters the ordinary router, so trunk selection and the billing gate apply exactly as to a handset dialling out.



## OpenAPI

````yaml /api-reference/openapi-public.json post /calls
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:
    post:
      tags:
        - Live
      summary: Click to call
      description: >-
        Answers once the agent has picked up (up to 30 seconds); ?dry_run=true
        checks instead -- the extension has a phone registered to ring, the
        number resolves, an outside number has a route and credit -- and returns
        the plan, placing nothing. Rings the agent first, then dials the
        destination when they answer. Dialling the destination first would leave
        the called party waiting in silence, and if no agent answered they were
        called for nothing.\n\nThe answered leg enters the ordinary router, so
        trunk selection and the billing gate apply exactly as to a handset
        dialling out.
      operationId: postCalls
      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:
              $ref: '#/components/schemas/ClickToCallRequest'
        required: true
      responses:
        '202':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClickToCallResponse'
          description: Origination accepted
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: The extension is not registered on any node
        '502':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: The switch refused the origination
        '503':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          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 (for an
            AI call) 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.
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
  schemas:
    ClickToCallRequest:
      description: >-
        Who rings first (extension, or from) and the number to call
        (destination, or to).
      properties:
        callback_url:
          description: >-
            Where this call's events are POSTed, signed with the organisation's
            callback secret (see /integration/callback-secret): call.started,
            call.answered, call.ended, recording.ready, and call.failed if it
            never connected.
          type: string
        destination:
          example: '0255551234'
          type: string
        extension:
          example: '1001'
          type: string
        from:
          description: >-
            Who rings first, by one of: extension number, agent id, or the login
            email of a person linked to an agent.
          properties:
            agent_id:
              format: uuid
              type: string
            extension:
              type: string
            user_email:
              type: string
          type: object
        organisation_id:
          description: Optional when your scope has exactly one organisation.
          format: uuid
          type: string
        reference:
          description: >-
            Your own id for this call. On every event and callback for it, and
            on its CDR.
          maxLength: 128
          type: string
        to:
          description: The number to call; the same as destination.
          type: string
      type: object
    ClickToCallResponse:
      properties:
        call_uuid:
          format: uuid
          type: string
        reference:
          type: string
        request_id:
          description: >-
            When a reference or callback_url was given: the request to follow
            (GET /call-requests/{id}).
          type: string
      type: object
    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
  responses:
    Forbidden:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
      description: Outside the caller's scope, or insufficient role
  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

````