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

# Raise a ticket

> Always recorded with source 'human'. Nothing may claim that except this path: the action handler records 'agent' or 'flow', and the distinction tells whoever picks the ticket up how much to trust the wording. A contact or team outside the caller's scope is refused — the foreign key proves the row exists, not that the caller may see it.



## OpenAPI

````yaml /api-reference/openapi-public.json post /tickets
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:
  /tickets:
    post:
      tags:
        - Tickets
      summary: Raise a ticket
      description: >-
        Always recorded with source 'human'. Nothing may claim that except this
        path: the action handler records 'agent' or 'flow', and the distinction
        tells whoever picks the ticket up how much to trust the wording. A
        contact or team outside the caller's scope is refused — the foreign key
        proves the row exists, not that the caller may see it.
      operationId: postTickets
      parameters:
        - $ref: '#/components/parameters/idempotencyKey'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateTicketRequest'
        required: true
      responses:
        '201':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Ticket'
          description: Created
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'
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:
    CreateTicketRequest:
      properties:
        body:
          type: string
        contact_id:
          format: uuid
          type: string
        organisation_id:
          format: uuid
          type: string
        priority:
          enum:
            - low
            - normal
            - high
            - urgent
          type: string
        subject:
          type: string
        team_id:
          format: uuid
          type: string
      required:
        - subject
      type: object
    Ticket:
      properties:
        body:
          type: string
        call_uuid:
          format: uuid
          type: string
        contact_e164:
          type: string
        contact_id:
          format: uuid
          type: string
        created_at:
          format: date-time
          type: string
        id:
          format: uuid
          type: string
        organisation_id:
          format: uuid
          type: string
        priority:
          enum:
            - low
            - normal
            - high
            - urgent
          type: string
        ref:
          description: >-
            Per-organisation, so a customer can read it out. Not a global
            sequence, which would leak one tenant's volume into another's
            numbering.
          type: integer
        resolved_at:
          format: date-time
          nullable: true
          type: string
        source:
          description: >-
            Who raised it: a model mid-call, a person in the panel, or an IVR
            flow node.
          enum:
            - agent
            - human
            - flow
          type: string
        status:
          enum:
            - open
            - pending
            - resolved
            - closed
          type: string
        subject:
          type: string
        team_id:
          format: uuid
          type: string
        update_count:
          type: integer
        updated_at:
          format: date-time
          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:
    BadRequest:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
      description: The request is not valid. The message names every field that is wrong.
    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

````