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

# Pause the AI for a contact

> Stop the AI from answering ONE person's texts so your own system — your software, or your team working through the API — can handle the conversation, then turn the AI back on with resumeSMSContactAI when you are done. The pause is per person and covers their texts to any of your numbers that an agent answers. It silences the AI, not your team: a number that routes straight to your team keeps ringing your team, and the person's texts to it reach your team as before (the event says `handledBy: direct_dial`). WHILE THE PAUSE IS ON:
* Every text the person sends is still received, recorded on its conversation and shown in Observe. The AI just does not reply.
* Each of those texts is delivered to your webhooks subscribed to `sms.message.received` (createWebhook), with `aiPaused: true` and `handledBy: api` — that is your system's cue to answer.
* Answer with sendSMSMessage (POST /sms/messages) from the number they texted. A message to a person who texted you within the last 24 hours is a reply (`kind: reply` on the receipt), so it is not held to quiet hours unless your workspace uses the strict posture. Consent, opt-outs (STOP), the send cap and the first-contact disclosure apply exactly as they do to every send.
* The pause holds until you clear it. It never expires on its own. * If the AI is already composing a reply to the person when you pause, that reply is not sent: their text is recorded and delivered to your webhooks with `handledBy: api`, like every text during the pause. The races either way are a few milliseconds wide: a reply already being sent at the instant you pause still goes out, and a text that arrives at the instant you resume can still be delivered to you as paused. CHECK THE RESPONSE'S `webhookSubscribed`. It is true when the workspace has an active webhook subscribed to `sms.message.received`. When it is false, nothing will tell your system that the person texted — their texts are still recorded and shown in Observe, but no one answers them. Create a webhook for the event (createWebhook), or re-enable a disabled or auto-disabled one (updateWebhook with `status: active`), then rely on the pause. WHAT OUTRANKS THE PAUSE. A teammate who has taken the thread over keeps it: the person's texts go to that teammate, not to your system (the event says `handledBy: seat`), and sendSMSMessage answers 409 `conversation_busy` (`seat_owns_thread`) for that person from any of your numbers, so your system never talks over a person. A conversation handed to an external agent through the Agent Bridge stays with that agent, and group texts are always handled by your team. The pause covers text messages only — calls from the number still reach your agent. MARKER. When the pause begins and the person has an open text conversation, an "AI paused" marker is added to it, so Observe shows when the AI was paused and by whom. Idempotent: pausing a contact that is already paused keeps the original `pausedAt` and `pausedBy` (who first paused it) and adds no second marker. A non-empty `note` replaces the stored note; an empty or omitted note keeps it. You may pause a number that has never texted you — the pause is in place for their first text.




## OpenAPI

````yaml /openapi.yaml put /sms/contacts/{e164}/ai-pause
openapi: 3.1.0
info:
  title: Flowyte V2 Control-Plane REST API
  version: 1.0.0
  description: >-
    The single REST API for the Flowyte platform (base path `/api/v1`).
    Authenticate every request with a secret API key — `Authorization: Bearer
    flowyte_sk_…` — and each operation lists the scope the key must hold.
    Successful responses use the `ApiResponse<T>` envelope; list responses use
    cursor-based `PaginatedResponse<T>`. Errors are RFC 9457 problem+json.
    Streaming endpoints return Server-Sent Events
    (`event:<type>\ndata:<json>\n\n`, terminating with `event: done`).
  contact:
    name: Flowyte Platform
  license:
    name: Proprietary
servers:
  - url: /api/v1
    description: Flowyte control-plane (versioned URI; additive in v1).
security:
  - apiKey: []
