> ## 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 split test

> Read the Agent Split Test on the live campaign bound to this Primary Variant. Answers 404 when the agent has no live campaign, or when that campaign has never been converted to a split test.

Required API key scope: `agents:read`.



## OpenAPI

````yaml /openapi.yaml get /api/agent-builder/agents/{id}/split-test
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/agent-builder/agents/{id}/split-test:
    get:
      tags:
        - Agents
      summary: Get split test
      description: >-
        Read the Agent Split Test on the live campaign bound to this Primary
        Variant. Answers 404 when the agent has no live campaign, or when that
        campaign has never been converted to a split test.


        Required API key scope: `agents:read`.
      operationId: get-agent-split-test
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            minLength: 1
          description: >-
            Agent id of the Primary Variant. Every split operation is addressed
            through the primary, not through a secondary variant.
          example: agent_8a488fcfa8fdbf8ce8ad5ccc45
      responses:
        '200':
          description: The current split.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SplitTestResponse'
              examples:
                default:
                  value:
                    success: true
                    splitTest:
                      locationId: loc_9f7a123
                      campaignId: campaign_speed_to_lead_123
                      primaryAgentId: agent_8a488fcfa8fdbf8ce8ad5ccc45
                      status: active
                      revision: 4
                      sync:
                        status: healthy
                        failedAt: null
                      variants:
                        - agentId: agent_8a488fcfa8fdbf8ce8ad5ccc45
                          name: Speed to Lead
                          sequence: 1
                          weight: 50
                          status: active
                          addedAt: '2026-08-14T09:12:44.318Z'
                          removedAt: null
                          isPrimary: true
                        - agentId: agent_7c4e1b28f0a94d6591cc2fd340
                          name: Speed to Lead II
                          sequence: 2
                          weight: 50
                          status: active
                          addedAt: '2026-08-20T16:04:02.771Z'
                          removedAt: null
                          isPrimary: false
        '400':
          description: Validation failed or the request is malformed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SplitTestErrorResponse'
              examples:
                default:
                  value:
                    success: false
                    error: VALIDATION
                    message: Weights must include every active variant exactly once.
        '401':
          description: Missing or invalid authentication.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SplitTestErrorResponse'
              examples:
                default:
                  value:
                    success: false
                    error: Unauthorized
                    message: Authentication required.
        '403':
          description: >-
            Authenticated but missing the required scope or access to this
            agent.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SplitTestErrorResponse'
              examples:
                default:
                  value:
                    success: false
                    error: AccessDenied
                    message: You do not have access to this agent.
        '404':
          description: >-
            No agent, no live campaign bound to it, or no Agent Split Test on
            that campaign.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SplitTestErrorResponse'
              examples:
                default:
                  value:
                    success: false
                    error: NOT_FOUND
                    message: This campaign does not have an Agent Split Test.
        '429':
          description: Rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SplitTestErrorResponse'
              examples:
                default:
                  value:
                    success: false
                    error: TooManyRequests
                    message: Too many requests, please try again later.
        '500':
          description: Unexpected server error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SplitTestErrorResponse'
              examples:
                default:
                  value:
                    success: false
                    error: InternalError
                    message: Unexpected server error.
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |-
            curl --request GET \
              --url https://api.teamfollowup.ai/api/agent-builder/agents/{id}/split-test \
              --header 'Authorization: Bearer YOUR_API_KEY'
