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

# List TFU Live agent history

> Lists this TFU Live agent’s saves, newest first, a page at a time. Each says who saved, when and what changed, with the change itself. Use it to choose a revision for `POST /api/tfu-live-agents/{id}/restore`. The last 200 saves are kept.

Required scope: `agents:read`.

Required API key scope: `agents:read`.



## OpenAPI

````yaml /openapi.yaml get /api/tfu-live-agents/{id}/history
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": "<code>", "message": "..." }` on failure. Branch on the `error`
    code; `message` is for people and its wording can change.


    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: Caller ID
    description: >-
      Register the businesses behind your calling numbers with Twilio, so
      carriers know who is calling and label the calls less often as spam. Read
      where every number stands, then register one business per call, naming the
      person who confirmed its details.
  - 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: >-
      Configure instructions, conversation style, workflows, Chat and call
      handling, then test and go live.
  - name: Voices
    description: >-
      Browse the voice catalogue and select a voice; configure speech and
      listening behavior in Agents.
paths:
  /api/tfu-live-agents/{id}/history:
    get:
      tags:
        - TFU Live
      summary: List TFU Live agent history
      description: >-
        Lists this TFU Live agent’s saves, newest first, a page at a time. Each
        says who saved, when and what changed, with the change itself. Use it to
        choose a revision for `POST /api/tfu-live-agents/{id}/restore`. The last
        200 saves are kept.


        Required scope: `agents:read`.


        Required API key scope: `agents:read`.
      operationId: get-tfu-live-agents-by-id-history
      parameters:
        - name: locationId
          in: query
          required: true
          schema:
            type: string
          description: >-
            The sub-account. It must belong to the agency, and be the
            credential’s own sub-account when the credential is limited to one.
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: >-
            The TFU Live agent id, with its tfu_live: prefix, as `GET
            /api/tfu-live-agents` returns it. Other agent ids are refused.
        - name: page
          in: query
          schema:
            type: integer
            minimum: 1
            default: 1
          description: The page to read, from 1.
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 50
            default: 10
          description: >-
            Saves per page. A save that changed a long prompt can be large, so
            ask for fewer when a page is too big.
      responses:
        '200':
          description: >-
            Successful TFU Live response. Setup acceptance is not verified
            readiness or campaign activation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TfuLiveAgentHistoryResponse'
              example:
                success: true
                data:
                  history:
                    - revision: 2
                      definitionHash: 3f2b9c0d1e
                      savedAt: '2026-09-20T10:15:00.000Z'
                      actor: user
                      restorable: true
                      changes:
                        - 'Voice instructions: 1 line added, 1 line removed.'
                      details:
                        - field: voice
                          added:
                            - >-
                              Speak at a calm pace and pronounce addresses
                              clearly.
                          removed:
                            - Speak calmly.
                    - revision: 1
                      definitionHash: 9a4d7e2c6b
                      savedAt: '2026-09-19T16:02:00.000Z'
                      actor: user
                      restorable: true
                      changes:
                        - 'Brain: 4 lines added.'
                  pagination:
                    page: 1
                    limit: 10
                    total: 2
                    totalPages: 1
        '400':
          description: >-
            TFU Live refused the request: { success: false, error, message,
            code, workflowId?, stepId?, field?, setupItems? }. Branch on error
            (code holds the same value), show message to people, and read the
            current agent before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TfuLiveError'
              example:
                success: false
                error: invalid_request
                message: Some details are missing. Please fill them in and try again.
                code: invalid_request
        '401':
          description: >-
            TFU Live refused the request: { success: false, error, message,
            code, workflowId?, stepId?, field?, setupItems? }. Branch on error
            (code holds the same value), show message to people, and read the
            current agent before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TfuLiveError'
              example:
                success: false
                error: Unauthorized
                message: Please sign in to continue.
        '403':
          description: >-
            TFU Live refused the request: { success: false, error, message,
            code, workflowId?, stepId?, field?, setupItems? }. Branch on error
            (code holds the same value), show message to people, and read the
            current agent before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TfuLiveError'
              example:
                success: false
                error: InsufficientScope
                message: >-
                  This access key does not allow this action. Please ask your
                  account admin to change its permissions.
                requiredScope: agents:write
        '404':
          description: >-
            TFU Live refused the request: { success: false, error, message,
            code, workflowId?, stepId?, field?, setupItems? }. Branch on error
            (code holds the same value), show message to people, and read the
            current agent before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TfuLiveError'
              example:
                success: false
                error: not_found
                message: >-
                  We couldn't find that agent. Please refresh and choose
                  another.
                code: not_found
        '409':
          description: >-
            TFU Live refused the request: { success: false, error, message,
            code, workflowId?, stepId?, field?, setupItems? }. Branch on error
            (code holds the same value), show message to people, and read the
            current agent before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TfuLiveError'
              example:
                success: false
                error: conflict
                message: >-
                  This changed while you were working on it. Please refresh and
                  try again.
                code: conflict
        '422':
          description: >-
            TFU Live refused the request: { success: false, error, message,
            code, workflowId?, stepId?, field?, setupItems? }. Branch on error
            (code holds the same value), show message to people, and read the
            current agent before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TfuLiveError'
              examples:
                invalid_workflow:
                  value:
                    success: false
                    error: invalid_workflow
                    message: Please check the steps in this workflow and try again.
                    code: invalid_workflow
                    workflowId: wf_account1
                    stepId: check
                workflow_resource_not_found:
                  value:
                    success: false
                    error: workflow_resource_not_found
                    message: >-
                      Something this workflow step uses could not be found.
                      Please choose it again.
                    code: workflow_resource_not_found
                    workflowId: wf_book0001
                    stepId: slots
                    field: routing[1].calendarId
                workflow_secret_refused:
                  value:
                    success: false
                    error: workflow_secret_refused
                    message: >-
                      Please save the private connection details in this
                      workflow step again.
                    code: workflow_secret_refused
                    workflowId: wf_account1
                    stepId: lookup
                    field: headers.Authorization
                invalid_agent:
                  value:
                    success: false
                    error: invalid_agent
                    message: Please check the agent settings and try again.
                    code: invalid_agent
                setup_incomplete:
                  value:
                    success: false
                    error: setup_incomplete
                    message: >-
                      Some settings are missing. Please finish the highlighted
                      steps.
                    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 refused the request: { success: false, error, message,
            code, workflowId?, stepId?, field?, setupItems? }. Branch on error
            (code holds the same value), show message to people, and read the
            current agent before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TfuLiveError'
              example:
                success: false
                error: TooManyRequests
                message: That's a lot at once. Please wait a moment and try again.
        '502':
          description: >-
            TFU Live refused the request: { success: false, error, message,
            code, workflowId?, stepId?, field?, setupItems? }. Branch on error
            (code holds the same value), show message to people, and read the
            current agent before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TfuLiveError'
              example:
                success: false
                error: provider_unavailable
                message: This isn't available right now. Please try again in a moment.
                code: provider_unavailable
                ref: 3f2b8c1e-7d4a-4f8e-9b6a-2c1d0e5f7a9b
        '503':
          description: >-
            TFU Live refused the request: { success: false, error, message,
            code, workflowId?, stepId?, field?, setupItems? }. Branch on error
            (code holds the same value), show message to people, and read the
            current agent before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TfuLiveError'
              example:
                success: false
                error: TFU_LIVE_CAMPAIGN_PENDING
                message: >-
                  Your agent draft was saved. Please try creating it again to
                  finish attaching its campaign.
                code: TFU_LIVE_CAMPAIGN_PENDING
                ref: 3f2b8c1e-7d4a-4f8e-9b6a-2c1d0e5f7a9b
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |-
            curl --request GET \
              --url https://api.teamfollowup.ai/api/tfu-live-agents/{id}/history \
              --header 'Authorization: Bearer YOUR_API_KEY'