tags:
  - name: Agents
    description: The single user-facing entity.
  - name: Support
    description: In-app "Get help" form → support inbox email.
  - name: Skills
    description: >
      Agent capabilities / tools. A skill is ONE atomic action — typically a
      single API call the agent makes in one step (look up an order, create a
      record, send a message, transfer the call). Use a skill when the task is a
      single step. When a task needs several details gathered across turns
      BEFORE acting, build a Playbook (which gathers the inputs and then calls
      skills) — see the Playbooks tag.
  - name: Integrations
    description: Native OAuth integrations.
  - name: Knowledge
    description: RAG knowledge sources & preview.
  - name: Playbooks
    description: >
      Multi-turn conversation scripts — a node graph (gather → confirm → branch)
      the agent follows to collect several inputs IN ORDER across turns before
      acting. Build a playbook when a single skill call isn't enough because the
      agent must gather MANY details first, or run a SEQUENCE of skills, before
      it can finish (e.g. take a full service request: gather the problem,
      address, and time, confirm, THEN file it; qualify a lead; a multi-step
      intake). A playbook does NOT call an integration itself — it owns the
      conversation and holds the state across turns; the actual action is
      performed by the SKILL(s) it gathers the inputs for. So a playbook
      ORCHESTRATES skills. Rule of thumb — one API call → a Skill; "gather N
      things in order, then submit" → a Playbook that drives the conversation
      and calls the skill(s) at the end.
  - name: Variables
    description: >
      The agent-wide interaction-variable registry — DERIVED at read time from
      the agent's playbooks and skills (collect slots, skill output bindings,
      {var} placeholders) and merged with a thin annotation overlay (notes,
      declared type hints, manual declarations). Read-only observation, NEVER a
      gate: it never validates a reference and never affects authoring, publish,
      or runtime behaviour.
  - name: Guardrails
    description: Deterministic guardrail policies & caller verification.
  - name: Numbers
    description: Phone numbers / DIDs.
  - name: SMS
    description: >
      SMS Hub — A2P 10DLC self-serve registration (brand + campaign), the free
      AI compliance review, per-number SMS enablement, the consent/opt-out
      surface (suppressions, contacts, recorded consent, TCPA proof export), and
      sending a text — with pictures or short videos (MMS) — from the API.
      Sending numbers are US-only; a number must be SMS-enabled and the org's
      10DLC registration active before it can send.
  - name: Test
    description: Test, simulate, talk-token, probe.
  - name: Observe
    description: Post-call analytics, conversations, receipts, transcripts.
  - name: Billing
    description: Plans, wallet, usage, fixed phrases.
  - name: Voices
    description: Voice catalog.
  - name: ApiKeys
    description: Developer / API keys.
  - name: Webhooks
    description: Webhook endpoints & deliveries.
  - name: Records
    description: >
      Caller Context Store — pre-synced external records the agent greets a
      caller from, plus the learned object-type field registry. Fed by the
      Zapier app's Create/Update Record action and directly by this REST API;
      read at call time by the context_lookup skill (a sub-100ms local lookup,
      no Zapier round-trip).
  - name: AuditLogs
    description: API/key activity logs.
  - name: Chat
    description: Chat channel — sessions, messages, OpenAI-compatible, widget.
  - name: PublishableKeys
    description: Browser-safe, one-agent publishable keys.
  - name: Widget
    description: Embed widget config + snippet.
  - name: Uploads
    description: Multipart file uploads backing file_id params
  - name: Meta
    description: Platform metadata (language/SKU/tier capabilities).
  - name: Outbound
    description: >
      Outbound voice — contact lists (import + scrub) and campaigns (create,
      launch, pause/resume/cancel). Launch schedules one call attempt per valid
      contact; a background worker dials them. This release dials informational
      campaigns only.
  - name: Team
    description: >
      Team Members — the general "invite a teammate" surface (roster, the
      platform invitations, role changes/removals, and the domain-discovery
      join-request inbox). Distinct from the Flowyte Phone SEAT surface: a team
      invite mints NO softphone seat. Reads → team:read; mutations → team:write
      (owner/admin; staff is role-gated out). Owner-only guards protect owner
      grants/edits and the org's last owner; no self-role-change or
      self-removal.
  - name: Onboarding
    description: >
      Pre-org domain discovery — the signup-flow seam a just-signed-in user hits
      BEFORE they have a workspace, to learn "your coworkers may already be
      here" and ask to join. Engine-root, authenticated by a the platform
      session JWT that may have no active org; tenancy is derived SERVER-SIDE
      from the caller's verified email (anti-enumeration), never from input.
  - name: OAuth2
    description: >
      Flowyte's minimal OAuth2 authorization server. The Flowyte Zapier app is
      the first registered client. The authorization-code grant (confidential
      client, optional PKCE) issues org-scoped SERVICE tokens (flowyte_oat_…)
      that ride the SAME scope matrix as an sk key. The public
      authorize/token/revoke endpoints are served at the ORIGIN ROOT (NOT under
      /api/v1 — see each path's `servers` override); consent + disconnect are
      /api/v1.
paths:
  /sms/contacts/{e164}/ai-pause:
    parameters:
      - name: e164
        in: path
        required: true
        description: The contact's number in E.164 format (e.g. +14155551234).
        example: '+14155551234'
        schema:
          type: string
    put:
      tags:
        - SMS
      summary: Pause the AI for a contact
      description: >
        Stop the AI from answering ONE person's texts so your own system — your
        software, or your team working through the API — can handle the
        conversation, then turn the AI back on with resumeSMSContactAI when you
        are done. The pause is per person and covers their texts to any of your
        numbers that an agent answers. It silences the AI, not your team: a
        number that routes straight to your team keeps ringing your team, and
        the person's texts to it reach your team as before (the event says
        `handledBy: direct_dial`). WHILE THE PAUSE IS ON:

        * Every text the person sends is still received, recorded on its
        conversation and shown in Observe. The AI just does not reply.

        * Each of those texts is delivered to your webhooks subscribed to
        `sms.message.received` (createWebhook), with `aiPaused: true` and
        `handledBy: api` — that is your system's cue to answer.

        * Answer with sendSMSMessage (POST /sms/messages) from the number they
        texted. A message to a person who texted you within the last 24 hours is
        a reply (`kind: reply` on the receipt), so it is not held to quiet hours
        unless your workspace uses the strict posture. Consent, opt-outs (STOP),
        the send cap and the first-contact disclosure apply exactly as they do
        to every send.

        * The pause holds until you clear it. It never expires on its own. * If
        the AI is already composing a reply to the person when you pause, that
        reply is not sent: their text is recorded and delivered to your webhooks
        with `handledBy: api`, like every text during the pause. The races
        either way are a few milliseconds wide: a reply already being sent at
        the instant you pause still goes out, and a text that arrives at the
        instant you resume can still be delivered to you as paused. CHECK THE
        RESPONSE'S `webhookSubscribed`. It is true when the workspace has an
        active webhook subscribed to `sms.message.received`. When it is false,
        nothing will tell your system that the person texted — their texts are
        still recorded and shown in Observe, but no one answers them. Create a
        webhook for the event (createWebhook), or re-enable a disabled or
        auto-disabled one (updateWebhook with `status: active`), then rely on
        the pause. WHAT OUTRANKS THE PAUSE. A teammate who has taken the thread
        over keeps it: the person's texts go to that teammate, not to your
        system (the event says `handledBy: seat`), and sendSMSMessage answers
        409 `conversation_busy` (`seat_owns_thread`) for that person from any of
        your numbers, so your system never talks over a person. A conversation
        handed to an external agent through the Agent Bridge stays with that
        agent, and group texts are always handled by your team. The pause covers
        text messages only — calls from the number still reach your agent.
        MARKER. When the pause begins and the person has an open text
        conversation, an "AI paused" marker is added to it, so Observe shows
        when the AI was paused and by whom. Idempotent: pausing a contact that
        is already paused keeps the original `pausedAt` and `pausedBy` (who
        first paused it) and adds no second marker. A non-empty `note` replaces
        the stored note; an empty or omitted note keeps it. You may pause a
        number that has never texted you — the pause is in place for their first
        text.
      operationId: pauseSMSContactAI
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PauseSMSContactAIRequest'
            example:
              note: handled by Kiwi ops (ticket 8812)
      responses:
        '200':
          description: >-
            The AI is paused for the contact (also 200, with the original
            `pausedAt`, when it already was).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse_SMSContactAIPause'
              example:
                success: true
                data:
                  phoneNumber: '+14155551234'
                  aiPaused: true
                  pausedAt: '2026-09-24T16:30:00.000Z'
                  pausedBy: key_3f9a12
                  note: handled by Kiwi ops (ticket 8812)
                  conversationId: conv_9d2f01
                  webhookSubscribed: true
        '400':
          $ref: '#/components/responses/ValidationError'
          description: >-
            `validation_error` — the body is not valid JSON of this shape, or
            `note` is longer than 500 characters. Nothing was changed.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
          description: >-
            Refused — the API key lacks the `sms:write` scope
            (`insufficient_scope`).
        '422':
          $ref: '#/components/responses/Unprocessable'
          description: '`invalid_phone` — the path number is not a valid E.164 number.'
      security:
        - apiKey:
            - sms:write
