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

> ## Agent Instructions
> Use the public API base URL: https://api.teamfollowup.ai/api.
> Authenticate public API requests with Authorization: Bearer YOUR_API_KEY.
> Use product-owned terms: agents, campaigns, projects (GoHighLevel sub-accounts), contacts, calls, outcomes, skills, cadences, phone numbers.
> Scope requests by locationId rather than projectName.
> Read the guide linked from each API reference group before recommending an endpoint.

# Get TFU Live catalog

> TFU Live only. Discover what an agent can be built from: the workflow model (data.workflows: every node with its settings in words and as JSON Schema, its outputs, timing and the arguments it takes, the templates and which of their settings must be filled before saving, the rules and the limits), the sub-account’s CRM (data.subAccount; the native CRM has no tags), the tool groups that stay tools, voice names and background rooms. It is not an agent’s configuration: equipped is always false here; read the agent for that. See the workflows contract guide.

Required scope: `agents:read`.

Required API key scope: `agents:read`.



## OpenAPI

````yaml /openapi.yaml get /api/tfu-live-agents/{id}/brain/catalog
openapi: 3.1.0
info:
  title: TFUAI Server API
  version: 1.0.0
  description: >-
    API reference for the TFUAI SaaS server.


    All published endpoints are mounted under `/api`. Responses use a standard
    envelope: `{ "success": true, ... }` on success and `{ "success": false,
    "error": "..." }` on failure.


    Product API modules are being launched module by module. This spec currently
    exposes only contracted public modules.


    Authenticate public API requests with an API key in the `Authorization`
    header: `Authorization: Bearer YOUR_API_KEY`.
servers:
  - url: https://api.teamfollowup.ai
    description: Production API origin. Public API paths are under /api.
security: []
tags:
  - name: Agents
    description: >-
      Build the conversation: identity and settings, script, lead context and
      split testing.
  - name: Analytics
    description: >-
      Understand call volume, pickup, booking and transfer metrics within the
      selected reporting scope.
  - name: Billing
    description: >-
      Balances, spend, purchases and sub-account rebilling. Reference and guides
      only; the builder chatbot has no billing playbook.
  - name: Calls
    description: >-
      Review completed calls, recordings, transcripts and campaign run history;
      distinguish observation from placing a new call.
  - name: Campaigns
    description: >-
      Configure what starts calls, who is eligible, calling windows, caller IDs,
      activation and the actions that follow each outcome.


      What runs after a call lands: for each outcome (booked, opted out, asked
      for a callback…), an ordered chain of actions — tag the contact, move a
      pipeline stage, send an SMS, book an appointment. Stored as a graph:
      `nodes` are the actions, `edges` say what follows what, and
      `dispositionEntries` maps each outcome to the node its chain starts at.


      **Pick the narrowest endpoint that does the job.**


      | To | Call | |

      | --- | --- | --- |

      | See what fires per outcome | `GET .../workflow?view=summary` | Reads as
      plain text, no graph walking |

      | Add steps to an outcome | `POST .../outcomes/{outcome}/nodes` | Server
      derives node ids, edge ids, handles, layout |

      | Change a message, tag or setting | `PATCH .../workflow` | Merges;
      carries no graph, so it cannot damage one |

      | Remove one step | `DELETE .../nodes/{nodeId}` | Also re-links the chain
      around it |

      | Author or replace the whole graph | `PUT .../workflow` | Replaces
      everything you send |


      `PUT` is the only one that can re-wire, position nodes, build an `if`,
      save an unconfigured draft, or copy a whole workflow — and the only one
      that can overwrite a change someone else made after you read it. Use it
      when you are genuinely authoring the graph, and send `expectedVersion`
      when you do. For everything else the narrower endpoints are both easier
      and safer.
  - name: Contacts
    description: >-
      Find contacts and their calls, manage do-not-call status and identify
      internal contacts excluded from reporting.
  - name: In-call Capabilities
    description: >-
      Configure actions and instructions the agent uses during a live call:
      booking, transfers, lookups and custom skills.
  - name: Master agent
    description: >-
      Run a shared agent and campaign across linked projects; manage
      inheritance, local bindings, synchronization and rollout readiness.
  - name: Native Calendar
    description: >-
      The diary of a sub-account with no CRM: its bookable calendars, the free
      slots they offer, and the appointments on them. Availability is computed
      per request against live bookings and is never cached, because a cached
      slot is one somebody else has already taken.
  - name: Native Contacts
    description: >-
      The people a sub-account with no CRM calls, and the fields it keeps on
      them. This is the system of record for those contacts: there is nowhere
      else they exist. A sub-account with a CRM keeps its contacts there and
      every operation here answers 400 for it.
  - name: Phone Numbers
    description: >-
      Find and manage caller IDs, assign numbers to campaigns and understand
      connected Twilio numbers.
  - name: Projects
    description: >-
      Understand project ownership, inspect configuration and validate the local
      resources used by a campaign.
  - name: TFU Live
    description: >-
      Build one TFU Live agent with its Brain, Voice and equipped actions;
      connect it through shared Campaigns.
  - name: Voices
    description: >-
      Browse the voice catalogue and select a voice; configure speech and
      listening behavior in Agents.