components:
  schemas:
    TfuLiveAgentHistoryResponse:
      type: object
      required:
        - success
        - data
      properties:
        success:
          const: true
        data:
          type: object
          required:
            - history
            - pagination
          additionalProperties: false
          properties:
            history:
              type: array
              items:
                $ref: '#/components/schemas/TfuLiveHistoryEntry'
              description: This page of saves, newest first.
            pagination:
              type: object
              required:
                - page
                - limit
                - total
                - totalPages
              additionalProperties: false
              properties:
                page:
                  type: integer
                  minimum: 1
                limit:
                  type: integer
                  minimum: 1
                  maximum: 50
                total:
                  type: integer
                  minimum: 0
                  description: Every save kept, on all pages.
                totalPages:
                  type: integer
                  minimum: 0
      additionalProperties: false
    TfuLiveError:
      type: object
      description: >-
        A TFU Live refusal: the standard error envelope, plus where a workflow
        refusal points and what setup still needs.
      required:
        - success
        - error
        - message
      properties:
        success:
          type: boolean
          example: false
        error:
          type: string
          description: >-
            The refusal’s code, the same value as code. A shared gate
            (authentication, scope, rate limit) answers with its own code, such
            as Unauthorized, InsufficientScope or TooManyRequests, and sends no
            code.
        message:
          type: string
          description: >-
            One plain sentence for a person: what happened and what to do next.
            Show it, never parse it: the wording can change, and browser users
            get it in their own language. API keys and OAuth apps always get
            English.
          example: We couldn't find that. It may have been moved or deleted.
        errors:
          type: array
          description: >-
            Sent when specific fields were refused: one entry for each field to
            fix.
          items:
            type: object
            additionalProperties: false
            required:
              - field
              - code
              - message
            properties:
              field:
                type: string
                description: Where the value sits in the request, as a dotted path.
                example: name
              code:
                type: string
                description: A stable code for what is wrong with the value.
                example: FieldRequired
              message:
                type: string
                description: One plain sentence for a person.
                example: Please fill this in.
        details:
          type: object
          additionalProperties: {}
          description: >-
            Data your code may need to act on the failure, such as ids or
            limits. Never text for people.
        ref:
          type: string
          description: >-
            Sent only when the failure was on our side. Quote it to support so
            they can find the request. It matches the `x-request-id` response
            header.
          example: 3f2b8c1e-7d4a-4f8e-9b6a-2c1d0e5f7a9b
        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
            - TFU_LIVE_CAMPAIGN_REFUSED
            - TFU_LIVE_ALREADY_ON_GOHIGHLEVEL
            - TFU_LIVE_CONNECTION_NOT_CONFIGURED
            - TFU_LIVE_GO_LIVE_BLOCKED
            - TFU_LIVE_CALLS_SCHEDULED
            - TFU_LIVE_PLAN_CHANGED
            - TFU_LIVE_PLAN_ANSWER_INVALID
            - TFU_LIVE_PLAN_ANSWER_REQUIRED
            - TFU_LIVE_CLONE_RESOURCES_UNAVAILABLE
            - TFU_LIVE_MOVE_RESOURCES_UNAVAILABLE
            - TFU_LIVE_OPERATION_IN_PROGRESS
            - TFU_LIVE_MASTER_PARENT_REFUSED
            - TFU_LIVE_MASTER_CHILD_REFUSED
            - TFU_LIVE_CLONE_UNSUPPORTED
            - TFU_LIVE_MOVE_CHANGED
            - TFU_LIVE_MOVE_CRM_UNSUPPORTED
            - TFU_LIVE_MOVE_DEFINITION_INVALID
            - TFU_LIVE_MOVE_CHANGES_TOO_MUCH
            - TFU_LIVE_MOVE_BRAIN_SYNC_PENDING
          description: >-
            The same code as error, kept for integrations built before error
            carried it. The kind of refusal: invalid_workflow (a workflow’s
            structure or a node’s settings, including a workflow whose calendars
            are on more than one system), 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 about it, for a person.
          description: >-
            On setup_incomplete: everything the agent still needs, the first of
            which the refusal names.
        blockers:
          type: array
          items:
            type: object
            required:
              - code
              - who
              - message
            additionalProperties: false
            description: One thing that stops the agent’s campaign from taking real calls.
            properties:
              code:
                type: string
                description: >-
                  What it is, such as no_caller_id, no_trigger_tag,
                  not_prepared, calling_line_not_ready, needs_gohighlevel or
                  card_required.
              who:
                type: string
                enum:
                  - rep
                  - operator
                  - staff
                description: >-
                  Who clears it. rep: a setting of the agent’s own (its number,
                  its trigger, its setup). operator: the person (approve
                  GoHighLevel, add a card, upgrade the plan). staff: Team Follow
                  Up.
              message:
                type: string
                description: >-
                  What to do about it. An API key or OAuth client gets the
                  go-live check’s own words.
              page:
                type: string
                description: >-
                  Where a person does it in the dashboard, when there is a page
                  for it.
              place:
                type: object
                additionalProperties: false
                required:
                  - workflowId
                  - stepId
                description: The workflow step it is about, when it is about one.
                properties:
                  workflowId:
                    type: string
                  stepId:
                    type: string
          description: >-
            On TFU_LIVE_GO_LIVE_BLOCKED: everything standing between the agent’s
            campaign and real calls, as `GET
            /api/tfu-live-agents/{id}/go-live-check` lists it. The campaign
            stayed paused.
        scheduledCalls:
          type: integer
          minimum: 1
          description: >-
            On TFU_LIVE_CALLS_SCHEDULED (409): how many leads of the agent’s
            live campaign have a call still to come (a cadence call, an AI
            callback, a promised callback). An agent with calls off makes none
            of them. Nothing was saved; send the same edit with
            confirmScheduledCallsLost: true to turn calls off anyway.
        inputs:
          type: array
          items:
            type: string
          description: >-
            On TFU_LIVE_PLAN_ANSWER_INVALID and TFU_LIVE_PLAN_ANSWER_REQUIRED
            (422): the ids of the plan’s inputs whose answer is wrong or
            missing. It can be empty when the answers fail together, such as
            answers that leave a cadence with no steps.
        kinds:
          type: array
          items:
            type: string
          description: >-
            On TFU_LIVE_CLONE_RESOURCES_UNAVAILABLE and
            TFU_LIVE_MOVE_RESOURCES_UNAVAILABLE (503): the new sub-account’s
            lists that could not be read, such as calendar, field or tag. Absent
            when the cadences could not be read. Nothing was written. Try again.
      additionalProperties: {}
    TfuLiveHistoryEntry:
      type: object
      required:
        - revision
        - definitionHash
        - savedAt
        - changes
      additionalProperties: {}
      properties:
        revision:
          type: integer
          minimum: 1
          description: >-
            The revision this save made. Send it to `POST
            /api/tfu-live-agents/{id}/restore` to bring it back.
        definitionHash:
          type: string
          description: The version this save made, as ifVersion names a version.
        savedAt:
          type: string
          format: date-time
        actor:
          type: string
          description: >-
            Who made the save: user (a person), assistant (the agent editing
            itself in the builder conversation), system (the platform, such as a
            move to another sub-account) or split_sync (copied from its split
            test).
        restoredFrom:
          type: integer
          minimum: 1
          description: 'On a restore: the revision it brought back.'
        restorable:
          type: boolean
          description: >-
            Whether the text of this revision is kept, so a restore can bring it
            back.
        changes:
          type: array
          items:
            type: string
          description: What changed, in a few words per change.
        details:
          type: array
          items:
            type: object
            required:
              - field
            properties:
              field:
                type: string
            additionalProperties: {}
          description: >-
            The change itself, field by field: the lines added and removed, or a
            setting before and after.
  securitySchemes:
    ApiKeyAuth:
      type: http
      scheme: bearer
      bearerFormat: API key
      description: 'Send your API key as `Authorization: Bearer YOUR_API_KEY`.'

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.