components:
  schemas:
    PauseSMSContactAIRequest:
      type: object
      description: >-
        Optional context for pausing the AI for one contact. The body may be
        omitted.
      properties:
        note:
          type: string
          maxLength: 500
          description: >-
            Why the AI is paused or who is handling the conversation (at most
            500 characters, whitespace-trimmed). Shown on getSMSContact and on
            the conversation's "AI paused" marker in Observe. An empty or
            omitted note keeps the one already stored.
          example: handled by Kiwi ops (ticket 8812)
    ApiResponse_SMSContactAIPause:
      allOf:
        - $ref: '#/components/schemas/ApiResponseBase'
        - type: object
          required:
            - data
          properties:
            data:
              $ref: '#/components/schemas/SMSContactAIPause'
    ApiResponseBase:
      type: object
      required:
        - success
      properties:
        success:
          type: boolean
        message:
          type: string
        errors:
          type: array
          items:
            type: object
            required:
              - field
              - message
            properties:
              field:
                type: string
              message:
                type: string
    SMSContactAIPause:
      type: object
      required:
        - phoneNumber
        - aiPaused
        - pausedAt
        - pausedBy
        - note
        - webhookSubscribed
      description: The result of pausing the AI for one contact.
      properties:
        phoneNumber:
          type: string
          description: The contact's number (E.164).
        aiPaused:
          type: boolean
          description: >-
            Always true — the AI does not answer this contact's texts until
            resumeSMSContactAI.
        pausedAt:
          type: string
          format: date-time
          description: When the pause began. Repeating the call keeps the original instant.
        pausedBy:
          type: string
          description: >-
            Who first paused it — the API key id, or the user id for a dashboard
            session. Unchanged by a repeated pause while the contact stays
            paused.
        note:
          type: string
          description: The latest note given ('' when none was ever given).
        conversationId:
          type: string
          description: >-
            The person's most recent open text conversation — where the "AI
            paused" marker is drawn when the pause begins. Absent when they have
            no open conversation.
        webhookSubscribed:
          type: boolean
          description: >-
            True when the workspace has an active webhook subscribed to
            `sms.message.received`, so your system will hear the person's texts.
            When false, their texts are still recorded and shown in Observe but
            nothing notifies your system and no one answers them: create a
            webhook for the event (createWebhook) or re-enable a disabled one
            (updateWebhook).
    ProblemDetails:
      description: RFC 9457 problem+json.
      type: object
      properties:
        type:
          type: string
          format: uri
          default: about:blank
        title:
          type: string
        status:
          type: integer
        detail:
          type: string
        instance:
          type: string
        code:
          type: string
        errors:
          type: array
          items:
            type: object
            properties:
              field:
                type: string
              message:
                type: string
    ApiResponse_Void:
      allOf:
        - $ref: '#/components/schemas/ApiResponseBase'
        - type: object
          properties:
            data:
              type:
                - object
                - 'null'
  responses:
    ValidationError:
      description: Validation failure (errors[] populated on the envelope).
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetails'
        application/json:
          schema:
            $ref: '#/components/schemas/ApiResponse_Void'
    Unauthorized:
      description: Missing or invalid API key.
      headers:
        WWW-Authenticate:
          schema:
            type: string
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetails'
    Forbidden:
      description: Org mismatch / RLS / insufficient scope / origin not allowed.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetails'
    Unprocessable:
      description: Semantically invalid (e.g. language not in SKU's STT set).
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetails'
  securitySchemes:
    apiKey:
      type: oauth2
      description: >
        Flowyte secret API key (`Authorization: Bearer flowyte_sk_live_…`).
        Scope-gated; is scoped to your organization — a key can never reach
        another tenant. The listed scopes in each operation's `apiKey`
        requirement are the scopes that key must hold. The `tokenUrl` is
        nominal: keys are minted in the dashboard.
      flows:
        clientCredentials:
          tokenUrl: /api/v1/api-keys
          scopes:
            agents:read: Read agents.
            agents:write: Create/update/delete agents, publish, rollback.
            knowledge:read: Read knowledge sources & preview.
            knowledge:write: Add/remove knowledge sources, uploads.
            skills:read: Read skills & skill-types.
            skills:write: Create/update/delete skills.
            playbooks:read: Read playbooks & graphs.
            playbooks:write: Create/update/delete playbooks & graphs.
            guardrails:read: Read guardrail policies & caller-verification.
            guardrails:write: Update guardrail policies & caller-verification.
            numbers:read: Read phone numbers / search availability.
            numbers:write: Purchase / assign / release numbers.
            sms:read: >-
              Read the org's SMS (10DLC) registration status and numbers, SMS
              contacts, and download any text-message attachment by id
              (getSMSMedia) — pictures, videos and files (such as a PDF) sent or
              received by text.
            sms:write: >-
              Save/submit the 10DLC registration, toggle numbers for SMS, record
              or revoke a contact's SMS consent, and upload pictures and short
              videos to send by text.
            sms:send: >-
              Send outbound text messages from the org's SMS-enabled numbers
              (consent, opt-out and quiet hours are enforced server-side), with
              pictures or short videos attached — including any text-message
              attachment of the workspace whose id the caller knows (an upload,
              or a picture a customer sent).
            outbound:read: Read outbound contact lists and campaigns.
            outbound:write: >-
              Create/import contact lists, create/launch/pause/resume/cancel
              outbound campaigns, and enqueue single outbound calls.
            integrations:read: Read connected native integrations (status only — never tokens).
            integrations:write: Discover schemas, set data scoping, and disconnect a connection.
            integrations:connect: >-
              Connect a data source (submit credentials / begin OAuth) — a
              SEPARATE, higher-privilege scope because connecting INGESTS
              credentials and opens a new egress path; a discover/scope/author
              key need not carry it.
            records:read: >-
              Read the pre-synced Caller Context Store records and object-type
              field registry.
            records:write: >-
              Upsert / delete / bulk-import / purge caller-context records and
              edit type metadata.
            calls:read: Read conversations, receipts, transcripts, analytics.
            analytics:read: >-
              Read the Observe history list, per-agent analytics (the
              answer-rate summary), the raw knowledge-gap list, and the metric
              catalog + per-metric queries + metric drill-downs.
            analytics:write: >-
              Curate knowledge gaps (dismiss / mark in-progress). [M4 —
              reserved]
            dashboards:read: List and read saved Observe reporting dashboards.
            dashboards:write: >-
              Create, update (full-document replace), and delete Observe
              reporting dashboards.
            reports:read: List and read Observe scheduled reports (report schedules).
            reports:write: >-
              Create, update, and delete Observe scheduled reports (a delete
              stops a recurring digest).
            billing:read: Read plans, wallet, usage.
            audit:read: Read API/key activity logs.
            webhooks:write: Manage webhook endpoints.
            keys:write: Manage secret API keys.
            chat:read: Read chat sessions & messages.
            chat:write: Create chat sessions & send messages (server-side).
            widgets:read: Read widget config & embed snippet.
            widgets:write: Update widget config.
            pubkeys:read: Read publishable keys.
            pubkeys:write: Manage publishable keys.
            phone:read: >-
              Read Flowyte Phone config — settings, ring targets/queues +
              rosters, contacts, block-list, own presence.
            phone:write: >-
              Update Flowyte Phone config — settings, ring targets/queues +
              members, contacts, block-list.
            presence:write: Set your own softphone presence (available/away/dnd/…).
            team:read: Read the team — softphone seats and the team presence roster.
            team:write: >-
              Manage softphone seats — invite, update, and deactivate team
              members.
            escalation_destinations:read: Read external-agent (AI Harness) escalation destinations.
            escalation_destinations:write: >-
              Create, update, delete, and rotate the signing secret of
              escalation destinations.
            escalation_policies:read: Read an agent's escalation routing policy. [ — reserved]
            escalation_policies:write: Update an agent's escalation routing policy. [ — reserved]
            escalations:read: >-
              Read escalation sessions and their message history (connector). [
              — reserved]
            escalations:claim: >-
              Claim an escalation session and extend its lease (connector). [ —
              reserved]
            escalations:respond: >-
              Post messages into a claimed escalation session (connector). [ —
              reserved]
            escalations:resolve: >-
              Resolve, return, or request human takeover of an escalation
              (connector). [ — reserved]
            escalations:initiate: >-
              Start a NEW outbound SMS conversation with a customer (connector).
              Deliberately separate from escalations:respond — the other scopes
              work a conversation the platform handed over; this one texts a
              person who never contacted you on that thread. Also requires the
              org to be enabled for harness-initiated conversations.

````

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