components:
  schemas:
    SplitTestResponse:
      type: object
      additionalProperties: false
      required:
        - success
        - splitTest
      properties:
        success:
          type: boolean
        splitTest:
          $ref: '#/components/schemas/SplitTest'
    SplitTestErrorResponse:
      type: object
      additionalProperties: {}
      required:
        - success
        - error
        - message
      properties:
        success:
          type: boolean
        error:
          type: string
          description: >-
            Machine-readable error code. `VALIDATION`, `NOT_FOUND`, `CONFLICT`
            and `SYNC_FAILED` (502: the agent behind a variant could not be
            renamed, and nothing was committed) are the ones this module raises.
          example: CONFLICT
        message:
          type: string
          description: Human-readable explanation safe to show to an operator.
          example: Agent Split Test changed since it was loaded. Refresh and retry.
    SplitTest:
      type: object
      additionalProperties: false
      required:
        - locationId
        - campaignId
        - primaryAgentId
        - status
        - revision
        - variants
      properties:
        locationId:
          type: string
          description: Project the campaign belongs to.
          example: loc_9f7a123
        campaignId:
          type: string
          description: Campaign whose traffic is being split.
          example: campaign_speed_to_lead_123
        primaryAgentId:
          type: string
          description: >-
            Agent id of the Primary Variant, and the id every split operation is
            addressed through.
          example: agent_8a488fcfa8fdbf8ce8ad5ccc45
        status:
          type: string
          enum:
            - active
            - ended
          description: >-
            A split ends automatically when removal leaves one variant, which
            then takes all the traffic.
          example: active
        revision:
          type: integer
          minimum: 1
          description: >-
            Increments on every change. Send the value you read back on any
            mutation; a mismatch answers 409 rather than overwriting somebody
            else's edit.
          example: 4
        sync:
          $ref: '#/components/schemas/SplitTestSync'
        variants:
          type: array
          description: >-
            Every variant, in stable sequence order: the live ones, the ones
            excluded from the cycle (`splitDraft: true`), and the removed ones.
          items:
            $ref: '#/components/schemas/SplitTestVariant'
    SplitTestSync:
      type: object
      additionalProperties: {}
      required:
        - status
      description: >-
        Whether the split is in step with the external voice platform. `error`
        means a shared-field update could not be rolled back and traffic has
        been forced to the Primary Variant.
      properties:
        status:
          type: string
          enum:
            - healthy
            - error
          example: healthy
        failedAt:
          type:
            - string
            - 'null'
          format: date-time
          description: When the sync failure was recorded. Null while healthy.
          example: null
        lastError:
          type:
            - object
            - 'null'
          additionalProperties: {}
          description: >-
            Diagnostic detail for the failure. Shape is not contractual and is
            present only after a failure.
    SplitTestVariant:
      type: object
      additionalProperties: false
      required:
        - agentId
        - name
        - sequence
        - weight
        - status
        - isPrimary
      description: >-
        One arm of the split. The Primary Variant is the agent the campaign is
        bound to; the others are clones created by this API.
      properties:
        agentId:
          type: string
          description: >-
            Agent id for this variant. Use it with the ordinary agent endpoints
            to read or edit the variant itself.
          example: agent_7c4e1b28f0a94d6591cc2fd340
        name:
          type: string
          description: >-
            Display name. By default a secondary variant is named after the
            primary with a Roman numeral suffix and follows a primary rename. A
            name chosen through `PATCH /split-test/variants/{variantAgentId}`
            stays until it is reset; automatic synchronization updates only the
            names still on the convention.
          example: Speed to Lead II
        customName:
          type: boolean
          description: >-
            Present and true when an operator chose this name. The convention
            leaves it alone; reset it with `PATCH
            /split-test/variants/{variantAgentId}` and `name: null`. Never set
            on the Primary Variant, whose name is the agent's own.
          example: false
        sequence:
          type: integer
          minimum: 1
          description: >-
            Stable position used to derive the canonical name. Never reused, so
            a removed variant does not free its numeral.
          example: 2
        weight:
          type: integer
          minimum: 0
          maximum: 100
          description: >-
            Share of campaign traffic, as a percentage. Weights across the live
            variants total 100. A variant excluded from the cycle (`splitDraft:
            true`) is 0, and so is a removed one.
          example: 50
        splitDraft:
          type: boolean
          description: >-
            Present and true when this variant has been excluded from the split
            cycle. It stays a full member (shared post-call fields and
            campaign-owned tools still reach it, it can still be renamed, and a
            test call can still be sent to it) but it takes no calls and holds a
            `weight` of 0. Leads it was already speaking to are not lost: while
            it is excluded, each of their calls goes to one live variant, the
            same one every call, and nothing about the lead is rewritten, so
            including the variant again hands those leads straight back. Those
            covering calls do not count in the covering variant's own numbers.
            Absent means the variant is live. Never set on the Primary Variant,
            which is the fallback for every route and always takes traffic.
          example: false
        status:
          type: string
          enum:
            - active
            - removed
          description: >-
            Membership, not traffic: an excluded variant is still `active` and
            carries `splitDraft: true`. Removed variants stay in the list so
            historical call attribution keeps resolving.
          example: active
        addedAt:
          type:
            - string
            - 'null'
          format: date-time
          example: '2026-08-20T16:04:02.771Z'
        removedAt:
          type:
            - string
            - 'null'
          format: date-time
          description: Set when the variant was removed, null while active.
          example: null
        isPrimary:
          type: boolean
          description: >-
            True for the campaign's bound agent. The Primary Variant cannot be
            removed.
          example: false
  securitySchemes:
    ApiKeyAuth:
      type: http
      scheme: bearer
      bearerFormat: API key
      description: 'Send your API key as `Authorization: Bearer YOUR_API_KEY`.'

````