paths:
  /api/tfu-live-agents/{id}/brain/catalog:
    get:
      tags:
        - TFU Live
      summary: Get TFU Live catalog
      description: >-
        TFU Live only. Discover what an agent can be built from: the workflow
        model (data.workflows: every node with its settings in words and as JSON
        Schema, its outputs, timing and the arguments it takes, the templates
        and which of their settings must be filled before saving, the rules and
        the limits), the sub-account’s CRM (data.subAccount; the native CRM has
        no tags), the tool groups that stay tools, voice names and background
        rooms. It is not an agent’s configuration: equipped is always false
        here; read the agent for that. See the workflows contract guide.


        Required scope: `agents:read`.


        Required API key scope: `agents:read`.
      operationId: get-tfu-live-agents-by-id-brain-catalog
      parameters:
        - name: locationId
          in: query
          required: true
          schema:
            type: string
          description: >-
            Sub-account belonging to the authenticated agency and any narrower
            credential location binding.
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: TFU Live agent id. Never use an ordinary provider agent id.
        - name: group
          in: query
          schema:
            type: string
            enum:
              - outreach
              - conversation_history
              - skills
      responses:
        '200':
          description: >-
            Successful TFU Live response. Setup acceptance is not verified
            readiness or campaign activation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TfuLiveCatalogResponse'
              example:
                success: true
                data:
                  capabilities:
                    - id: outreach
                      name: Messages
                      purpose: >-
                        Text the lead during a conversation, now or at a time
                        they ask for. Callbacks, transfers, bookings and the
                        rest are workflows.
                      supported: true
                      equipped: false
                      partiallyEquipped: false
                  voices:
                    - marin
                    - cedar
                  rooms:
                    - id: office
                      name: Office
                  workflows:
                    configurationRoot: workflows
                    nodes:
                      - type: check_tag
                        name: Check tag
                        timing: waits
                        outputs:
                          - 'yes'
                          - 'no'
                        summary: >-
                          Checks whether the contact has one tag and continues
                          on Yes or No. The AI learns the answer (checkedTags).
                        settings:
                          tag: the tag to check
                        settingsSchema:
                          type: object
                          additionalProperties: false
                          properties:
                            tag:
                              type: string
                              minLength: 1
                              maxLength: 100
                              description: >-
                                One CRM tag, not tfu_ai_kill_switch or
                                tfu_ai_standby.
                          required:
                            - tag
                        arguments: []
                        argumentSchemas: {}
                    templates:
                      - key: check_tag
                        name: Check tag
                        description: >-
                          Use when you need to know whether the lead has this
                          tag.
                        steps:
                          - id: check
                            type: check_tag
                            config:
                              tag: ''
                            outputs:
                              'yes': []
                              'no': []
                        mustFill:
                          - step: check
                            setting: tag
                    rules:
                      - >-
                        Nothing follows Put on DND. Book appointment needs a
                        Find slots node earlier on its path.
                    limits:
                      workflows: 20
                      outputDepth: 5
                      stepsPerWorkflow: 60
                      nameLength: 60
                      descriptionLength: 3000
                      labelLength: 120
                      totalBytes: 180000
                      toolNameLength: 64
                      toolDescriptionSent: 1024
                  subAccount:
                    crm: ghl
                    nativeCrm: false
                    tagNodes: true
        '400':
          description: >-
            TFU Live request rejected: { success: false, error, code,
            workflowId?, stepId?, field?, setupItems? }. Read the error and
            current agent before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TfuLiveError'
              example:
                success: false
                error: locationId is required.
                code: invalid_request
        '401':
          description: >-
            TFU Live request rejected: { success: false, error, code,
            workflowId?, stepId?, field?, setupItems? }. Read the error and
            current agent before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TfuLiveError'
              example:
                success: false
                error: Unauthorized
                message: Access token is required. Please login
        '403':
          description: >-
            TFU Live request rejected: { success: false, error, code,
            workflowId?, stepId?, field?, setupItems? }. Read the error and
            current agent before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TfuLiveError'
              example:
                success: false
                error: InsufficientScope
                message: This API key does not have the required scope.
                requiredScope: agents:write
        '404':
          description: >-
            TFU Live request rejected: { success: false, error, code,
            workflowId?, stepId?, field?, setupItems? }. Read the error and
            current agent before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TfuLiveError'
              example:
                success: false
                error: Agent not found.
                code: not_found
        '409':
          description: >-
            TFU Live request rejected: { success: false, error, code,
            workflowId?, stepId?, field?, setupItems? }. Read the error and
            current agent before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TfuLiveError'
              example:
                success: false
                error: The agent changed. Read the current version before saving.
                code: conflict
        '422':
          description: >-
            TFU Live request rejected: { success: false, error, code,
            workflowId?, stepId?, field?, setupItems? }. Read the error and
            current agent before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TfuLiveError'
              examples:
                invalid_workflow:
                  value:
                    success: false
                    error: Choose the tag this node checks.
                    code: invalid_workflow
                    workflowId: wf_account1
                    stepId: check
                workflow_resource_not_found:
                  value:
                    success: false
                    error: Choose an active calendar verified for this sub-account.
                    code: workflow_resource_not_found
                    workflowId: wf_book0001
                    stepId: slots
                    field: routing[1].calendarId
                workflow_secret_refused:
                  value:
                    success: false
                    error: >-
                      The saved value of the Authorization header was saved for
                      https://api.example.com; this webhook now sends to
                      https://collector.example.net, so enter the value again.
                    code: workflow_secret_refused
                    workflowId: wf_account1
                    stepId: lookup
                    field: headers.Authorization
                invalid_agent:
                  value:
                    success: false
                    error: >-
                      Choose an agent id using up to 100 letters, digits,
                      underscores or hyphens.
                    code: invalid_agent
                setup_incomplete:
                  value:
                    success: false
                    error: >-
                      Fill what this agent still needs before it is set up: Book
                      appointment: Choose the calendar to search.
                    code: setup_incomplete
                    workflowId: wf_book0001
                    stepId: slots
                    field: calendarId
                    setupItems:
                      - kind: workflow_setting
                        workflowId: wf_book0001
                        workflowName: Book appointment
                        stepId: slots
                        node: find_slots
                        field: calendarId
                        message: Choose the calendar to search.
        '429':
          description: >-
            TFU Live request rejected: { success: false, error, code,
            workflowId?, stepId?, field?, setupItems? }. Read the error and
            current agent before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TfuLiveError'
              example:
                success: false
                error: TooManyRequests
                message: Too many write requests, please slow down.
        '502':
          description: >-
            TFU Live request rejected: { success: false, error, code,
            workflowId?, stepId?, field?, setupItems? }. Read the error and
            current agent before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TfuLiveError'
              example:
                success: false
                error: TFU Live request failed.
                code: provider_unavailable
        '503':
          description: >-
            TFU Live request rejected: { success: false, error, code,
            workflowId?, stepId?, field?, setupItems? }. Read the error and
            current agent before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TfuLiveError'
              example:
                success: false
                error: TFU_LIVE_CAMPAIGN_PENDING
                code: TFU_LIVE_CAMPAIGN_PENDING
                message: >-
                  The agent draft was saved. Retry creation with the same agent
                  id and original body to finish attaching its campaign.
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |-
            curl --request GET \
              --url https://api.teamfollowup.ai/api/tfu-live-agents/{id}/brain/catalog \
              --header 'Authorization: Bearer YOUR_API_KEY'
