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

# Load contacts into a campaign

> Takes contact ids, not numbers: a campaign must not conjure customer records as a side effect of being filled in. Idempotent -- a contact already on the list is skipped. At most 10,000 per request.



## OpenAPI

````yaml /api-reference/openapi-public.json post /campaigns/{id}/contacts
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:
  /campaigns/{id}/contacts:
    post:
      tags:
        - Campaigns
      summary: Load contacts into a campaign
      description: >-
        Takes contact ids, not numbers: a campaign must not conjure customer
        records as a side effect of being filled in. Idempotent -- a contact
        already on the list is skipped. At most 10,000 per request.
      operationId: postCampaignsIdContacts
      parameters:
        - $ref: '#/components/parameters/idempotencyKey'
        - in: path
          name: id
          required: true
          schema:
            format: uuid
            type: string
      requestBody:
        content:
          application/json:
            schema:
              description: Send one of items, contact_ids or segment_id.
              properties:
                contact_ids:
                  items:
                    format: uuid
                    type: string
                  maxItems: 10000
                  type: array
                items:
                  description: >-
                    People one by one, each with your reference and variables. A
                    number with no contact creates one (contact.created).
                    variables are the call's own ({{name}} in the message or
                    workflow, and an AI agent's brief) and come back with the
                    result.
                  items:
                    properties:
                      contact_id:
                        format: uuid
                        type: string
                      e164:
                        type: string
                      name:
                        type: string
                      reference:
                        maxLength: 128
                        type: string
                      variables:
                        additionalProperties:
                          type: string
                        maxProperties: 30
                        type: object
                    type: object
                  maxItems: 10000
                  type: array
                segment_id:
                  description: >-
                    Load everyone in this segment. A COPY, not a reference: the
                    campaign's list is a state machine recording whether each
                    person has been dialled, so a list that read a segment live
                    would change under a running campaign and could re-offer
                    somebody already called. There is no size limit on this
                    form, because the work happens in the database.
                  format: uuid
                  type: string
              type: object
        required: true
      responses:
        '200':
          content:
            application/json:
              schema:
                properties:
                  added:
                    type: integer
                  offered:
                    description: How many ids were sent. Zero when loading from a segment.
                    type: integer
                  suppressed:
                    description: >-
                      How many on the list will never be dialled -- do-not-call
                      or blacklisted. Reported here rather than left to be found
                      on the call sheet: it is the difference between the list
                      somebody chose and the calls that will happen.
                    type: integer
                type: object
          description: OK
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
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.
    Unauthorized:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
      description: Missing, invalid or expired token
    Forbidden:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
      description: Outside the caller's scope, or insufficient role
    NotFound:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
      description: Not found, or not visible to the caller
  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

````