> ## 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 free slots

> What this calendar can actually offer, day by day.

Each day holds the ISO start times that are open, in the order they run. The shape matches what the GoHighLevel path returns, so the same code reads either.

**Computed per request against live bookings, and never cached.** A cached slot is one somebody else has already taken, and the whole point of this read is that it was true a moment ago. Nothing here is served from an edge cache or answered from an `ETag`.

The times come back in the calendar's own zone unless you pass `timezone`. `lookaheadDays` and `minNoticeMinutes` override the calendar's settings for this read alone, which is how you preview the effect of loosening either.

An empty answer is a real answer: the hours, the notice, and what is already booked can genuinely leave nothing.

Required API key scope: `projects:read`.



## OpenAPI

````yaml /openapi.yaml get /api/native-calendar/calendars/{calendarId}/free-slots
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: Manage voice agents, campaigns, workflows, and outcomes.
  - name: Analytics
    description: >-
      Minimal, non-billing performance summary: volume, conversion, and pickup
      metrics.
  - name: Billing
    description: >-
      Billing for your own agency: balance, spend, transaction history, invoices
      and sub-account wallets; auto-recharge, rebilling, Credit Guard and Stripe
      customers; and, with the billing:charge scope, purchases and charges.
  - name: Calls
    description: Review calls, test runs, and execution history.
  - name: Campaign Workflows
    description: >-
      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/digest` | 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: Contact list, filters, contact call history, and do-not-call actions.
  - name: GHL
    description: CRM variables and contact helpers used by agent and campaign setup flows.
  - 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: >-
      Caller ID pool, number search, assignment, movement, and release
      endpoints.
  - name: Power Dialer
    description: >-
      Power Dialer queue, lead cadence, callback, parked lead, and campaign
      schedule endpoints.
  - name: Projects
    description: >-
      Project management endpoints: list, update, disconnect, configure project
      campaigns, and validate setup.
  - name: Skills and Tools
    description: Manage reusable agent behaviors and in-call tool descriptions.
  - name: Split Testing
    description: >-
      Split live campaign traffic across agent variants and shift the weights
      between them.
  - name: Voices
    description: Voice catalogue endpoints for choosing the voice used by an agent.
paths:
  /api/native-calendar/calendars/{calendarId}/free-slots:
    get:
      tags:
        - Native Calendar
      summary: Get free slots
      description: >-
        What this calendar can actually offer, day by day.


        Each day holds the ISO start times that are open, in the order they run.
        The shape matches what the GoHighLevel path returns, so the same code
        reads either.


        **Computed per request against live bookings, and never cached.** A
        cached slot is one somebody else has already taken, and the whole point
        of this read is that it was true a moment ago. Nothing here is served
        from an edge cache or answered from an `ETag`.


        The times come back in the calendar's own zone unless you pass
        `timezone`. `lookaheadDays` and `minNoticeMinutes` override the
        calendar's settings for this read alone, which is how you preview the
        effect of loosening either.


        An empty answer is a real answer: the hours, the notice, and what is
        already booked can genuinely leave nothing.


        Required API key scope: `projects:read`.
      operationId: get-native-calendar-free-slots
      parameters:
        - name: calendarId
          in: path
          required: true
          schema:
            type: string
            minLength: 1
          description: The calendar id.
          example: cal_6b1f2a7c90
        - name: locationId
          in: query
          required: true
          schema:
            type: string
          description: >-
            The sub-account this calendar belongs to. It is the only thing that
            identifies the tenant here, and access is re-checked against it on
            every call.
          example: nat_fd9e2a8dd4be4396b604
        - name: timezone
          in: query
          required: false
          schema:
            type: string
          description: Read the slots in this zone instead of the calendar's own.
          example: America/New_York
        - name: lookaheadDays
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 365
          description: How far ahead to look, overriding `maxDaysOut`.
          example: 14
        - name: minNoticeMinutes
          in: query
          required: false
          schema:
            type: integer
            minimum: 0
          description: How soon the first slot may be, overriding the calendar.
          example: 60
      responses:
        '200':
          description: Open start times, keyed by day.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NativeCalendarSlotsResponse'
              examples:
                default:
                  value:
                    success: true
                    data:
                      timezone: America/Chicago
                      slots:
                        '2026-09-24':
                          slots:
                            - '2026-09-24T14:00:00.000Z'
                            - '2026-09-24T14:30:00.000Z'
                            - '2026-09-24T15:00:00.000Z'
                        '2026-09-25':
                          slots:
                            - '2026-09-25T14:00:00.000Z'
        '400':
          description: >-
            The request is malformed, or the calendar definition is invalid.
            `errors` carries every reason, not only the first.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NativeCalendarErrorResponse'
              examples:
                default:
                  value:
                    success: false
                    error: timezone is required
        '401':
          description: Missing or invalid authentication.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NativeCalendarErrorResponse'
              examples:
                default:
                  value:
                    success: false
                    error: Unauthorized
        '403':
          description: >-
            Authenticated, but without access to this sub-account or this
            calendar.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NativeCalendarErrorResponse'
              examples:
                default:
                  value:
                    success: false
                    error: calendar does not belong to this project
        '404':
          description: No such calendar or appointment in this sub-account.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NativeCalendarErrorResponse'
              examples:
                default:
                  value:
                    success: false
                    error: calendar not found
        '429':
          description: Rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NativeCalendarErrorResponse'
              examples:
                default:
                  value:
                    success: false
                    error: TooManyRequests
        '500':
          description: Unexpected server error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NativeCalendarErrorResponse'
              examples:
                default:
                  value:
                    success: false
                    error: Calendar request failed.
        '503':
          description: The calendar service is unreachable or not configured.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NativeCalendarErrorResponse'
              examples:
                default:
                  value:
                    success: false
                    error: Calendar service is unreachable.
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |-
            curl --request GET \
              --url https://api.teamfollowup.ai/api/native-calendar/calendars/{calendarId}/free-slots \
              --header 'Authorization: Bearer YOUR_API_KEY'
components:
  schemas:
    NativeCalendarSlotsResponse:
      type: object
      additionalProperties: {}
      required:
        - success
        - data
      properties:
        success:
          type: boolean
        data:
          type: object
          additionalProperties: {}
          properties:
            timezone:
              type: string
              description: The zone the start times are read in.
              example: America/Chicago
            slots:
              type: object
              description: >-
                Keyed by `YYYY-MM-DD`, each `{ slots: [ISO start time, ...] }`.
                The same shape the GoHighLevel path returns.
              additionalProperties:
                type: object
                additionalProperties: {}
                properties:
                  slots:
                    type: array
                    items:
                      type: string
    NativeCalendarErrorResponse:
      type: object
      additionalProperties: {}
      required:
        - success
        - error
      properties:
        success:
          type: boolean
        error:
          type: string
          example: timezone is required
        errors:
          type: array
          items:
            type: string
          description: Every reason a calendar definition was refused, not only the first.
        upcomingCount:
          type: integer
          description: >-
            On a refused delete: how many appointments are still ahead on this
            calendar.
          example: 3
  securitySchemes:
    ApiKeyAuth:
      type: http
      scheme: bearer
      bearerFormat: API key
      description: 'Send your API key as `Authorization: Bearer YOUR_API_KEY`.'

````