components:
  schemas:
    TfuLiveCatalogResponse:
      type: object
      required:
        - success
        - data
      properties:
        success:
          const: true
        data:
          type: object
          required:
            - capabilities
            - voices
            - rooms
            - workflows
            - subAccount
          additionalProperties: false
          properties:
            capabilities:
              type: array
              description: >-
                The tool groups that stay tools. equipped is always false here:
                the catalog is not an agent’s configuration; read the agent for
                that.
              items:
                type: object
                additionalProperties: {}
            voices:
              type: array
              items:
                type: string
              description: Voice names for voice.voiceId.
            rooms:
              type: array
              items:
                type: object
                required:
                  - id
                  - name
                properties:
                  id:
                    type: string
                  name:
                    type: string
            workflows:
              $ref: '#/components/schemas/TfuLiveWorkflowCatalogue'
            subAccount:
              type: object
              required:
                - crm
                - nativeCrm
                - tagNodes
              properties:
                crm:
                  type: string
                  description: ghl, or native for the TFU AI CRM.
                nativeCrm:
                  type: boolean
                tagNodes:
                  type: boolean
                  description: >-
                    False on the native CRM: Check tag, Add tag and Remove tag
                    are refused there.
      additionalProperties: false
    TfuLiveError:
      type: object
      required:
        - success
        - error
      properties:
        success:
          const: false
        error:
          type: string
          description: >-
            What to do about it, in words. A status-wide gate (authentication,
            scope, rate limit) may use its own error name with a message.
        code:
          type: string
          enum:
            - invalid_workflow
            - setup_incomplete
            - workflow_resource_not_found
            - workflow_resource_unavailable
            - workflow_secret_refused
            - invalid_agent
            - invalid_request
            - unauthorized
            - insufficient_balance
            - forbidden
            - not_found
            - conflict
            - too_large
            - provider_unavailable
            - internal_error
            - AGENT_OPERATION_UNSUPPORTED
            - TFU_LIVE_CAMPAIGN_PENDING
          description: >-
            The kind of refusal: invalid_workflow (a workflow’s structure or a
            node’s settings), setup_incomplete (a setting still to fill or a
            Brain template placeholder still in the prompt, where the agent must
            be complete: preparing it, or a save that sets it up; setupItems
            lists every one), workflow_resource_not_found (a calendar, custom
            field, pipeline stage, team or rep the sub-account lacks, or an
            inactive calendar), workflow_resource_unavailable (503: the
            sub-account’s resources could not be read; retry),
            workflow_secret_refused (a secret header rule), invalid_agent (any
            other part of the agent), else by status. TFU_LIVE_* names a product
            state.
        workflowId:
          type: string
          description: >-
            The workflow a workflow refusal is about. Absent on a workflow being
            created, which has no id yet.
        stepId:
          type: string
          description: The step inside it.
        field:
          type: string
          description: >-
            The setting inside the step: calendarId, routing[1].calendarId,
            items[0].field, destination.teamId, headers.Authorization;
            brain.prompt for a placeholder. On a create from a Brain template,
            the request value: values.<to-fill id>, values or brainTemplateId.
        setupItems:
          type: array
          items:
            type: object
            required:
              - kind
              - message
            additionalProperties: false
            description: >-
              Something the agent still needs before it can be prepared for real
              calls.
            properties:
              kind:
                type: string
                enum:
                  - workflow_setting
                  - prompt_placeholder
                description: >-
                  workflow_setting: a setting still to fill (a calendar, a tag,
                  who takes a transfer, zip codes, a choice’s answers, an item’s
                  label); prompt_placeholder: a Brain template [bracketed]
                  placeholder still in the prompt (legacy: templates no longer
                  hold any).
              workflowId:
                type: string
              workflowName:
                type: string
              stepId:
                type: string
              node:
                type: string
                description: The node type.
              field:
                type: string
                description: >-
                  The setting inside the step (calendarId, destination,
                  items[0].choices), or brain.prompt.
              placeholder:
                type: string
              message:
                type: string
                description: What to do, in words.
          description: >-
            On setup_incomplete: everything the agent still needs, the first of
            which the refusal names.
      additionalProperties: {}
    TfuLiveWorkflowCatalogue:
      type: object
      description: >-
        The workflow model as the runtime publishes it: every node, the
        templates, the rules and the limits.
      required:
        - configurationRoot
        - nodes
        - templates
        - rules
        - limits
      properties:
        configurationRoot:
          const: workflows
        shape:
          type: object
          additionalProperties:
            type: string
        timing:
          type: object
          additionalProperties:
            type: string
        fieldReferences:
          type: array
          items:
            type: string
        contactFields:
          type: object
          properties:
            readable:
              type: array
              items:
                type: string
            writable:
              type: array
              items:
                type: string
            custom:
              type: string
        outputLabels:
          type: object
          additionalProperties:
            type: string
        nodes:
          type: array
          items:
            $ref: '#/components/schemas/TfuLiveWorkflowNode'
        templates:
          type: array
          items:
            $ref: '#/components/schemas/TfuLiveWorkflowTemplate'
        rules:
          type: array
          items:
            type: string
        limits:
          type: object
          properties:
            workflows:
              type: integer
            outputDepth:
              type: integer
            stepsPerWorkflow:
              type: integer
            nameLength:
              type: integer
            descriptionLength:
              type: integer
            labelLength:
              type: integer
            totalBytes:
              type: integer
            toolNameLength:
              type: integer
            toolDescriptionSent:
              type: integer
        webhook:
          type: object
          additionalProperties: {}
          description: >-
            Webhook with response header rules: the credential pattern that
            forces a secret, reserved names, the secret forms and the limits.
        unavailable:
          type: boolean
          description: >-
            Present, and the rest absent, when the connected runtime publishes
            no workflow model.
    TfuLiveWorkflowNode:
      type: object
      required:
        - type
        - name
        - timing
        - outputs
        - summary
        - settings
        - settingsSchema
        - arguments
        - argumentSchemas
      additionalProperties: false
      properties:
        type:
          type: string
          enum:
            - collect_information
            - condition
            - check_tag
            - add_tag
            - remove_tag
            - set_field
            - move_stage
            - add_note
            - send_sms
            - send_email
            - send_webhook
            - notify_teammate
            - webhook_request
            - transfer
            - dnd
            - find_slots
            - book_appointment
            - cancel_appointment
            - schedule_ai_call
            - check_zip_code
            - cancel_scheduled
            - steer_agent
        name:
          type: string
        timing:
          type: string
          enum:
            - waits
            - instant
            - after
            - control
          description: >-
            waits: before the answer, part of it; instant: the call’s working
            copy at once, the CRM write follows; after: after the answer,
            durably; control: a Condition, chooses an output.
        outputs:
          type: array
          items:
            type: string
          description: Its fixed outputs; empty for a node without outputs.
        dynamicOutputs:
          type: object
          description: >-
            Condition only: one output per case, keyed by the case id, in case
            order, before otherwise.
          properties:
            from:
              type: string
            position:
              type: string
            rule:
              type: string
        summary:
          type: string
        settings:
          type: object
          additionalProperties:
            type: string
          description: Each setting in words.
        settingsSchema:
          type: object
          description: >-
            The settings as JSON Schema (2020-12): shape and limits. Rules that
            depend on the node’s place in the workflow are in rules and are
            checked on save.
        arguments:
          type: array
          items:
            type: string
          description: >-
            Tool arguments the node takes itself on a later AI call (Find slots’
            slot_id and confirmed). No Collect information item may take one of
            these names.
        argumentSchemas:
          type: object
          additionalProperties:
            type: object
    TfuLiveWorkflowTemplate:
      type: object
      required:
        - key
        - name
        - description
        - steps
        - mustFill
      additionalProperties: false
      properties:
        key:
          type: string
        name:
          type: string
        description:
          type: string
        steps:
          type: array
          items:
            $ref: '#/components/schemas/TfuLiveWorkflowStep'
        mustFill:
          type: array
          description: >-
            Settings the template leaves empty for the client’s choice. On an
            explicit draft they are setup items; preparing the agent, or a save
            that sets it up, refuses them until they are filled
            (setup_incomplete).
          items:
            type: object
            required:
              - step
              - setting
            properties:
              step:
                type: string
              setting:
                type: string
    TfuLiveWorkflowStep:
      type: object
      required:
        - id
        - type
        - config
      additionalProperties: false
      description: >-
        One node. A node with outputs ends its list: the steps after it go on
        its outputs.
      properties:
        id:
          type: string
          pattern: ^[a-z0-9_-]{1,40}$
          description: Unique in the workflow; receipts and resume use it.
        type:
          type: string
          enum:
            - collect_information
            - condition
            - check_tag
            - add_tag
            - remove_tag
            - set_field
            - move_stage
            - add_note
            - send_sms
            - send_email
            - send_webhook
            - notify_teammate
            - webhook_request
            - transfer
            - dnd
            - find_slots
            - book_appointment
            - cancel_appointment
            - schedule_ai_call
            - check_zip_code
            - cancel_scheduled
            - steer_agent
        label:
          type: string
          minLength: 1
          maxLength: 120
        config:
          type: object
          additionalProperties: {}
          description: >-
            The node’s settings: the catalog’s nodes[].settingsSchema for its
            type.
        outputs:
          type: object
          additionalProperties:
            type: array
            items:
              $ref: '#/components/schemas/TfuLiveWorkflowStep'
          description: >-
            Only on a node that has outputs: { <output>: [steps] }, the
            catalog’s nodes[].outputs (a Condition’s are its case ids, then
            otherwise).
  securitySchemes:
    ApiKeyAuth:
      type: http
      scheme: bearer
      bearerFormat: API key
      description: 'Send your API key as `Authorization: Bearer YOUR_API_KEY`.'

````