openapi: 3.1.0
info:
  title: RelationsAI API
  version: 2026-10-21
  summary: Place AI voice calls, run calling campaigns and manage contacts from your own systems.
  contact:
    name: RelationsAI support
    email: support@relationsai.com
  description: |
    The RelationsAI API lets your servers place outbound AI voice calls, run campaigns, keep contacts and
    the do-not-call list in sync, and receive events by webhook. It is a JSON-over-HTTPS REST API.

    **Private preview.** The API is enabled per workspace. A workspace that has not been enabled gets
    `403 api_access_not_enabled` on every request. Write to support@relationsai.com to request access.

    ## Authentication
    Every request sends an API key as a bearer token: `Authorization: Bearer <key>`. Keys are created in
    the console (API & Developers) by a workspace admin and are shown once.

    - `rai_test_...` keys work in **test mode**: nothing is dialled, nothing is charged, and every object
      has `"livemode": false`.
    - `rai_live_...` keys work in **live mode**: real calls to real people, charged to the workspace
      balance.
    - Older `sk_live_...` keys are not accepted by this API (`401 legacy_api_key_not_supported`).

    Each key carries **scopes** (for example `calls:write`). Each operation lists the scopes it needs
    under `x-required-scopes`. A key can never do more than the member who created it is currently
    allowed to do. Live keys are refused from browsers (requests with an `Origin` header).

    ## Test mode and live mode
    Test mode and live mode are fully separate. Calls, campaigns, recipients, contacts, do-not-call
    entries, webhook endpoints, events and deliveries created with a test key exist only in test mode,
    and the same for live. An id from the other mode is answered with `404 resource_not_found`.
    Agents and phone numbers are your workspace's real configuration in both modes; test mode also has
    a built-in **Sample agent** and a sample number `+12025550150`, so you can try everything before
    your own agent is ready.

    In test mode the destination number chooses what happens to a call:

    | Destination | Simulated result |
    |---|---|
    | `+12025550100` | Answered and completed, with transcript, recording and analysis |
    | `+12025550101` | No answer |
    | `+12025550102` | Busy |
    | `+12025550103` | Failed (network error) |
    | `+12025550104` | Answered by voicemail: `no_response` |
    | `+12025550105` | Completed after a longer conversation |
    | `+12025550106` | The person hangs up early: `completed`, short duration |
    | any other number | Completed |

    A test call reaches `ended` within about 20 seconds and `settled` within about 30 seconds.
    Do-not-call entries and missing consent refuse calls in test mode exactly as in live mode.

    ## Requests and responses
    - Bodies are JSON with `Content-Type: application/json`. Field names are `snake_case`. Request
      bodies are strict: an unknown field is a `400 validation_error`, never silently ignored.
    - Ids are opaque strings with a type prefix (`call_`, `cmp_`, `ct_`, ...). Treat them as opaque.
    - Timestamps are RFC 3339 in UTC, for example `2026-10-21T09:30:00.000Z`.
    - Money is `{"amount": <integer minor units>, "currency": "INR"}`, always what your workspace is
      charged.
    - Phone numbers are E.164 strings, for example `+919000000001`.
    - **Enums are open.** New values can be added at any time; treat an unknown value as "other",
      never as success.
    - Every response carries `X-Request-Id`. Quote it to support.
    - `HEAD` is accepted wherever `GET` is and answers the same status and headers with no body.
    - An operation that documents no request body ignores a body sent with it (it is not read, so it is
      never refused as `415`, `413` or `invalid_json`).
    - Responses carry no automatic `ETag`; only campaigns and contacts have one (see Concurrency), and
      conditional GET headers (`If-None-Match`, `If-Modified-Since`) are ignored: a response is never `304`.

    ## Pagination
    List operations return `{"object": "list", "data": [...], "has_more": bool, "next_cursor": string|null}`,
    newest first. Pass `limit` (1 to 100, default 25) and, for the next page, `cursor` set to the
    previous `next_cursor` with the **same filters**. Cursors are opaque and bound to the filters that
    produced them.

    ## Idempotency
    The `Idempotency-Key` header is **optional** on every `POST` and `DELETE`: an extra safety for retries.
    Without it every request runs, so a retry after a timeout or a lost response can repeat the action (place
    a second call, start a campaign again); before retrying, check the state with a `GET` (for a call, list
    calls by `to` and `created_after`). With it (1 to 255 printable ASCII characters, no spaces; a UUID v4 is
    ideal), a retry is safe. Keys are scoped to your workspace and mode and kept for 24 hours.
    What is stored under a key: a successful (2xx) answer, and the few errors whose documentation says the
    outcome is unknown and the answer is kept (for example `campaign_outcome_unknown`). A retry with the
    same key and the same request gets that stored answer again with `Idempotent-Replayed: true` (the
    same data and status; `request_id` and `X-Request-Id` are the retry's own, and a stored `retry: after`
    error carries its `Retry-After`). Any other error is not stored: a retry with the same key runs the
    request again (each error page says what to check first). Reusing a key for a different request is
    `409 idempotency_key_reused`. If the first attempt is still running you get
    `409 idempotency_key_in_progress` with `Retry-After`. If you send keys, **never generate a new key to
    retry a request that may have succeeded**: that is how a request runs twice.

    ## Concurrency
    Campaigns and contacts carry an `ETag` response header. `PATCH` on them requires `If-Match` with
    that value (`428 precondition_required` if missing, `412 version_conflict` if the resource changed).
    `If-Match: *` matches any current version and applies the update without the concurrency check.

    ## Errors
    Every error has the same envelope: `{"error": {"code", "message", "details", "request_id", "retry",
    "doc_url"}}`. Branch on `code`. `retry` tells you what to do: `no` (fix the request or the
    configuration), `yes` (retry with backoff: with the same Idempotency-Key if you sent one, otherwise after
    checking the state with a `GET`) or `after` (wait
    `Retry-After` seconds). Some errors can happen after work may have begun; their documentation says
    so and tells you to retry with the same key and then check the resource state.

    ## Rate limits
    Limits apply per key and per workspace, separately in test and live mode, in three classes: `read`
    (600 per minute per key, 1200 per workspace), `write` (120 per key, 240 per workspace) and `dial`
    (placing calls and starting or resuming campaigns: 30 per minute per workspace). Requests that end
    before they reach an operation (an unknown path, a refused body, a missing or invalid key, a workspace
    without API access) are counted per client IP address: 300 per minute, after which every request
    from that address answers `429 rate_limited` until the window resets. Live mode also caps calls
    placed through the API per UTC day (`429 daily_call_limit_reached`): each `POST /v1/calls` counts
    one, a campaign start counts every recipient and is refused whole if they do not all fit, and a
    resume counts nothing. Every response has `RateLimit-Limit`, `RateLimit-Remaining` and
    `RateLimit-Reset` (for the tightest limit that applied); 429 and 503 responses have `Retry-After`.
    Each operation's class is shown as `x-rate-limit-class`.

    ## Asynchronous work
    Calls and campaigns run after the request returns. `POST /v1/calls` answers `202` with a call in
    `queued` status; follow it with webhooks (`call.ended`, `call.settled`) or by polling
    `GET /v1/calls/{call_id}`. Transcripts, recordings and analysis become ready after the call ends,
    usually within a minute and sometimes several minutes later; `call.settled` says everything,
    including the charge, is final.

    ## Versioning
    The major version is in the path (`/v1`). Additive changes (new operations, fields, enum values,
    event types, error codes) ship without advance notice and are recorded in the changelog. Breaking changes need a new major
    version and at least six months' notice. Events carry `api_version`.
servers:
  - url: https://voice-api.relationsai.com/v1
    description: Production. Test keys use test mode, live keys use live mode.
security:
  - ApiKeyAuth: []
tags:
  - name: Workspace
    description: The workspace and API key a request is authenticated as, and what they can do.
  - name: Agents
    description: AI voice agents. Agents are created, configured and published in the console; the API reads them and tells you whether one is ready to place calls. Agent editing through the API is planned.
  - name: Phone numbers
    description: The workspace's phone numbers and which agents use them. Numbers are added and assigned in the console.
  - name: Calls
    description: Place outbound calls and read their status, outcome, transcript, recording and analysis.
  - name: Campaigns
    description: Call a list of contacts with one agent, with pause, resume and stop.
  - name: Contacts
    description: People you call, with consent and custom fields that become call variables.
  - name: Do-not-call list
    description: "Numbers that must never be called. Checked, in both modes, on every `POST /v1/calls`, when a campaign starts and when it resumes (the resume re-screens). A number added while a campaign is running is not removed from that run: pause and resume the campaign to re-screen it, or stop the campaign."
  - name: Webhook endpoints
    description: Receive signed event notifications on your server.
x-tagGroups:
  - name: Basics
    tags:
      - Workspace
  - name: Configuration
    tags:
      - Agents
      - Phone numbers
  - name: Calling
    tags:
      - Calls
      - Campaigns
  - name: Audience
    tags:
      - Contacts
      - Do-not-call list
  - name: Events
    tags:
      - Webhook endpoints
x-scopes:
  - scope: workspace:read
    label: Read workspace
    description: Read the workspace, the current key and its limits. Every key has it.
    default: true
  - scope: agents:read
    label: Read agents
    description: List and retrieve agents and check their readiness.
    default: true
  - scope: numbers:read
    label: Read phone numbers
    description: List and retrieve phone numbers.
    default: true
  - scope: calls:read
    label: Read calls
    description: List and retrieve calls, with status, outcome, timing and cost.
    default: true
  - scope: calls:write
    label: Place calls
    description: Place outbound calls. Live calls are charged to the workspace.
    default: false
  - scope: transcripts:read
    label: Read transcripts
    description: Read call transcripts, verbatim.
    default: true
  - scope: recordings:read
    label: Read recordings
    description: Get short-lived links to call recordings.
    default: true
  - scope: analysis:read
    label: Read analysis
    description: Read call summaries, extracted fields and goal outcome.
    default: true
  - scope: campaigns:read
    label: Read campaigns
    description: List and retrieve campaigns and their recipients.
    default: true
  - scope: campaigns:write
    label: Manage campaigns
    description: Create and edit campaigns, add recipients, and start, pause, resume and stop them. Live campaigns are charged.
    default: false
  - scope: contacts:read
    label: Read contacts
    description: List and retrieve contacts, including consent and custom fields.
    default: true
  - scope: contacts:write
    label: Manage contacts
    description: Create, update and delete contacts and record consent.
    default: false
  - scope: dnc:read
    label: Read do-not-call list
    description: List and look up do-not-call entries.
    default: true
  - scope: dnc:write
    label: Manage do-not-call list
    description: Add numbers to and remove numbers from the do-not-call list. Removals are audited.
    default: false
  - scope: webhooks:read
    label: Read webhook endpoints
    description: List and retrieve webhook endpoints and their deliveries.
    default: true
  - scope: webhooks:write
    label: Manage webhook endpoints
    description: Create, update, delete and test webhook endpoints, rotate their secrets and retry deliveries.
    default: false
x-event-types:
  - type: call.ended
    description: A call ended. Outcome and duration are known; artifacts and the charge may still be pending.
  - type: call.settled
    description: Everything about a call is final, including transcript, recording, analysis and the charge.
  - type: campaign.started
    description: A campaign started a run and began dialling.
  - type: campaign.paused
    description: A campaign was paused, by a request or automatically (budget, balance, telephony).
  - type: campaign.resumed
    description: A paused campaign resumed its run.
  - type: campaign.stopped
    description: A campaign was stopped. It will not dial again unless started anew.
  - type: campaign.completed
    description: A campaign run finished dialling every recipient.
  - type: campaign.failed
    description: A campaign run ended in failure before finishing.
  - type: webhook_endpoint.test
    description: A test event you sent to an endpoint.
components:
  schemas:
    Agent:
      type: object
      description: "An AI voice agent: what callers hear and how the conversation goes. Agents are created, configured, published and switched on in the console. A call uses the agent's published version."
      additionalProperties: false
      required:
        - id
        - object
        - livemode
        - name
        - description
        - status
        - published
        - published_version
        - is_default
        - sample
        - created_at
        - updated_at
      properties:
        id:
          type: string
          description: Agent id (`agent_...`).
          pattern: ^agent_[A-Za-z0-9_-]{1,58}$
        object:
          type: string
          const: agent
          description: Always `agent`.
        livemode:
          type: boolean
          description: Mode of the key that read it. Agents are shared configuration, readable in both modes.
        name:
          type: string
          description: Agent name.
        description:
          type:
            - string
            - "null"
          description: What the agent is for, as written in the console. Null when not set.
        status:
          type: string
          description: "Whether the agent is switched on in the console. `active` agents can place calls; `paused` and `draft` agents cannot. Open enum: unknown values mean the agent cannot be assumed callable."
          enum:
            - active
            - paused
            - draft
            - unknown
        published:
          type:
            - boolean
            - "null"
          description: True when the agent has a published version that calls use. Null when the publication state could not be read right now; use the readiness endpoint for a definite answer.
        published_version:
          type:
            - integer
            - "null"
          description: Number of the published version, when known.
          minimum: 1
        is_default:
          type: boolean
          description: True for the workspace's default agent.
        sample:
          type: boolean
          description: True only for the built-in Sample agent that exists in test mode.
        created_at:
          type: string
          format: date-time
          description: When the agent was created.
        updated_at:
          type:
            - string
            - "null"
          format: date-time
          description: When the agent's configuration last changed, when known.
    AgentList:
      description: A page of agents, newest first.
      allOf:
        - $ref: "#/components/schemas/ListMeta"
        - type: object
          description: The agents.
          required:
            - data
          properties:
            data:
              type: array
              description: Agents on this page.
              items:
                $ref: "#/components/schemas/Agent"
      unevaluatedProperties: false
    AgentReadiness:
      type: object
      description: Whether an agent can place calls right now, and every reason it cannot. This is a point-in-time check of the agent and the workspace. Per-destination rules (do-not-call list, consent, calling hours, the per-number daily limit) are checked when each call is placed and are not part of readiness.
      additionalProperties: false
      required:
        - object
        - livemode
        - agent_id
        - ready
        - reasons
        - checked_at
      properties:
        object:
          type: string
          const: agent_readiness
          description: Always `agent_readiness`.
        livemode:
          type: boolean
          description: Mode of the key that asked.
        agent_id:
          type: string
          description: The agent checked.
        ready:
          type: boolean
          description: True when `reasons` is empty.
        reasons:
          type: array
          description: Every reason the agent cannot place calls. Empty when ready.
          items:
            $ref: "#/components/schemas/AgentReadinessReason"
        checked_at:
          type: string
          format: date-time
          description: When the check ran.
    AgentReadinessReason:
      type: object
      description: One reason an agent cannot place calls.
      additionalProperties: false
      required:
        - code
        - message
      properties:
        code:
          type: string
          description: "Machine-readable reason. Open enum: `agent_paused` (switched off in the console), `agent_not_connected` (setup not finished: open the agent in the console and save it once), `agent_not_published` (no published version, or its live version is paused), `no_outbound_number` (no outbound number assigned to the agent), `calling_not_configured` (no telephony account or number in the workspace), `telephony_disconnected`, `account_inactive` (trial ended or account suspended), `spend_limit_reached`, `insufficient_balance`."
        message:
          type: string
          description: What to do about it, for an operator.
    ArtifactState:
      type: object
      description: State of one call artifact.
      additionalProperties: false
      required:
        - state
      properties:
        state:
          type: string
          description: "`pending`, `ready`, `absent` or `failed`. Open enum."
          enum:
            - pending
            - ready
            - absent
            - failed
    Call:
      type: object
      description: |
        An outbound call placed by an agent. A call moves through these statuses:

        `queued` (accepted; being placed) -> `ringing` (not reported today, see `capabilities.call_ringing_status` on the workspace) -> `in_progress` (connected) -> `ended`.

        After `ended`, the transcript, recording and analysis become ready (`artifacts`), and the charge is
        finalised. When everything is final, `settled` becomes true and a `call.settled` event is sent.
        `outcome`, `duration_seconds` and `cost` can still change between `ended` and `settled`; treat them
        as final only once `settled` is true.
      additionalProperties: false
      required:
        - id
        - object
        - livemode
        - status
        - outcome
        - end_reason
        - direction
        - source
        - agent_id
        - campaign_id
        - phone_number_id
        - from
        - to
        - metadata
        - created_at
        - ended_at
        - duration_seconds
        - billable_minutes
        - cost
        - artifacts
        - settled
        - settled_at
      properties:
        id:
          type: string
          description: Call id (`call_...`).
          pattern: ^call_[A-Za-z0-9_-]{1,59}$
        object:
          type: string
          const: call
          description: Always `call`.
        livemode:
          type: boolean
          description: "`true` for a live call, `false` for a simulated test-mode call."
        status:
          type: string
          description: Where the call is in its lifecycle. Open enum. `unknown` means the state could not be confirmed for an unusually long time; it is not a success.
          enum:
            - queued
            - ringing
            - in_progress
            - ended
            - unknown
        outcome:
          type:
            - string
            - "null"
          description: "How the call ended. Null until `status` is `ended`. `completed`: answered and a conversation took place. `no_response`: answered but nobody spoke (this includes most voicemail greetings). `no_answer`, `busy`: not answered. `failed`: could not be connected. `unknown`: the result could not be determined. Open enum."
          enum:
            - completed
            - no_response
            - no_answer
            - busy
            - failed
            - unknown
            - null
        end_reason:
          type:
            - string
            - "null"
          description: "Why the call ended. Null until `status` is `ended`. `hangup`: a normal end of a connected call. `no_answer`, `busy`, `invalid_number`, `network_error`: the call was not connected for that reason. `insufficient_balance`: ended because the workspace balance ran out. `not_confirmed`: the start was never confirmed, so the call is treated as failed and is not charged (whether the number briefly rang cannot be known). `refused`: the call was refused before it started. `unknown`. Open enum."
          enum:
            - hangup
            - no_answer
            - busy
            - invalid_number
            - network_error
            - insufficient_balance
            - not_confirmed
            - refused
            - unknown
            - null
        direction:
          type: string
          description: Always `outbound` today. Open enum.
          enum:
            - outbound
            - inbound
        source:
          type: string
          description: "`api` (placed with POST /v1/calls), `console`, or `campaign`. Open enum."
          enum:
            - api
            - console
            - campaign
        agent_id:
          type:
            - string
            - "null"
          description: The agent that handled the call. Null only if the agent was deleted.
        campaign_id:
          type:
            - string
            - "null"
          description: The campaign that placed the call, if any.
        phone_number_id:
          type:
            - string
            - "null"
          description: The workspace number the call was placed from, once known.
        from:
          type:
            - string
            - "null"
          description: The caller number shown to the person called (E.164), once known. Null when not known in full.
        to:
          type:
            - string
            - "null"
          description: The number called (E.164), always in full. Null only for some calls recorded before 2026-08-14 whose number was stored partially at the time; a partial number is never shown in place of a full one.
        metadata:
          $ref: "#/components/schemas/Metadata"
        created_at:
          type: string
          format: date-time
          description: When the call was accepted.
        ended_at:
          type:
            - string
            - "null"
          format: date-time
          description: When the call ended.
        duration_seconds:
          type:
            - integer
            - "null"
          description: Talk time in seconds once known. Final when `settled` is true.
          minimum: 0
        billable_minutes:
          type:
            - integer
            - "null"
          description: Minutes charged (whole minutes, rounded up). Zero for calls that are not charged. Final when `settled` is true.
          minimum: 0
        cost:
          description: What the workspace was charged for this call. Null until known; always zero in test mode.
          oneOf:
            - $ref: "#/components/schemas/Money"
            - type: "null"
              description: Not known yet.
        artifacts:
          $ref: "#/components/schemas/CallArtifacts"
        settled:
          type: boolean
          description: True when outcome, duration, artifacts and charge are all final.
        settled_at:
          type:
            - string
            - "null"
          format: date-time
          description: When the call settled.
    CallAnalysis:
      type: object
      description: "What the call achieved: a summary, the fields the agent was configured to extract, and whether the call's goal was met. Produced after the call ends."
      additionalProperties: false
      required:
        - object
        - livemode
        - call_id
        - state
        - simulated
        - summary
        - extracted_fields
        - goal_met
      properties:
        object:
          type: string
          const: call_analysis
          description: Always `call_analysis`.
        livemode:
          type: boolean
          description: Mode of the call.
        call_id:
          type: string
          description: The call.
        state:
          type: string
          description: "Overall state: `pending` while any part is still being produced, `ready` when every part has finished (a part may still be `failed`), `absent` when the call produced nothing to analyse. Open enum."
          enum:
            - pending
            - ready
            - absent
            - failed
        simulated:
          type: boolean
          description: True for a test-mode fixture.
        summary:
          type: object
          description: A short written summary of the conversation.
          additionalProperties: false
          required:
            - state
            - text
          properties:
            state:
              type: string
              description: "`pending`, `ready`, `absent` or `failed`. Open enum."
              enum:
                - pending
                - ready
                - absent
                - failed
            text:
              type:
                - string
                - "null"
              description: The summary. Null unless `state` is `ready`.
        extracted_fields:
          type: array
          description: Fields the agent is configured (in the console) to extract from the conversation.
          items:
            $ref: "#/components/schemas/ExtractedField"
        goal_met:
          type:
            - boolean
            - "null"
          description: Whether the call met the agent's goal, when the agent is configured to report it. Null otherwise.
    CallArtifacts:
      type: object
      description: "Readiness of each artifact of the call. `pending`: not ready yet. `ready`: available from its endpoint. `absent`: there is none for this call (for example a call that was not answered has no recording). `failed`: it could not be produced. Open enum."
      additionalProperties: false
      required:
        - transcript
        - recording
        - analysis
      properties:
        transcript:
          $ref: "#/components/schemas/ArtifactState"
        recording:
          $ref: "#/components/schemas/ArtifactState"
        analysis:
          $ref: "#/components/schemas/ArtifactState"
    CallCreateRequest:
      type: object
      description: Place one outbound call.
      additionalProperties: false
      required:
        - agent_id
        - to
      properties:
        agent_id:
          type: string
          description: The agent that makes the call (`agent_...`). It must be ready (see the agent readiness endpoint).
          pattern: ^agent_[A-Za-z0-9_-]{1,58}$
        to:
          type: string
          description: The number to call, in E.164 format (a plus, then 8 to 15 digits, the first not 0).
          format: e164
          pattern: ^\+[1-9][0-9]{7,14}$
        phone_number_id:
          type: string
          description: "The workspace number to call from (`pn_...`). Optional: by default the agent's outbound number is used. Required when the agent has more than one outbound number."
          pattern: ^pn_[A-Za-z0-9_-]{1,61}$
        variables:
          type: object
          description: "Values the agent can use in the conversation, for example `{\"first_name\": \"Asha\"}`. Up to 50 keys; keys are lowercase letters, digits and `_`, starting with a letter, up to 64 characters; values are strings up to 500 characters. If the destination matches a contact, the contact's name and custom fields are added automatically; values here take precedence."
          maxProperties: 50
          propertyNames:
            pattern: ^[a-z][a-z0-9_]{0,63}$
          additionalProperties:
            type: string
            maxLength: 500
        metadata:
          $ref: "#/components/schemas/Metadata"
    CallEvent:
      description: A call event. `data.object` is the call as it was when the event was created.
      allOf:
        - $ref: "#/components/schemas/EventBase"
        - type: object
          description: Call event payload.
          properties:
            type:
              type: string
              description: The call event type.
              enum:
                - call.ended
                - call.settled
            data:
              type: object
              description: Event data.
              additionalProperties: false
              required:
                - object
              properties:
                object:
                  $ref: "#/components/schemas/Call"
      unevaluatedProperties: false
    CallList:
      description: A page of calls, newest first.
      allOf:
        - $ref: "#/components/schemas/ListMeta"
        - type: object
          description: The calls.
          required:
            - data
          properties:
            data:
              type: array
              description: Calls on this page.
              items:
                $ref: "#/components/schemas/Call"
      unevaluatedProperties: false
    CallRecording:
      type: object
      description: The call recording. When `state` is `ready`, `url` is a short-lived HTTPS link to the audio that needs no API key. Fetch it before `expires_at`, and retrieve this object again for a fresh link. Do not store the link.
      additionalProperties: false
      required:
        - object
        - livemode
        - call_id
        - state
        - simulated
        - url
        - expires_at
        - content_type
      properties:
        object:
          type: string
          const: call_recording
          description: Always `call_recording`.
        livemode:
          type: boolean
          description: Mode of the call.
        call_id:
          type: string
          description: The call.
        state:
          type: string
          description: "`pending`, `ready`, `absent` (no recording exists for this call) or `failed`. Open enum."
          enum:
            - pending
            - ready
            - absent
            - failed
        simulated:
          type: boolean
          description: True for the short synthetic audio file used in test mode.
        url:
          type:
            - string
            - "null"
          format: uri
          description: Short-lived link to the audio. Null unless `state` is `ready`.
        expires_at:
          type:
            - string
            - "null"
          format: date-time
          description: When `url` stops working.
        content_type:
          type:
            - string
            - "null"
          description: Media type of the audio, for example `audio/ogg` or `audio/mpeg` (`audio/wav` for test-mode audio). Null when not known in advance; the download's `Content-Type` is authoritative.
    CallTranscript:
      type: object
      description: The words spoken on a call, in order, verbatim (nothing is masked). Available after the call ends; `state` says whether it is ready.
      additionalProperties: false
      required:
        - object
        - livemode
        - call_id
        - state
        - simulated
        - turns
      properties:
        object:
          type: string
          const: call_transcript
          description: Always `call_transcript`.
        livemode:
          type: boolean
          description: Mode of the call.
        call_id:
          type: string
          description: The call.
        state:
          type: string
          description: "`pending`, `ready`, `absent` (nothing was said or the call was not connected) or `failed`. `turns` is empty unless `ready`. Open enum."
          enum:
            - pending
            - ready
            - absent
            - failed
        simulated:
          type: boolean
          description: True for a test-mode fixture transcript.
        turns:
          type: array
          description: Turns in the order they were spoken.
          items:
            $ref: "#/components/schemas/TranscriptTurn"
    Campaign:
      type: object
      description: |
        A campaign calls a list of recipients (contacts) with one agent. Lifecycle:

        `draft` -> start -> `running` <-> `paused` -> `stopped`, or `running` -> `completed` / `failed`.

        - **start** begins a run. It is allowed from `draft`, `paused`, `stopped`, `completed` and `failed`.
          From `paused` it abandons the paused run and begins a new one; from `stopped`, `completed` or
          `failed` it calls the previous run's recipients again, including people already reached. A start of
          a campaign that was stopped before it ever started calls the recipients added to it. Every start
          screens recipients against the do-not-call list, consent and the per-number daily limit and leaves
          blocked ones out.
        - **pause** (from `running`) stops new calls; calls already connected finish normally.
        - **resume** (from `paused`) continues the same run. Every remaining recipient is screened again; if
          any is now blocked, the resume is refused and the campaign stays paused.
        - **Do-not-call timing.** Recipients are screened when a run starts and when it resumes, not before
          each call. A number added to the do-not-call list while the campaign is running is still called by
          that run: pause and resume the campaign (the resume is refused while a remaining recipient is
          listed) or stop it.
        - **stop** (from `draft`, `running` or `paused`) ends the campaign; calls already connected finish.
        - **Edits** (PATCH) are allowed in every status except `running` and take effect at the next start.
          A resume continues with the settings the run began with.
        - **Recipients** can be added only while the campaign is `draft`.

        A campaign whose do-not-call screening was switched off in the console (`dnc_screening`
        `disabled_in_console`) cannot be started or resumed through the API.

        A campaign can also be paused automatically, for example when its budget cap is reached, the
        workspace balance runs out, or the telephony connection drops. `capabilities` says which actions
        are allowed right now.
      additionalProperties: false
      required:
        - id
        - object
        - livemode
        - name
        - agent_id
        - status
        - capabilities
        - concurrency_limit
        - budget_cap
        - recipient_count
        - progress
        - spend
        - run_number
        - created_at
      properties:
        id:
          type: string
          description: Campaign id (`cmp_...`).
          pattern: ^cmp_[A-Za-z0-9_-]{1,60}$
        object:
          type: string
          const: campaign
          description: Always `campaign`.
        livemode:
          type: boolean
          description: "`true` for a live campaign, `false` for a test-mode campaign."
        name:
          type: string
          description: Campaign name.
        agent_id:
          type:
            - string
            - "null"
          description: The agent that makes the calls. Null if the agent was deleted; the campaign cannot start until one is set.
        status:
          type: string
          description: "`draft` (never started), `running`, `paused`, `stopped`, `completed` (the run finished), `failed` (the run ended in failure), `unknown`. Open enum."
          enum:
            - draft
            - running
            - paused
            - stopped
            - completed
            - failed
            - unknown
        capabilities:
          $ref: "#/components/schemas/CampaignCapabilities"
        concurrency_limit:
          type: integer
          description: Most calls the campaign places at the same time. Lowered at start to the plan maximum (`limits.campaign_max_concurrency` on the workspace). Campaigns created in the console can hold a higher value than the API accepts on a write.
          minimum: 1
        budget_cap:
          description: The spend at which the campaign is paused. When the campaign's spend reaches the cap the campaign is paused. The check runs about every 15 minutes, so spend can exceed the cap by the calls placed in that time. Null for no cap.
          oneOf:
            - $ref: "#/components/schemas/Money"
            - type: "null"
              description: No cap.
        recipient_count:
          type: integer
          description: "Before the first start, the recipients added to the campaign. From a start on, the recipients that run calls: recipients left out by compliance screening at that start are not counted."
          minimum: 0
        progress:
          $ref: "#/components/schemas/CampaignProgress"
        spend:
          description: What the current or latest run has cost so far. Always zero in test mode, which never charges.
          allOf:
            - $ref: "#/components/schemas/Money"
        run_number:
          type: integer
          description: How many runs the campaign has had. 0 before the first start.
          minimum: 0
        dnc_screening:
          type: string
          description: "`enforced` (numbers on the do-not-call list are left out at every start and block a resume) or `disabled_in_console` (a person switched screening off for this campaign in the console; the API refuses to start or resume it with `409 campaign_dnc_override_enabled`). Read-only. Open enum."
          enum:
            - enforced
            - disabled_in_console
        created_at:
          type: string
          format: date-time
          description: When the campaign was created.
    CampaignCapabilities:
      type: object
      description: Which actions the campaign allows in its current status.
      additionalProperties: false
      required:
        - start
        - pause
        - resume
        - stop
        - update
        - add_recipients
      properties:
        start:
          type: boolean
          description: POST .../start is allowed.
        pause:
          type: boolean
          description: POST .../pause is allowed.
        resume:
          type: boolean
          description: POST .../resume is allowed.
        stop:
          type: boolean
          description: POST .../stop is allowed.
        update:
          type: boolean
          description: PATCH is allowed.
        add_recipients:
          type: boolean
          description: POST .../recipients is allowed.
    CampaignCreateRequest:
      type: object
      description: Create a campaign in `draft` status. Nothing is dialled until you start it.
      additionalProperties: false
      required:
        - name
        - agent_id
      properties:
        name:
          type: string
          description: Campaign name.
          minLength: 1
          maxLength: 200
        agent_id:
          type: string
          description: The agent that makes the calls.
          pattern: ^agent_[A-Za-z0-9_-]{1,58}$
        concurrency_limit:
          type: integer
          description: Most simultaneous calls. Defaults to 1. Lowered at start to the plan maximum.
          minimum: 1
          maximum: 100
          default: 1
        budget_cap:
          description: The spend at which the campaign is paused. When the campaign's spend reaches the cap the campaign is paused. The check runs about every 15 minutes, so spend can exceed the cap by the calls placed in that time. Omit or null for no cap.
          oneOf:
            - $ref: "#/components/schemas/MoneyInput"
            - type: "null"
              description: No cap.
        contact_ids:
          type: array
          description: Contacts to add as recipients now. You can also add them later, while the campaign is `draft`.
          maxItems: 1000
          uniqueItems: true
          items:
            type: string
            pattern: ^ct_[A-Za-z0-9_-]{1,61}$
    CampaignEvent:
      description: A campaign event. `data.object` is the campaign as it was when the event was created.
      allOf:
        - $ref: "#/components/schemas/EventBase"
        - type: object
          description: Campaign event payload.
          properties:
            type:
              type: string
              description: The campaign event type.
              enum:
                - campaign.started
                - campaign.paused
                - campaign.resumed
                - campaign.stopped
                - campaign.completed
                - campaign.failed
            data:
              type: object
              description: Event data.
              additionalProperties: false
              required:
                - object
                - reason
              properties:
                object:
                  $ref: "#/components/schemas/Campaign"
                reason:
                  type:
                    - string
                    - "null"
                  description: "Why it happened, on `campaign.paused` and `campaign.stopped`: `requested` (an API or console request), `budget_cap_reached`, `insufficient_balance`, `spend_limit_reached`, `telephony_disconnected`, `failure_streak` (too many consecutive failed calls), `start_refused` (the start was refused before any call was placed, for example the agent or the phone number is not ready, so the campaign was left paused; fix the cause and start it again), `account_inactive`, `unknown` (also when the campaign was stopped outside RelationsAI's control). Null on other types. Open enum."
      unevaluatedProperties: false
    CampaignList:
      description: A page of campaigns, newest first.
      allOf:
        - $ref: "#/components/schemas/ListMeta"
        - type: object
          description: The campaigns.
          required:
            - data
          properties:
            data:
              type: array
              description: Campaigns on this page.
              items:
                $ref: "#/components/schemas/Campaign"
      unevaluatedProperties: false
    CampaignProgress:
      type: object
      description: Call counts for the current or latest run. A call is counted in `in_progress` until it ends, and only then in `connected`, `no_answer` or `failed`. Updated as calls end; can lag by up to a minute.
      additionalProperties: false
      required:
        - calls
        - connected
        - no_answer
        - failed
        - in_progress
      properties:
        calls:
          type: integer
          description: Calls placed.
          minimum: 0
        connected:
          type: integer
          description: Ended calls that were answered.
          minimum: 0
        no_answer:
          type: integer
          description: Ended calls that were not answered or were busy.
          minimum: 0
        failed:
          type: integer
          description: Every other ended call (it could not be connected, or it ended with an outcome that is not known).
          minimum: 0
        in_progress:
          type: integer
          description: Calls not yet ended.
          minimum: 0
    CampaignRecipient:
      type: object
      description: One recipient of a campaign and what has happened to them in the current or latest run.
      additionalProperties: false
      required:
        - id
        - object
        - livemode
        - campaign_id
        - contact_id
        - phone_number
        - status
        - attempts
        - last_call_id
        - outcome
        - suppression_reason
      properties:
        id:
          type: string
          description: Recipient id (`rcp_...`).
          pattern: ^rcp_[A-Za-z0-9_-]{1,60}$
        object:
          type: string
          const: campaign_recipient
          description: Always `campaign_recipient`.
        livemode:
          type: boolean
          description: Mode of the campaign.
        campaign_id:
          type: string
          description: The campaign.
        contact_id:
          type: string
          description: The contact.
        phone_number:
          type: string
          description: The number that is (or was) called.
        status:
          type: string
          description: "`pending` (not yet called in this run), `in_progress`, `completed` (called; see `outcome`), `failed` (every attempt failed), `suppressed` (left out by compliance screening, see `suppression_reason`), `cancelled` (the run stopped before reaching them), `unknown`. Open enum. In live mode a recipient left out by screening at start is not recorded per recipient yet: it shows `pending` while the run is open and `unknown` once the run has ended. Test mode records it as `suppressed`."
          enum:
            - pending
            - in_progress
            - completed
            - failed
            - suppressed
            - cancelled
            - unknown
        attempts:
          type: integer
          description: Call attempts made in this run.
          minimum: 0
        last_call_id:
          type:
            - string
            - "null"
          description: The most recent call to this recipient, if any.
        outcome:
          type:
            - string
            - "null"
          description: Outcome of the most recent call, using the call `outcome` values. Null if not called yet.
        suppression_reason:
          type:
            - string
            - "null"
          description: Why the recipient was left out, when `status` is `suppressed`. Open enum `dnc_listed`, `consent_required`, `contact_daily_limit_reached`, `unknown`.
    CampaignRecipientList:
      description: A page of campaign recipients, in a stable order.
      allOf:
        - $ref: "#/components/schemas/ListMeta"
        - type: object
          description: The recipients.
          required:
            - data
          properties:
            data:
              type: array
              description: Recipients on this page.
              items:
                $ref: "#/components/schemas/CampaignRecipient"
      unevaluatedProperties: false
    CampaignRecipientsAddRequest:
      type: object
      description: Add contacts to a draft campaign as recipients.
      additionalProperties: false
      required:
        - contact_ids
      properties:
        contact_ids:
          type: array
          description: Contacts to add. Contacts already in the campaign are skipped, not duplicated.
          minItems: 1
          maxItems: 1000
          uniqueItems: true
          items:
            type: string
            pattern: ^ct_[A-Za-z0-9_-]{1,61}$
    CampaignRecipientsAddResult:
      type: object
      description: Result of adding recipients.
      additionalProperties: false
      required:
        - object
        - livemode
        - campaign_id
        - added
        - recipient_count
      properties:
        object:
          type: string
          const: campaign_recipients_added
          description: Always `campaign_recipients_added`.
        livemode:
          type: boolean
          description: Mode of the campaign.
        campaign_id:
          type: string
          description: The campaign.
        added:
          type: integer
          description: Recipients newly added by this request (contacts already in the campaign are not counted).
          minimum: 0
        recipient_count:
          type: integer
          description: Total recipients in the campaign now.
          minimum: 0
    CampaignUpdateRequest:
      type: object
      description: Fields to change. Omitted fields are left as they are. Changes apply from the next start.
      additionalProperties: false
      minProperties: 1
      properties:
        name:
          type: string
          description: Campaign name.
          minLength: 1
          maxLength: 200
        agent_id:
          type: string
          description: The agent that makes the calls.
          pattern: ^agent_[A-Za-z0-9_-]{1,58}$
        concurrency_limit:
          type: integer
          description: Most simultaneous calls.
          minimum: 1
          maximum: 100
        budget_cap:
          description: The spend at which the campaign is paused, or null to remove the cap. When the campaign's spend reaches the cap the campaign is paused. The check runs about every 15 minutes, so spend can exceed the cap by the calls placed in that time.
          oneOf:
            - $ref: "#/components/schemas/MoneyInput"
            - type: "null"
              description: Remove the cap.
    Contact:
      type: object
      description: "A person you call. Phone numbers are unique within a workspace and mode. Custom field values become call variables: an agent can use `{{field_name}}` in its prompt."
      additionalProperties: false
      required:
        - id
        - object
        - livemode
        - phone_number
        - name
        - language
        - country_code
        - consent_granted
        - do_not_call
        - custom_fields
        - created_at
      properties:
        id:
          type: string
          description: Contact id (`ct_...`).
          pattern: ^ct_[A-Za-z0-9_-]{1,61}$
        object:
          type: string
          const: contact
          description: Always `contact`.
        livemode:
          type: boolean
          description: "`true` for a live contact, `false` for a test-mode contact."
        phone_number:
          type: string
          description: The contact's number. E.164 for contacts created through this API; contacts created earlier in the console may hold the number in the format it was entered.
        name:
          type:
            - string
            - "null"
          description: Display name.
        language:
          type:
            - string
            - "null"
          description: Preferred language, as free text or a language code.
        country_code:
          type:
            - string
            - "null"
          description: Country code as entered, for example `IN`.
        consent_granted:
          type: boolean
          description: "Whether the contact has consented to be called. When the workspace requires consent (a console compliance setting), calls to a contact without consent are refused. Setting this through the API records that consent was given; only set it when it really was. Consent is never recorded on a contact that is on the do-not-call list: it stays `false` there, and removing the entry does not restore it."
        do_not_call:
          type: boolean
          description: "True when the contact's number is on the do-not-call list. Read-only here: manage it with the do-not-call endpoints. Adding a number to the list also withdraws the contact's consent."
        custom_fields:
          type: object
          description: Values of the workspace's custom fields for this contact, by field name. Fields are defined in the console.
          additionalProperties:
            type: string
        created_at:
          type:
            - string
            - "null"
          format: date-time
          description: When the contact was created. Null for some contacts created before this was recorded.
    ContactCreateRequest:
      type: object
      description: Create a contact.
      additionalProperties: false
      required:
        - phone_number
      properties:
        phone_number:
          type: string
          description: The contact's number in E.164 format.
          format: e164
        name:
          type: string
          description: Display name.
          minLength: 1
          maxLength: 200
        language:
          type: string
          description: Preferred language.
          maxLength: 50
        country_code:
          type: string
          description: Country code, for example `IN`.
          minLength: 2
          maxLength: 10
        consent_granted:
          type: boolean
          description: Set to true only when the person has consented to be called. Recorded with the time and the API as its source.
          default: false
        custom_fields:
          $ref: "#/components/schemas/CustomFieldValues"
    ContactList:
      description: A page of contacts, newest first.
      allOf:
        - $ref: "#/components/schemas/ListMeta"
        - type: object
          description: The contacts.
          required:
            - data
          properties:
            data:
              type: array
              description: Contacts on this page.
              items:
                $ref: "#/components/schemas/Contact"
      unevaluatedProperties: false
    ContactUpdateRequest:
      type: object
      description: Fields to change. Omitted fields are left as they are.
      additionalProperties: false
      minProperties: 1
      properties:
        phone_number:
          type: string
          description: New number in E.164 format. Must not belong to another contact.
          format: e164
        name:
          type:
            - string
            - "null"
          description: Display name. Null clears it.
          maxLength: 200
        language:
          type:
            - string
            - "null"
          description: Preferred language. Null clears it.
          maxLength: 50
        country_code:
          type:
            - string
            - "null"
          description: Country code. Null clears it.
          maxLength: 10
        consent_granted:
          type: boolean
          description: True records that consent was given; false records that it was withdrawn.
        custom_fields:
          $ref: "#/components/schemas/CustomFieldValues"
    ContactUpsertRequest:
      type: object
      description: Create the contact with this phone number, or update it if it exists. Matching is by phone number in the same way the do-not-call check matches numbers.
      additionalProperties: false
      required:
        - phone_number
      properties:
        phone_number:
          type: string
          description: The contact's number in E.164 format. Identifies the contact.
          format: e164
        name:
          type:
            - string
            - "null"
          description: Display name. Null clears it.
          maxLength: 200
        language:
          type:
            - string
            - "null"
          description: Preferred language. Null clears it.
          maxLength: 50
        country_code:
          type:
            - string
            - "null"
          description: Country code. Null clears it.
          maxLength: 10
        consent_granted:
          type: boolean
          description: Set to true only when the person has consented to be called; false records withdrawal. Omit to leave unchanged.
        custom_fields:
          $ref: "#/components/schemas/CustomFieldValues"
    CustomFieldValues:
      type: object
      description: Custom field values by field name. Each key must be a custom field defined in the console; an unknown name is `422 custom_field_not_found`. Values are strings up to 500 characters. On update, a null value clears that field and omitted fields are left unchanged.
      maxProperties: 100
      propertyNames:
        minLength: 1
        maxLength: 64
      additionalProperties:
        type:
          - string
          - "null"
        maxLength: 500
    DeletedObject:
      type: object
      description: Returned by a successful delete. The object no longer exists.
      additionalProperties: false
      required:
        - id
        - object
        - livemode
        - deleted
      properties:
        id:
          type: string
          description: Id of the deleted object.
        object:
          type: string
          description: Type of the deleted object, for example `contact`.
        livemode:
          type: boolean
          description: "`true` for live mode, `false` for test mode."
        deleted:
          type: boolean
          description: Always `true`.
          const: true
    DncEntry:
      type: object
      description: "A number on the workspace do-not-call list. When it is checked, in both modes: every POST /v1/calls (`422 dnc_listed`), every campaign start (the number is left out) and every resume (the resume is refused while a remaining recipient is listed). A campaign that is already running is not screened again: pause and resume it, or stop it. Matching ignores formatting: a number matches by its digits, and by its last ten digits when both numbers have at least ten."
      additionalProperties: false
      required:
        - id
        - object
        - livemode
        - phone_number
        - contact_id
        - created_at
      properties:
        id:
          type: string
          description: Entry id (`dnc_...`).
          pattern: ^dnc_[A-Za-z0-9_-]{1,60}$
        object:
          type: string
          const: dnc_entry
          description: Always `dnc_entry`.
        livemode:
          type: boolean
          description: Mode of the entry. Test-mode entries apply only to test-mode calls.
        phone_number:
          type: string
          description: The number.
        contact_id:
          type:
            - string
            - "null"
          description: The contact with this number, if there is one.
        created_at:
          type:
            - string
            - "null"
          format: date-time
          description: When the number was added to the list. Recorded in test mode; null in live mode, where the time is not stored yet.
    DncEntryCreateRequest:
      type: object
      description: Add a number to the do-not-call list.
      additionalProperties: false
      required:
        - phone_number
      properties:
        phone_number:
          type: string
          description: The number in E.164 format.
          format: e164
    DncEntryList:
      description: A page of do-not-call entries, newest first.
      allOf:
        - $ref: "#/components/schemas/ListMeta"
        - type: object
          description: The entries.
          required:
            - data
          properties:
            data:
              type: array
              description: Entries on this page.
              items:
                $ref: "#/components/schemas/DncEntry"
      unevaluatedProperties: false
    Error:
      type: object
      description: The error envelope. Every non-2xx response has this shape. Branch on `error.code` (stable) and `error.retry`; never parse `error.message`, which is written for people and may change.
      additionalProperties: false
      required:
        - error
      properties:
        error:
          type: object
          description: The error.
          additionalProperties: false
          required:
            - code
            - message
            - details
            - request_id
            - retry
            - doc_url
          properties:
            code:
              type: string
              description: "Stable machine-readable error code. The full list, with causes and fixes, is in the error reference. Open enum: new codes may be added."
              pattern: ^[a-z][a-z0-9_]*$
              examples:
                - agent_not_ready
            message:
              type: string
              description: Human-readable explanation. Safe to show to an operator; never parse it.
            details:
              type: object
              description: Extra structured facts for this code, documented per code in the error reference. Always an object; `{}` when the code carries no details.
              additionalProperties: true
            request_id:
              type: string
              description: The id of this request (same as the `X-Request-Id` header). Quote it to support.
              pattern: ^req_[a-z2-7]{24}$
            retry:
              type: string
              description: "Whether to retry. `no`: change the request or configuration first. `yes`: retry with exponential backoff; for a POST or DELETE reuse the same Idempotency-Key if you sent one, otherwise check the state with a GET first (a blind retry can repeat the action). `after`: retry after the number of seconds in the `Retry-After` header."
              enum:
                - no
                - yes
                - after
            doc_url:
              type: string
              format: uri
              description: Link to this code's page in the error reference.
    EventBase:
      type: object
      description: Fields every event has. An event is delivered as the JSON body of a POST to your endpoint, signed with the `RelationsAI-Signature` header.
      required:
        - id
        - object
        - type
        - created_at
        - livemode
        - api_version
        - data
      properties:
        id:
          type: string
          description: Event id (`evt_...`). The same event can be delivered more than once; use this to discard duplicates.
          pattern: ^evt_[A-Za-z0-9_-]{1,60}$
        object:
          type: string
          const: event
          description: Always `event`.
        type:
          $ref: "#/components/schemas/WebhookEventType"
        created_at:
          type: string
          format: date-time
          description: When the event happened.
        livemode:
          type: boolean
          description: Mode of the event.
        api_version:
          type: string
          description: Version of the payload format, a date. Today `2026-10-21`.
    ExtractedField:
      type: object
      description: One extracted field.
      additionalProperties: false
      required:
        - name
        - type
        - state
        - value
      properties:
        name:
          type: string
          description: Field name as configured on the agent.
        type:
          type: string
          description: Declared type of the field, for example `string`, `number`, `boolean`. Open enum.
        state:
          type: string
          description: "`ready`, `pending`, `absent` (not mentioned in the call) or `failed`. Open enum."
          enum:
            - pending
            - ready
            - absent
            - failed
        value:
          description: The extracted value, typed per `type`. Null unless `state` is `ready`.
          type:
            - string
            - number
            - integer
            - boolean
            - "null"
    ListMeta:
      type: object
      description: Fields shared by every list response. Lists are newest first unless an operation says otherwise.
      required:
        - object
        - has_more
        - next_cursor
      properties:
        object:
          type: string
          const: list
          description: Always `list`.
        has_more:
          type: boolean
          description: True when more objects exist after this page.
        next_cursor:
          type:
            - string
            - "null"
          description: Pass as `cursor` (with the same filters) to fetch the next page. Null on the last page.
    Metadata:
      type: object
      description: Your own key-value data, stored with the object and returned as sent. Up to 16 keys; keys up to 40 characters (letters, digits, `_`, `-`, `.`), values strings up to 500 characters. Never sent to the person called and never used by the agent. Do not put secrets here.
      maxProperties: 16
      propertyNames:
        pattern: ^[A-Za-z0-9_.-]{1,40}$
      additionalProperties:
        type: string
        maxLength: 500
    Money:
      type: object
      description: "An amount of money as charged to your workspace, in the currency's minor unit (for INR, paise: `1250` is ₹12.50)."
      additionalProperties: false
      required:
        - amount
        - currency
      properties:
        amount:
          type: integer
          description: Amount in the minor unit of `currency`. Never negative.
          minimum: 0
        currency:
          type: string
          description: ISO 4217 currency code. Open enum; today always `INR`.
          pattern: ^[A-Z]{3}$
          examples:
            - INR
    MoneyInput:
      type: object
      description: An amount of money in the currency's minor unit. The currency must be the workspace currency.
      additionalProperties: false
      required:
        - amount
        - currency
      properties:
        amount:
          type: integer
          description: Amount in the minor unit of `currency` (for INR, paise). At least 1.
          minimum: 1
          maximum: 100000000000
        currency:
          type: string
          description: ISO 4217 code. Must be `INR` today.
          enum:
            - INR
    PhoneNumber:
      type: object
      description: A phone number your workspace can call from or be called on. Numbers are added and assigned to agents in the console. An outbound call shows the caller number chosen for it; by default that is the number assigned to the agent for outbound calls.
      additionalProperties: false
      required:
        - id
        - object
        - livemode
        - number
        - label
        - status
        - capabilities
        - inbound_agent_id
        - outbound_agent_ids
        - sample
      properties:
        id:
          type: string
          description: Phone number id (`pn_...`).
          pattern: ^pn_[A-Za-z0-9_-]{1,61}$
        object:
          type: string
          const: phone_number
          description: Always `phone_number`.
        livemode:
          type: boolean
          description: Mode of the key that read it. Numbers are shared configuration, readable in both modes.
        number:
          type: string
          description: The number in E.164 format.
          pattern: ^\+[1-9][0-9]{7,14}$
        label:
          type:
            - string
            - "null"
          description: Label given in the console, if any.
        status:
          type: string
          description: "`active` numbers can be used. `pending` numbers are still being set up. Open enum."
          enum:
            - active
            - pending
            - unknown
        capabilities:
          type: object
          description: What the number supports.
          additionalProperties: false
          required:
            - outbound
            - inbound
          properties:
            outbound:
              type: boolean
              description: Can place outbound calls.
            inbound:
              type: boolean
              description: Can receive inbound calls.
        inbound_agent_id:
          type:
            - string
            - "null"
          description: The agent of this workspace that answers calls to this number, if any.
        outbound_agent_ids:
          type: array
          description: Agents of this workspace that call from this number.
          items:
            type: string
        sample:
          type: boolean
          description: True only for the built-in sample number that exists in test mode.
    PhoneNumberList:
      description: A page of phone numbers.
      allOf:
        - $ref: "#/components/schemas/ListMeta"
        - type: object
          description: The phone numbers.
          required:
            - data
          properties:
            data:
              type: array
              description: Phone numbers on this page.
              items:
                $ref: "#/components/schemas/PhoneNumber"
      unevaluatedProperties: false
    RateLimitClass:
      type: object
      description: One rate-limit class. Null means that dimension is not limited separately.
      additionalProperties: false
      required:
        - per_key_per_minute
        - per_workspace_per_minute
      properties:
        per_key_per_minute:
          type:
            - integer
            - "null"
          description: Requests per minute allowed for one key.
          minimum: 1
        per_workspace_per_minute:
          type:
            - integer
            - "null"
          description: Requests per minute allowed across all keys of the workspace in this mode.
          minimum: 1
    TranscriptTurn:
      type: object
      description: One turn of the conversation.
      additionalProperties: false
      required:
        - index
        - speaker
        - text
        - start_ms
        - end_ms
      properties:
        index:
          type: integer
          description: Position of the turn, from 0.
          minimum: 0
        speaker:
          type: string
          description: "`agent` or `caller` (the person called). Open enum."
          enum:
            - agent
            - caller
        text:
          type: string
          description: What was said.
        start_ms:
          type:
            - integer
            - "null"
          description: Start of the turn in milliseconds from the start of the call, when known.
          minimum: 0
        end_ms:
          type:
            - integer
            - "null"
          description: End of the turn in milliseconds from the start of the call, when known.
          minimum: 0
    WebhookDelivery:
      type: object
      description: One event's delivery to one endpoint, with its attempts so far.
      additionalProperties: false
      required:
        - id
        - object
        - livemode
        - webhook_endpoint_id
        - event_id
        - event_type
        - status
        - attempts
        - last_attempt_at
        - next_attempt_at
        - response_status
        - duration_ms
        - error
        - created_at
      properties:
        id:
          type: string
          description: Delivery id (`wd_...`).
          pattern: ^wd_[A-Za-z0-9_-]{1,61}$
        object:
          type: string
          const: webhook_delivery
          description: Always `webhook_delivery`.
        livemode:
          type: boolean
          description: Mode of the event.
        webhook_endpoint_id:
          type: string
          description: The endpoint.
        event_id:
          type: string
          description: The event delivered (`evt_...`). Also sent as the `RelationsAI-Event-Id` header.
        event_type:
          $ref: "#/components/schemas/WebhookEventType"
        status:
          type: string
          description: "`pending` (first attempt not made yet), `retrying` (failed, another attempt is scheduled), `succeeded` (your server answered 2xx), `failed` (every attempt failed). Open enum."
          enum:
            - pending
            - retrying
            - succeeded
            - failed
        attempts:
          type: integer
          description: Attempts made so far.
          minimum: 0
        last_attempt_at:
          type:
            - string
            - "null"
          format: date-time
          description: When the last attempt was made.
        next_attempt_at:
          type:
            - string
            - "null"
          format: date-time
          description: When the next attempt is scheduled, if any.
        response_status:
          type:
            - integer
            - "null"
          description: HTTP status of your server's last answer, if it answered.
        duration_ms:
          type:
            - integer
            - "null"
          description: How long the last attempt took.
          minimum: 0
        error:
          type:
            - string
            - "null"
          description: "Why the last attempt failed: `timeout` (no answer in 10 seconds), `connection_failed` (including a host name that did not resolve in time), `tls_error`, `blocked_destination` (the URL resolved to a non-public address), `http_error` (a non-2xx answer), `signing_failed` (RelationsAI could not sign the delivery; nothing was sent, the attempt still counts, and the delivery fails after its last attempt like any other; contact support if it persists). Null if it succeeded. Open enum."
          enum:
            - timeout
            - connection_failed
            - tls_error
            - blocked_destination
            - http_error
            - signing_failed
            - null
        created_at:
          type: string
          format: date-time
          description: When the delivery was created.
    WebhookDeliveryList:
      description: A page of deliveries, newest first.
      allOf:
        - $ref: "#/components/schemas/ListMeta"
        - type: object
          description: The deliveries.
          required:
            - data
          properties:
            data:
              type: array
              description: Deliveries on this page.
              items:
                $ref: "#/components/schemas/WebhookDelivery"
      unevaluatedProperties: false
    WebhookEndpoint:
      type: object
      description: A URL on your server that receives signed event notifications for one mode. Deliveries are at-least-once and not ordered; use the event `id` to discard duplicates and the resource's own timestamps or status to discard stale updates.
      required:
        - id
        - object
        - livemode
        - url
        - description
        - events
        - status
        - secret_last4
        - created_at
        - updated_at
        - last_delivery
      properties:
        id:
          type: string
          description: Endpoint id (`we_...`).
          pattern: ^we_[A-Za-z0-9_-]{1,61}$
        object:
          type: string
          const: webhook_endpoint
          description: Always `webhook_endpoint`.
        livemode:
          type: boolean
          description: The endpoint receives events of this mode only.
        url:
          type: string
          format: uri
          description: Where events are delivered.
        description:
          type:
            - string
            - "null"
          description: Your note about the endpoint.
        events:
          type: array
          description: Event types delivered to this endpoint. The test event is delivered on request regardless of this list.
          items:
            $ref: "#/components/schemas/WebhookSubscribableEventType"
        status:
          type: string
          description: "`enabled` endpoints receive deliveries; `disabled` ones do not. Open enum."
          enum:
            - enabled
            - disabled
        secret_last4:
          type: string
          description: Last four characters of the current signing secret, to tell secrets apart.
        created_at:
          type: string
          format: date-time
          description: When the endpoint was created.
        updated_at:
          type: string
          format: date-time
          description: When the endpoint was last changed.
        last_delivery:
          description: The most recent delivery attempt, or null if none yet.
          oneOf:
            - type: object
              description: Summary of the most recent delivery attempt.
              additionalProperties: false
              required:
                - status
                - attempted_at
                - response_status
              properties:
                status:
                  type: string
                  description: Delivery status (see the delivery object).
                attempted_at:
                  type: string
                  format: date-time
                  description: When the attempt was made.
                response_status:
                  type:
                    - integer
                    - "null"
                  description: HTTP status your server answered, if it answered.
            - type: "null"
              description: No delivery yet.
    WebhookEndpointCreateRequest:
      type: object
      description: Create a webhook endpoint in the key's mode.
      additionalProperties: false
      required:
        - url
        - events
      properties:
        url:
          type: string
          format: uri
          description: "Must start with `https://`; any other scheme is refused with 400 `validation_error` (issue `invalid_format`) before the URL is checked. Then: port 443 only, no user name or password, not a RelationsAI host, and the host must resolve only to public internet addresses, otherwise 422 `webhook_url_not_allowed`. Checked when created, when changed, and again on every delivery."
          maxLength: 2048
          pattern: ^https://
        description:
          type: string
          description: Your note about the endpoint.
          maxLength: 500
        events:
          type: array
          description: Event types to deliver. `webhook_endpoint.test` cannot be subscribed to (the test operation always delivers it).
          minItems: 1
          uniqueItems: true
          items:
            $ref: "#/components/schemas/WebhookSubscribableEventType"
    WebhookEndpointList:
      description: A page of webhook endpoints, newest first.
      allOf:
        - $ref: "#/components/schemas/ListMeta"
        - type: object
          description: The endpoints.
          required:
            - data
          properties:
            data:
              type: array
              description: Endpoints on this page.
              items:
                $ref: "#/components/schemas/WebhookEndpoint"
      unevaluatedProperties: false
    WebhookEndpointUpdateRequest:
      type: object
      description: Fields to change. Omitted fields are left as they are.
      additionalProperties: false
      minProperties: 1
      properties:
        url:
          type: string
          format: uri
          description: "Must start with `https://`; any other scheme is refused with 400 `validation_error` (issue `invalid_format`) before the URL is checked. Then: port 443 only, no user name or password, not a RelationsAI host, and the host must resolve only to public internet addresses, otherwise 422 `webhook_url_not_allowed`. Checked when created, when changed, and again on every delivery."
          maxLength: 2048
          pattern: ^https://
        description:
          type:
            - string
            - "null"
          description: Your note about the endpoint. Null clears it.
          maxLength: 500
        events:
          type: array
          description: Event types to deliver. Replaces the current list. `webhook_endpoint.test` cannot be subscribed to (the test operation always delivers it).
          minItems: 1
          uniqueItems: true
          items:
            $ref: "#/components/schemas/WebhookSubscribableEventType"
        status:
          type: string
          description: "`enabled` or `disabled`."
          enum:
            - enabled
            - disabled
    WebhookEndpointWithSecret:
      description: A webhook endpoint together with its signing secret. The secret is shown only in this response; store it now.
      allOf:
        - $ref: "#/components/schemas/WebhookEndpoint"
        - type: object
          description: The secret.
          required:
            - secret
          properties:
            secret:
              type:
                - string
                - "null"
              description: "The signing secret (`whsec_...`), shown only in the first response to the create or rotate request. `null` on an idempotent replay of that request (same Idempotency-Key): the secret is stored only encrypted and is never returned again. If it was lost, rotate the secret."
              pattern: ^whsec_[A-Za-z0-9_-]{16,}$
      unevaluatedProperties: false
    WebhookEventType:
      type: string
      description: An event type. Open enum; new types can be added.
      enum:
        - call.ended
        - call.settled
        - campaign.started
        - campaign.paused
        - campaign.resumed
        - campaign.stopped
        - campaign.completed
        - campaign.failed
        - webhook_endpoint.test
    WebhookSecretRotateRequest:
      type: object
      description: How long the previous secret keeps signing deliveries alongside the new one.
      additionalProperties: false
      required:
        - grace_period_hours
      properties:
        grace_period_hours:
          type: integer
          description: Hours during which every delivery carries two signatures, one per secret, so you can deploy the new secret without dropping events. `0` retires every previous secret immediately (always allowed, also during a grace period). A value above 0 during a running grace period keeps the oldest secret still signing until its original grace end and discards the one in between.
          enum:
            - 0
            - 1
            - 24
            - 168
    WebhookSubscribableEventType:
      type: string
      description: "An event type an endpoint can subscribe to. Open enum; new types can be added. `webhook_endpoint.test` is not in this list: it cannot be subscribed to, and is delivered only by POST /v1/webhook-endpoints/{webhook_endpoint_id}/test, to that endpoint, whatever its subscriptions."
      enum:
        - call.ended
        - call.settled
        - campaign.started
        - campaign.paused
        - campaign.resumed
        - campaign.stopped
        - campaign.completed
        - campaign.failed
    WebhookTestEvent:
      description: A test event sent with POST /v1/webhook-endpoints/{webhook_endpoint_id}/test. `data.object` is the endpoint.
      allOf:
        - $ref: "#/components/schemas/EventBase"
        - type: object
          description: Test event payload.
          properties:
            type:
              type: string
              description: Always `webhook_endpoint.test`.
              const: webhook_endpoint.test
            data:
              type: object
              description: Event data.
              additionalProperties: false
              required:
                - object
              properties:
                object:
                  $ref: "#/components/schemas/WebhookEndpoint"
      unevaluatedProperties: false
    Workspace:
      type: object
      description: The workspace the API key belongs to, the key itself, and what the workspace can do through the API in the key's mode. Call it first to check a key, its scopes and its limits.
      additionalProperties: false
      required:
        - id
        - object
        - livemode
        - name
        - timezone
        - currency
        - api_key
        - capabilities
        - limits
      properties:
        id:
          type: string
          description: Workspace id (`ws_...`).
          pattern: ^ws_[A-Za-z0-9_-]{1,61}$
        object:
          type: string
          const: workspace
          description: Always `workspace`.
        livemode:
          type: boolean
          description: "`true` when the key is a live key, `false` for a test key."
        name:
          type: string
          description: Workspace name as shown in the console.
        timezone:
          type: string
          description: IANA timezone of the workspace. Calling hours (if enabled in the console) are evaluated in it.
          examples:
            - Asia/Kolkata
        currency:
          type: string
          description: Currency calls are charged in (ISO 4217). Open enum; today always `INR`.
          pattern: ^[A-Z]{3}$
        api_key:
          $ref: "#/components/schemas/WorkspaceApiKey"
        capabilities:
          $ref: "#/components/schemas/WorkspaceCapabilities"
        limits:
          $ref: "#/components/schemas/WorkspaceLimits"
    WorkspaceApiKey:
      type: object
      description: The API key this request was authenticated with. The secret itself is never returned.
      additionalProperties: false
      required:
        - id
        - name
        - environment
        - scopes
        - created_at
        - expires_at
      properties:
        id:
          type: string
          description: Key id (`key_...`). Shown in the console next to the key.
          pattern: ^key_[A-Za-z0-9_-]{1,60}$
        name:
          type: string
          description: The name given to the key when it was created.
        environment:
          type: string
          enum:
            - test
            - live
          description: "`test` for `rai_test_` keys, `live` for `rai_live_` keys."
        scopes:
          type: array
          description: "Scopes this key can use right now: the scopes it was created with, limited to what its creator's current role allows."
          items:
            type: string
        created_at:
          type: string
          format: date-time
          description: When the key was created.
        expires_at:
          type:
            - string
            - "null"
          format: date-time
          description: When the key stops working. Null for a test key created without expiry.
    WorkspaceCapabilities:
      type: object
      description: What this workspace can do through the API. A `false` here means the feature is not offered today, so a client can adapt instead of discovering it from errors.
      additionalProperties: false
      required:
        - campaign_pause
        - campaign_resume
        - call_ringing_status
        - live_transcript
        - sentiment_analysis
        - end_call
        - agent_editing
        - inbound_calls
        - webhooks
      properties:
        campaign_pause:
          type: boolean
          description: Running campaigns can be paused.
        campaign_resume:
          type: boolean
          description: Paused campaigns can be resumed (continuing the same run).
        call_ringing_status:
          type: boolean
          description: Calls report a separate `ringing` status. When false, a call goes from `queued` straight to `in_progress` or `ended`.
        live_transcript:
          type: boolean
          description: Transcripts can be read while a call is in progress. When false, transcripts are available after the call ends.
        sentiment_analysis:
          type: boolean
          description: Call analysis includes sentiment. When false, analysis has a summary, extracted fields and the goal outcome only.
        end_call:
          type: boolean
          description: Calls can be hung up through the API.
        agent_editing:
          type: boolean
          description: Agents can be created or edited through the API. When false, use the console.
        inbound_calls:
          type: boolean
          description: Inbound calls appear in the call list.
        webhooks:
          type: boolean
          description: Webhook endpoints can be created and events are delivered.
    WorkspaceLimits:
      type: object
      description: Limits that apply to this key and workspace in the key's mode.
      additionalProperties: false
      required:
        - rate_limits
        - daily_call_limit
        - campaign_max_concurrency
      properties:
        rate_limits:
          type: object
          description: Requests per minute by rate-limit class. Each operation shows its class as `x-rate-limit-class`.
          additionalProperties: false
          required:
            - read
            - write
            - dial
          properties:
            read:
              $ref: "#/components/schemas/RateLimitClass"
            write:
              $ref: "#/components/schemas/RateLimitClass"
            dial:
              $ref: "#/components/schemas/RateLimitClass"
        daily_call_limit:
          type:
            - integer
            - "null"
          description: Calls this workspace may place through the API per UTC day in live mode. Null in test mode, which has no daily cap.
          minimum: 0
        campaign_max_concurrency:
          type: integer
          description: Most simultaneous calls a campaign can run with on the workspace's plan. A higher `concurrency_limit` is lowered to this at start.
          minimum: 1
  securitySchemes:
    ApiKeyAuth:
      type: http
      scheme: bearer
      bearerFormat: rai_test_... or rai_live_...
      description: "An API key created in the console under API & Developers, sent as `Authorization: Bearer <key>`. `rai_test_` keys use test mode and `rai_live_` keys use live mode."
  parameters:
    AgentId:
      name: agent_id
      in: path
      required: true
      description: The agent id (`agent_...`).
      schema:
        type: string
        pattern: ^agent_[A-Za-z0-9_-]{1,58}$
      example: agent_3hT9kQ2mVx7RbN4pLc8Wz1
    CallId:
      name: call_id
      in: path
      required: true
      description: The call id (`call_...`).
      schema:
        type: string
        pattern: ^call_[A-Za-z0-9_-]{1,59}$
      example: call_6Vb3Nm8Qw2Er5Ty9Ui4Op7
    CampaignId:
      name: campaign_id
      in: path
      required: true
      description: The campaign id (`cmp_...`).
      schema:
        type: string
        pattern: ^cmp_[A-Za-z0-9_-]{1,60}$
      example: cmp_2Kd7Fg4Hj9Lz3Xc8Vb5Nm1
    ContactId:
      name: contact_id
      in: path
      required: true
      description: The contact id (`ct_...`).
      schema:
        type: string
        pattern: ^ct_[A-Za-z0-9_-]{1,61}$
      example: ct_8Rw2Tq5Lm9Xc3Vb7Nz4Kp1
    CreatedAfter:
      name: created_after
      in: query
      required: false
      description: Only objects created at or after this time (RFC 3339, UTC).
      schema:
        type: string
        format: date-time
      example: 2026-10-01T00:00:00.000Z
    CreatedBefore:
      name: created_before
      in: query
      required: false
      description: Only objects created before this time (RFC 3339, UTC).
      schema:
        type: string
        format: date-time
      example: 2026-10-22T00:00:00.000Z
    Cursor:
      name: cursor
      in: query
      required: false
      description: The `next_cursor` of the previous page. Send it with exactly the same filters as the request that returned it; a changed filter set is `400 invalid_cursor`.
      schema:
        type: string
        minLength: 1
        maxLength: 512
    DncEntryId:
      name: dnc_entry_id
      in: path
      required: true
      description: The do-not-call entry id (`dnc_...`).
      schema:
        type: string
        pattern: ^dnc_[A-Za-z0-9_-]{1,60}$
      example: dnc_4Ty8Ui2Op6As3Df9Gh7Jk5
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      description: "Optional. A unique key for this operation, 1 to 255 printable ASCII characters with no spaces (a UUID v4 is ideal). With it, a retry of the same request (same key, same body) returns the stored answer and never runs the action twice; reuse the same key for every retry, it is kept for 24 hours. Without it, every request runs: a retry after a timeout can repeat the action, so check the state with a GET before retrying."
      schema:
        type: string
        minLength: 1
        maxLength: 255
        pattern: ^[\x21-\x7E]+$
      example: 5b0b5a3e-7f43-4c55-9d0e-2f1c8e6a4b17
    IfMatch:
      name: If-Match
      in: header
      required: true
      description: "The `ETag` from your most recent read of this resource. The update is refused if the resource has changed since. `*` matches any current version: the update is applied without the concurrency check."
      schema:
        type: string
        minLength: 1
        maxLength: 128
      example: '"c3f1a9e2b7d4"'
    Limit:
      name: limit
      in: query
      required: false
      description: Maximum number of objects to return, from 1 to 100. Defaults to 25.
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 25
      example: 25
    PhoneNumberId:
      name: phone_number_id
      in: path
      required: true
      description: The phone number id (`pn_...`).
      schema:
        type: string
        pattern: ^pn_[A-Za-z0-9_-]{1,61}$
      example: pn_5Lq8Xc2Rk9TzW3mBv7Np4d
    RecordingToken:
      name: recording_token
      in: path
      required: true
      description: The opaque token from a recording `url`. It is the credential for this request.
      schema:
        type: string
        minLength: 16
        maxLength: 512
        pattern: ^[A-Za-z0-9._~-]+$
      example: rec_tok_Y2FsbF82VmIzTm04UXcyRXI1VHk5VWk0T3A3
    WebhookDeliveryId:
      name: webhook_delivery_id
      in: path
      required: true
      description: The webhook delivery id (`wd_...`).
      schema:
        type: string
        pattern: ^wd_[A-Za-z0-9_-]{1,61}$
      example: wd_1Qa5Ws9Ed3Rf7Tg2Yh6Uj4
    WebhookEndpointId:
      name: webhook_endpoint_id
      in: path
      required: true
      description: The webhook endpoint id (`we_...`).
      schema:
        type: string
        pattern: ^we_[A-Za-z0-9_-]{1,61}$
      example: we_9Pl3Ok7Ij2Uh6Yg4Tf8Rd1
  headers:
    ETag:
      description: Version tag of the returned resource. Send it as `If-Match` when you update the resource.
      schema:
        type: string
      example: '"c3f1a9e2b7d4"'
    Idempotent-Replayed:
      description: "`true` when this response is the stored result of an earlier request with the same Idempotency-Key."
      schema:
        type: string
        enum:
          - "true"
      example: "true"
    RateLimit-Limit:
      required: true
      description: Requests allowed in the current one-minute window by the tightest limit that applied to this request (the key's or the workspace's limit for the operation's rate-limit class).
      schema:
        type: integer
        minimum: 0
      example: 600
    RateLimit-Remaining:
      required: true
      description: Requests left in the current window.
      schema:
        type: integer
        minimum: 0
      example: 597
    RateLimit-Reset:
      required: true
      description: Seconds until the current window resets.
      schema:
        type: integer
        minimum: 0
      example: 42
    Retry-After:
      description: Seconds to wait before retrying.
      schema:
        type: integer
        minimum: 1
      example: 30
    X-Request-Id:
      required: true
      description: Unique id of this request (`req_...`). Also in every error body as `request_id`. Quote it to support.
      schema:
        type: string
        pattern: ^req_[a-z2-7]{24}$
      example: req_4k7m2qat5xvz3c6vqnwpbdfh
  examples:
    call_no_answer:
      summary: Not answered (test mode)
      value:
        id: call_9Tg5Yh2Uj8Ik4Ol7Pm3Nb6
        object: call
        livemode: false
        status: ended
        outcome: no_answer
        end_reason: no_answer
        direction: outbound
        source: api
        agent_id: agent_1ZltiWzxrXmMprGD6q63
        campaign_id: null
        phone_number_id: pn_6Vhm3sFrB5UpmXAnsvmDu
        from: "+12025550150"
        to: "+12025550101"
        metadata: {}
        created_at: 2026-10-21T09:35:00.000Z
        ended_at: 2026-10-21T09:35:18.000Z
        duration_seconds: 0
        billable_minutes: 0
        cost:
          amount: 0
          currency: INR
        artifacts:
          transcript:
            state: absent
          recording:
            state: absent
          analysis:
            state: absent
        settled: true
        settled_at: 2026-10-21T09:35:30.000Z
    call_queued:
      summary: Accepted and queued (test mode)
      value:
        id: call_6Vb3Nm8Qw2Er5Ty9Ui4Op7
        object: call
        livemode: false
        status: queued
        outcome: null
        end_reason: null
        direction: outbound
        source: api
        agent_id: agent_1ZltiWzxrXmMprGD6q63
        campaign_id: null
        phone_number_id: pn_6Vhm3sFrB5UpmXAnsvmDu
        from: "+12025550150"
        to: "+12025550100"
        metadata:
          crm_lead_id: L-20931
        created_at: 2026-10-21T09:30:00.000Z
        ended_at: null
        duration_seconds: null
        billable_minutes: null
        cost: null
        artifacts:
          transcript:
            state: pending
          recording:
            state: pending
          analysis:
            state: pending
        settled: false
        settled_at: null
    call_settled:
      summary: Ended and settled (live mode)
      value:
        id: call_2Hd8Ks4Lq7Mw3Nx9Pz5Rc1
        object: call
        livemode: true
        status: ended
        outcome: completed
        end_reason: hangup
        direction: outbound
        source: api
        agent_id: agent_3hT9kQ2mVx7RbN4pLc8Wz1
        campaign_id: null
        phone_number_id: pn_5Lq8Xc2Rk9TzW3mBv7Np4d
        from: "+918000000001"
        to: "+919000000001"
        metadata:
          crm_lead_id: L-20931
        created_at: 2026-10-21T09:30:00.000Z
        ended_at: 2026-10-21T09:32:14.000Z
        duration_seconds: 118
        billable_minutes: 2
        cost:
          amount: 600
          currency: INR
        artifacts:
          transcript:
            state: ready
          recording:
            state: ready
          analysis:
            state: ready
        settled: true
        settled_at: 2026-10-21T09:41:02.000Z
    campaign_draft:
      summary: A draft campaign (test mode)
      value:
        id: cmp_2Kd7Fg4Hj9Lz3Xc8Vb5Nm1
        object: campaign
        livemode: false
        name: November renewals
        agent_id: agent_1ZltiWzxrXmMprGD6q63
        status: draft
        capabilities:
          start: true
          pause: false
          resume: false
          stop: true
          update: true
          add_recipients: true
        concurrency_limit: 5
        budget_cap:
          amount: 500000
          currency: INR
        recipient_count: 2
        progress:
          calls: 0
          connected: 0
          no_answer: 0
          failed: 0
          in_progress: 0
        spend:
          amount: 0
          currency: INR
        run_number: 0
        dnc_screening: enforced
        created_at: 2026-10-21T08:00:00.000Z
    campaign_paused:
      summary: A paused campaign (live mode)
      value:
        id: cmp_7Wq3Er9Ty2Ui5Op8As4Df6
        object: campaign
        livemode: true
        name: November renewals
        agent_id: agent_3hT9kQ2mVx7RbN4pLc8Wz1
        status: paused
        capabilities:
          start: true
          pause: false
          resume: true
          stop: true
          update: true
          add_recipients: false
        concurrency_limit: 5
        budget_cap:
          amount: 500000
          currency: INR
        recipient_count: 1200
        progress:
          calls: 702
          connected: 451
          no_answer: 210
          failed: 41
          in_progress: 0
        spend:
          amount: 270600
          currency: INR
        run_number: 1
        dnc_screening: enforced
        created_at: 2026-10-20T08:00:00.000Z
    campaign_running:
      summary: A running campaign (live mode)
      value:
        id: cmp_7Wq3Er9Ty2Ui5Op8As4Df6
        object: campaign
        livemode: true
        name: November renewals
        agent_id: agent_3hT9kQ2mVx7RbN4pLc8Wz1
        status: running
        capabilities:
          start: false
          pause: true
          resume: false
          stop: true
          update: false
          add_recipients: false
        concurrency_limit: 5
        budget_cap:
          amount: 500000
          currency: INR
        recipient_count: 1200
        progress:
          calls: 640
          connected: 410
          no_answer: 190
          failed: 35
          in_progress: 5
        spend:
          amount: 246000
          currency: INR
        run_number: 1
        dnc_screening: enforced
        created_at: 2026-10-20T08:00:00.000Z
    campaign_started_test:
      summary: Started (test mode)
      value:
        id: cmp_2Kd7Fg4Hj9Lz3Xc8Vb5Nm1
        object: campaign
        livemode: false
        name: November renewals
        agent_id: agent_1ZltiWzxrXmMprGD6q63
        status: running
        capabilities:
          start: false
          pause: true
          resume: false
          stop: true
          update: false
          add_recipients: false
        concurrency_limit: 5
        budget_cap:
          amount: 500000
          currency: INR
        recipient_count: 2
        progress:
          calls: 0
          connected: 0
          no_answer: 0
          failed: 0
          in_progress: 0
        spend:
          amount: 0
          currency: INR
        run_number: 1
        dnc_screening: enforced
        created_at: 2026-10-21T08:00:00.000Z
    campaign_stopped:
      summary: A stopped campaign (live mode)
      value:
        id: cmp_7Wq3Er9Ty2Ui5Op8As4Df6
        object: campaign
        livemode: true
        name: November renewals
        agent_id: agent_3hT9kQ2mVx7RbN4pLc8Wz1
        status: stopped
        capabilities:
          start: true
          pause: false
          resume: false
          stop: false
          update: true
          add_recipients: false
        concurrency_limit: 5
        budget_cap:
          amount: 500000
          currency: INR
        recipient_count: 1200
        progress:
          calls: 702
          connected: 451
          no_answer: 210
          failed: 41
          in_progress: 0
        spend:
          amount: 270600
          currency: INR
        run_number: 1
        dnc_screening: enforced
        created_at: 2026-10-20T08:00:00.000Z
    contact:
      summary: A contact with consent (test mode)
      value:
        id: ct_8Rw2Tq5Lm9Xc3Vb7Nz4Kp1
        object: contact
        livemode: false
        phone_number: "+12025550100"
        name: Asha Rao
        language: en
        country_code: US
        consent_granted: true
        do_not_call: false
        custom_fields:
          policy_number: PN-55012
          due_date: 2026-11-05
        created_at: 2026-10-21T08:30:00.000Z
    contact_live:
      summary: A contact (live mode)
      value:
        id: ct_2Mh7Yd4Qs8Fv1Kc6Bx9Tn3
        object: contact
        livemode: true
        phone_number: "+919000000001"
        name: Asha Rao
        language: hi
        country_code: IN
        consent_granted: true
        do_not_call: false
        custom_fields:
          policy_number: PN-55012
        created_at: 2026-10-19T11:02:00.000Z
    delivery_pending:
      summary: A delivery about to be attempted
      value:
        id: wd_8Ik2Ol5Pm9Nb3Vc6Xz1As4
        object: webhook_delivery
        livemode: false
        webhook_endpoint_id: we_9Pl3Ok7Ij2Uh6Yg4Tf8Rd1
        event_id: evt_3Df7Gh1Jk5Lz9Xc2Vb6Nm8
        event_type: webhook_endpoint.test
        status: pending
        attempts: 0
        last_attempt_at: null
        next_attempt_at: 2026-10-21T09:45:00.000Z
        response_status: null
        duration_ms: null
        error: null
        created_at: 2026-10-21T09:45:00.000Z
    endpoint:
      summary: An enabled endpoint
      value:
        id: we_9Pl3Ok7Ij2Uh6Yg4Tf8Rd1
        object: webhook_endpoint
        livemode: false
        url: https://example.com/webhooks/relationsai
        description: CRM sync (test)
        events:
          - call.ended
          - call.settled
          - campaign.completed
        status: enabled
        secret_last4: x9Qa
        created_at: 2026-10-21T08:00:00.000Z
        updated_at: 2026-10-21T08:00:00.000Z
        last_delivery:
          status: succeeded
          attempted_at: 2026-10-21T09:31:02.000Z
          response_status: 200
    endpoint_with_secret:
      summary: Created, with its secret
      value:
        id: we_9Pl3Ok7Ij2Uh6Yg4Tf8Rd1
        object: webhook_endpoint
        livemode: false
        url: https://example.com/webhooks/relationsai
        description: CRM sync (test)
        events:
          - call.ended
          - call.settled
          - campaign.completed
        status: enabled
        secret_last4: x9Qa
        created_at: 2026-10-21T08:00:00.000Z
        updated_at: 2026-10-21T08:00:00.000Z
        last_delivery: null
        secret: whsec_test_7c2f9a4b1e8d3c6a5f0b2e9d4c7a1x9Qa
    error_account_inactive:
      summary: Workspace account inactive
      value:
        error:
          code: account_inactive
          message: This workspace cannot place calls because its account is not active.
          details:
            reason: trial_expired
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/account_inactive
    error_agent_not_ready:
      summary: Agent not ready to call
      value:
        error:
          code: agent_not_ready
          message: This agent cannot place calls right now.
          details:
            agent_id: agent_3hT9kQ2mVx7RbN4pLc8Wz1
            reasons:
              - agent_not_published
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/agent_not_ready
    error_api_access_not_enabled:
      summary: API access not enabled
      value:
        error:
          code: api_access_not_enabled
          message: API access is not enabled for this workspace.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/api_access_not_enabled
    error_api_key_expired:
      summary: API key expired
      value:
        error:
          code: api_key_expired
          message: This API key has expired.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/api_key_expired
    error_api_key_revoked:
      summary: API key revoked
      value:
        error:
          code: api_key_revoked
          message: This API key has been revoked.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/api_key_revoked
    error_authentication_required:
      summary: Authentication required
      value:
        error:
          code: authentication_required
          message: Send your API key as a Bearer token in the Authorization header.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/authentication_required
    error_call_not_accepted:
      summary: Call not accepted
      value:
        error:
          code: call_not_accepted
          message: The call could not be placed. Nothing was dialled and nothing was charged.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/call_not_accepted
    error_calling_capacity_reached:
      summary: Calling capacity reached
      value:
        error:
          code: calling_capacity_reached
          message: Too many calls are being started right now. Retry after the number of seconds in the Retry-After header.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: after
          doc_url: https://docs.relationsai.com/errors/calling_capacity_reached
    error_calling_not_configured:
      summary: Calling not set up
      value:
        error:
          code: calling_not_configured
          message: Calling is not set up for this workspace yet.
          details:
            reason: no_outbound_assignment
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/calling_not_configured
    error_campaign_budget_reached:
      summary: Campaign budget reached
      value:
        error:
          code: campaign_budget_reached
          message: This campaign has reached its budget cap.
          details:
            budget_cap:
              amount: 500000
              currency: INR
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/campaign_budget_reached
    error_campaign_dnc_override_enabled:
      summary: Campaign calls numbers on the do-not-call list
      value:
        error:
          code: campaign_dnc_override_enabled
          message: This campaign is set in the console to also call contacts on the do-not-call list, so it cannot be started or resumed through the API.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/campaign_dnc_override_enabled
    error_campaign_has_no_recipients:
      summary: Campaign has no recipients
      value:
        error:
          code: campaign_has_no_recipients
          message: This campaign has no recipients to call.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/campaign_has_no_recipients
    error_campaign_not_resumable:
      summary: Campaign cannot be resumed
      value:
        error:
          code: campaign_not_resumable
          message: This campaign cannot be resumed. Start it again to begin a new run.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/campaign_not_resumable
    error_campaign_operation_in_progress:
      summary: Another start or resume is in progress
      value:
        error:
          code: campaign_operation_in_progress
          message: This campaign is being started or resumed by another request. Retry shortly.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: after
          doc_url: https://docs.relationsai.com/errors/campaign_operation_in_progress
    error_campaign_outcome_unknown:
      summary: Campaign start or resume not confirmed
      value:
        error:
          code: campaign_outcome_unknown
          message: The request was sent but its outcome is not confirmed yet. Check the campaign before trying again.
          details:
            action: start
            needs_support: false
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: after
          doc_url: https://docs.relationsai.com/errors/campaign_outcome_unknown
    error_campaign_pause_not_confirmed:
      summary: Pause not confirmed
      value:
        error:
          code: campaign_pause_not_confirmed
          message: The pause was requested but not confirmed. The campaign may still be dialling.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: yes
          doc_url: https://docs.relationsai.com/errors/campaign_pause_not_confirmed
    error_campaign_recipients_blocked:
      summary: Recipients now blocked by compliance
      value:
        error:
          code: campaign_recipients_blocked
          message: Some recipients of this campaign are now blocked by compliance rules, so it was not resumed.
          details:
            blocked_total: 2
            by_reason:
              dnc_listed: 1
              consent_required: 1
            contact_ids:
              - ct_8Rw2Tq5Lm9Xc3Vb7Nz4Kp1
              - ct_2Mh7Yd4Qs8Fv1Kc6Bx9Tn3
            contact_ids_truncated: false
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/campaign_recipients_blocked
    error_campaign_recipients_suppressed:
      summary: Every recipient is suppressed
      value:
        error:
          code: campaign_recipients_suppressed
          message: Every recipient of this campaign is blocked by your compliance settings. Nothing was dialled.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/campaign_recipients_suppressed
    error_campaign_recipients_unavailable:
      summary: Recipients could not be checked
      value:
        error:
          code: campaign_recipients_unavailable
          message: The campaign's recipients could not be read for screening right now, so nothing was dialled.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: after
          doc_url: https://docs.relationsai.com/errors/campaign_recipients_unavailable
    error_campaign_state_conflict:
      summary: Campaign is in the wrong state
      value:
        error:
          code: campaign_state_conflict
          message: This action is not allowed in the campaign's current status.
          details:
            status: running
            action: update
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/campaign_state_conflict
    error_campaign_too_large:
      summary: Campaign too large
      value:
        error:
          code: campaign_too_large
          message: This campaign has too many recipients to start in one run.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/campaign_too_large
    error_consent_required:
      summary: Consent required
      value:
        error:
          code: consent_required
          message: This contact has no recorded consent, and consent is required for calls in this workspace.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/consent_required
    error_contact_already_exists:
      summary: Contact already exists
      value:
        error:
          code: contact_already_exists
          message: A contact with this phone number already exists.
          details:
            contact_id: ct_8Rw2Tq5Lm9Xc3Vb7Nz4Kp1
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/contact_already_exists
    error_contact_daily_limit_reached:
      summary: Daily call limit for this number reached
      value:
        error:
          code: contact_daily_limit_reached
          message: This number has already been called the maximum number of times allowed in 24 hours.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/contact_daily_limit_reached
    error_contact_limit_reached:
      summary: Contact limit reached
      value:
        error:
          code: contact_limit_reached
          message: No more contacts can be created right now.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/contact_limit_reached
    error_contact_on_dnc_list:
      summary: Contact is on the do-not-call list
      value:
        error:
          code: contact_on_dnc_list
          message: This contact is on the do-not-call list. Remove its do-not-call entry before deleting it.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/contact_on_dnc_list
    error_custom_field_not_found:
      summary: Custom field not found
      value:
        error:
          code: custom_field_not_found
          message: This custom field does not exist in the workspace.
          details:
            field: policy_numbr
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/custom_field_not_found
    error_daily_call_limit_reached:
      summary: Daily call limit reached
      value:
        error:
          code: daily_call_limit_reached
          message: This workspace has reached its daily limit of calls placed through the API.
          details:
            limit: 500
            requested: 120
            remaining: 37
            resets_at: 2026-10-22T00:00:00.000Z
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: after
          doc_url: https://docs.relationsai.com/errors/daily_call_limit_reached
    error_dnc_listed:
      summary: Number on the do-not-call list
      value:
        error:
          code: dnc_listed
          message: This number is on your do-not-call list, so the call was not placed.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/dnc_listed
    error_idempotency_key_in_progress:
      summary: Request with this Idempotency-Key in progress
      value:
        error:
          code: idempotency_key_in_progress
          message: A request with this Idempotency-Key is still being processed.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: after
          doc_url: https://docs.relationsai.com/errors/idempotency_key_in_progress
    error_idempotency_key_reused:
      summary: Idempotency-Key reused
      value:
        error:
          code: idempotency_key_reused
          message: This Idempotency-Key was already used with a different request.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/idempotency_key_reused
    error_idempotency_outcome_unknown:
      summary: Outcome of the earlier request unknown
      value:
        error:
          code: idempotency_outcome_unknown
          message: An earlier request with this Idempotency-Key did not finish, and its outcome is unknown.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/idempotency_outcome_unknown
    error_insufficient_balance:
      summary: Insufficient balance
      value:
        error:
          code: insufficient_balance
          message: The workspace balance is too low to start this call. Top up to continue.
          details:
            balance:
              amount: 250
              currency: INR
            required:
              amount: 600
              currency: INR
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/insufficient_balance
    error_insufficient_permissions:
      summary: Key creator lacks permission
      value:
        error:
          code: insufficient_permissions
          message: The member who created this API key no longer has permission for this operation.
          details:
            required_scopes:
              - campaigns:write
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/insufficient_permissions
    error_insufficient_scope:
      summary: Insufficient scope
      value:
        error:
          code: insufficient_scope
          message: This API key does not have the scope this operation requires.
          details:
            required_scopes:
              - calls:write
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/insufficient_scope
    error_internal_error:
      summary: Internal error
      value:
        error:
          code: internal_error
          message: Something went wrong on our side.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: yes
          doc_url: https://docs.relationsai.com/errors/internal_error
    error_invalid_api_key:
      summary: Invalid API key
      value:
        error:
          code: invalid_api_key
          message: The API key is not valid.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/invalid_api_key
    error_invalid_cursor:
      summary: Invalid pagination cursor
      value:
        error:
          code: invalid_cursor
          message: The pagination cursor is invalid or does not match these filters.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/invalid_cursor
    error_invalid_idempotency_key:
      summary: Invalid Idempotency-Key
      value:
        error:
          code: invalid_idempotency_key
          message: The Idempotency-Key header must be 1 to 255 printable ASCII characters with no spaces.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/invalid_idempotency_key
    error_invalid_json:
      summary: Invalid JSON body
      value:
        error:
          code: invalid_json
          message: The request body is not valid JSON.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/invalid_json
    error_invalid_phone_number:
      summary: Invalid phone number
      value:
        error:
          code: invalid_phone_number
          message: The phone number is not a valid E.164 number.
          details:
            field: to
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/invalid_phone_number
    error_ip_not_allowed:
      summary: IP address not allowed
      value:
        error:
          code: ip_not_allowed
          message: Requests from this IP address are not allowed for this workspace.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/ip_not_allowed
    error_legacy_api_key_not_supported:
      summary: Legacy API key not supported
      value:
        error:
          code: legacy_api_key_not_supported
          message: Legacy API keys cannot be used with the v1 API. Create a scoped key in the console.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/legacy_api_key_not_supported
    error_live_key_not_allowed_in_browser:
      summary: Live key used from a browser
      value:
        error:
          code: live_key_not_allowed_in_browser
          message: Live API keys cannot be used from a browser. Use a test key, or call the API from your server.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/live_key_not_allowed_in_browser
    error_media_link_expired:
      summary: Recording link expired
      value:
        error:
          code: media_link_expired
          message: This recording link has expired. Retrieve the recording again for a new link.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/media_link_expired
    error_outside_calling_hours:
      summary: Outside calling hours
      value:
        error:
          code: outside_calling_hours
          message: This is outside the permitted calling window for this workspace. Nothing was dialled.
          details:
            window: 09:00-21:00
            timezone: Asia/Kolkata
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/outside_calling_hours
    error_payload_too_large:
      summary: Payload too large
      value:
        error:
          code: payload_too_large
          message: The request body is too large.
          details:
            limit_bytes: 1048576
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/payload_too_large
    error_phone_number_not_usable:
      summary: Phone number cannot be used for this call
      value:
        error:
          code: phone_number_not_usable
          message: This phone number cannot place outbound calls for this agent.
          details:
            phone_number_id: pn_5Lq8Xc2Rk9TzW3mBv7Np4d
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/phone_number_not_usable
    error_phone_number_required:
      summary: Caller number must be chosen
      value:
        error:
          code: phone_number_required
          message: This agent has more than one outbound number. Choose one with phone_number_id.
          details:
            agent_id: agent_3hT9kQ2mVx7RbN4pLc8Wz1
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/phone_number_required
    error_precondition_required:
      summary: If-Match required
      value:
        error:
          code: precondition_required
          message: This update needs an If-Match header with the ETag of the version you read.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/precondition_required
    error_rate_limited:
      summary: Rate limit exceeded
      value:
        error:
          code: rate_limited
          message: Too many requests. Retry after the number of seconds in the Retry-After header.
          details:
            limit_class: write
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: after
          doc_url: https://docs.relationsai.com/errors/rate_limited
    error_recipient_contacts_not_found:
      summary: Contacts not found
      value:
        error:
          code: recipient_contacts_not_found
          message: Some contact ids do not name contacts in this workspace.
          details:
            contact_ids:
              - ct_9Zx4Vb7Nm2Qw5Er8Ty1Ui3
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/recipient_contacts_not_found
    error_resource_not_found:
      summary: Resource not found
      value:
        error:
          code: resource_not_found
          message: No such resource.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/resource_not_found
    error_service_unavailable:
      summary: Service temporarily unavailable
      value:
        error:
          code: service_unavailable
          message: The service is temporarily unavailable. Retry after the number of seconds in the Retry-After header.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: after
          doc_url: https://docs.relationsai.com/errors/service_unavailable
    error_spend_limit_reached:
      summary: Monthly spend limit reached
      value:
        error:
          code: spend_limit_reached
          message: This workspace has reached the monthly spend limit set by its admin.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/spend_limit_reached
    error_telephony_disconnected:
      summary: Telephony connection down
      value:
        error:
          code: telephony_disconnected
          message: The telephony connection for this workspace is not working, so the campaign was paused.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/telephony_disconnected
    error_unsupported_media_type:
      summary: Unsupported media type
      value:
        error:
          code: unsupported_media_type
          message: Request bodies must be sent as application/json.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/unsupported_media_type
    error_validation_error:
      summary: Validation failed
      value:
        error:
          code: validation_error
          message: One or more fields are invalid.
          details:
            errors:
              - field: agent_id
                issue: required
                message: agent_id is required.
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/validation_error
    error_version_conflict:
      summary: Version conflict
      value:
        error:
          code: version_conflict
          message: The resource changed since you read it.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/version_conflict
    error_webhook_delivery_not_retryable:
      summary: Delivery cannot be retried
      value:
        error:
          code: webhook_delivery_not_retryable
          message: This delivery cannot be retried in its current status.
          details:
            status: succeeded
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/webhook_delivery_not_retryable
    error_webhook_endpoint_disabled:
      summary: Webhook endpoint disabled
      value:
        error:
          code: webhook_endpoint_disabled
          message: This webhook endpoint is disabled.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/webhook_endpoint_disabled
    error_webhook_endpoint_limit_reached:
      summary: Webhook endpoint limit reached
      value:
        error:
          code: webhook_endpoint_limit_reached
          message: This workspace already has the maximum number of webhook endpoints for this mode.
          details:
            limit: 16
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/webhook_endpoint_limit_reached
    error_webhook_url_not_allowed:
      summary: Webhook URL not allowed
      value:
        error:
          code: webhook_url_not_allowed
          message: This URL cannot receive webhooks.
          details:
            reason: private_address
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/webhook_url_not_allowed
    error_webhooks_not_enabled:
      summary: Webhooks not enabled
      value:
        error:
          code: webhooks_not_enabled
          message: Webhook delivery is not available yet.
          details: {}
          request_id: req_4k7m2qat5xvz3c6vqnwpbdfh
          retry: no
          doc_url: https://docs.relationsai.com/errors/webhooks_not_enabled
paths:
  /workspace:
    get:
      operationId: getWorkspace
      summary: Retrieve the workspace
      externalDocs:
        description: "Guide: Authentication"
        url: https://docs.relationsai.com/getting-started/authentication
      description: |
        Returns the workspace your API key belongs to, the key itself (name, mode, scopes, expiry), what
        the workspace can do through the API (`capabilities`) and the limits that apply (`limits`).

        Call this first: it is the quickest way to check that a key works, which mode it is in and which
        scopes it has. It needs no scope beyond the `workspace:read` scope every key has, and it never
        changes anything.
      tags:
        - Workspace
      x-required-scopes:
        - workspace:read
      x-idempotency: none
      x-rate-limit-class: read
      x-test-mode: Returns the same workspace with `livemode` false, the test key, and `limits.daily_call_limit` null.
      x-availability: ga-candidate
      responses:
        "200":
          description: The workspace, the current key, capabilities and limits.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Workspace"
              examples:
                test_key:
                  summary: A test key
                  value:
                    id: ws_7Hk2Lm9QxR4tB8vN3cZp6W
                    object: workspace
                    livemode: false
                    name: Acme Lending
                    timezone: Asia/Kolkata
                    currency: INR
                    api_key:
                      id: key_4Nf8Gt2Hx6Jq9Lm3Pv7Rs1
                      name: CRM sync (test)
                      environment: test
                      scopes:
                        - workspace:read
                        - agents:read
                        - numbers:read
                        - calls:read
                        - calls:write
                        - transcripts:read
                        - recordings:read
                        - analysis:read
                      created_at: 2026-10-20T08:15:00.000Z
                      expires_at: null
                    capabilities:
                      campaign_pause: true
                      campaign_resume: true
                      call_ringing_status: false
                      live_transcript: false
                      sentiment_analysis: false
                      end_call: false
                      agent_editing: false
                      inbound_calls: false
                      webhooks: true
                    limits:
                      rate_limits:
                        read:
                          per_key_per_minute: 600
                          per_workspace_per_minute: 1200
                        write:
                          per_key_per_minute: 120
                          per_workspace_per_minute: 240
                        dial:
                          per_key_per_minute: null
                          per_workspace_per_minute: 30
                      daily_call_limit: null
                      campaign_max_concurrency: 10
                live_key:
                  summary: A live key
                  value:
                    id: ws_7Hk2Lm9QxR4tB8vN3cZp6W
                    object: workspace
                    livemode: true
                    name: Acme Lending
                    timezone: Asia/Kolkata
                    currency: INR
                    api_key:
                      id: key_9Bv2Cx7Zl4Kj8Hg3Fd6Sa5
                      name: CRM sync
                      environment: live
                      scopes:
                        - workspace:read
                        - calls:read
                        - calls:write
                      created_at: 2026-10-21T06:00:00.000Z
                      expires_at: 2027-01-19T06:00:00.000Z
                    capabilities:
                      campaign_pause: true
                      campaign_resume: true
                      call_ringing_status: false
                      live_transcript: false
                      sentiment_analysis: false
                      end_call: false
                      agent_editing: false
                      inbound_calls: false
                      webhooks: false
                    limits:
                      rate_limits:
                        read:
                          per_key_per_minute: 600
                          per_workspace_per_minute: 1200
                        write:
                          per_key_per_minute: 120
                          per_workspace_per_minute: 240
                        dial:
                          per_key_per_minute: null
                          per_workspace_per_minute: 30
                      daily_call_limit: 500
                      campaign_max_concurrency: 10
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
          x-error-codes:
            - validation_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /agents:
    get:
      operationId: listAgents
      summary: List agents
      externalDocs:
        description: "Guide: Creating and preparing agents"
        url: https://docs.relationsai.com/guides/creating-and-preparing-agents
      description: |
        Lists the workspace's agents, newest first. Agents are created, configured and published in the
        console; the API reads them. Deleted agents are not listed.

        `published` is checked live for each page, so it can be null when that check is not available at
        that moment. Use the readiness endpoint before placing calls with an agent.
      tags:
        - Agents
      x-required-scopes:
        - agents:read
      x-idempotency: none
      x-rate-limit-class: read
      x-test-mode: Lists the workspace's real agents plus the built-in Sample agent (`sample` true), which is always active, published and ready in test mode.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: A page of agents.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AgentList"
              examples:
                agents:
                  summary: Agents in test mode
                  value:
                    object: list
                    data:
                      - id: agent_3hT9kQ2mVx7RbN4pLc8Wz1
                        object: agent
                        livemode: false
                        name: Loan renewal reminder
                        description: Reminds customers that their loan is due for renewal and books a callback.
                        status: active
                        published: true
                        published_version: 4
                        is_default: true
                        sample: false
                        created_at: 2026-09-02T10:12:44.000Z
                        updated_at: 2026-10-18T14:03:10.000Z
                      - id: agent_1ZltiWzxrXmMprGD6q63
                        object: agent
                        livemode: false
                        name: Sample agent
                        description: A built-in agent for trying the API in test mode.
                        status: active
                        published: true
                        published_version: 1
                        is_default: false
                        sample: true
                        created_at: 2026-10-21T00:00:00.000Z
                        updated_at: null
                    has_more: false
                    next_cursor: null
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_cursor`: Invalid pagination cursor.
          x-error-codes:
            - validation_error
            - invalid_cursor
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_cursor:
                  $ref: "#/components/examples/error_invalid_cursor"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /agents/{agent_id}:
    get:
      operationId: getAgent
      summary: Retrieve an agent
      externalDocs:
        description: "Guide: Creating and preparing agents"
        url: https://docs.relationsai.com/guides/creating-and-preparing-agents
      description: Returns one agent. An agent that was deleted, belongs to another workspace, or is the test-mode Sample agent read with a live key is `404 resource_not_found`.
      tags:
        - Agents
      x-required-scopes:
        - agents:read
      x-idempotency: none
      x-rate-limit-class: read
      x-test-mode: Returns real agents and the Sample agent.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/AgentId"
      responses:
        "200":
          description: The agent.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Agent"
              examples:
                agent:
                  summary: A published agent
                  value:
                    id: agent_3hT9kQ2mVx7RbN4pLc8Wz1
                    object: agent
                    livemode: true
                    name: Loan renewal reminder
                    description: Reminds customers that their loan is due for renewal and books a callback.
                    status: active
                    published: true
                    published_version: 4
                    is_default: true
                    sample: false
                    created_at: 2026-09-02T10:12:44.000Z
                    updated_at: 2026-10-18T14:03:10.000Z
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
          x-error-codes:
            - validation_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /agents/{agent_id}/readiness:
    get:
      operationId: getAgentReadiness
      summary: Check whether an agent can place calls
      externalDocs:
        description: "Guide: Creating and preparing agents"
        url: https://docs.relationsai.com/guides/creating-and-preparing-agents
      description: |
        Checks, right now, everything about the agent and the workspace that would stop a call being
        placed, and returns every problem found (not just the first). An agent is ready when it is
        switched on, fully set up and published, has an outbound phone number, and the workspace has
        calling set up, an active account, spend headroom and enough balance.

        Readiness does not check per-destination rules (the do-not-call list, consent, calling hours and
        the per-number daily limit); those are applied to each call. A ready agent can therefore still be
        refused for a particular number, and readiness can change at any time.
      tags:
        - Agents
      x-required-scopes:
        - agents:read
      x-idempotency: none
      x-rate-limit-class: read
      x-test-mode: The Sample agent is always ready. Real agents are checked for their configuration only; balance, spend limit and account status never block test mode.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/AgentId"
      responses:
        "200":
          description: The readiness result.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AgentReadiness"
              examples:
                ready:
                  summary: Ready
                  value:
                    object: agent_readiness
                    livemode: true
                    agent_id: agent_3hT9kQ2mVx7RbN4pLc8Wz1
                    ready: true
                    reasons: []
                    checked_at: 2026-10-21T09:30:00.000Z
                not_ready:
                  summary: Not ready
                  value:
                    object: agent_readiness
                    livemode: true
                    agent_id: agent_7Yx2Wq9Lp4Mn8Bv3Kc6Hd1
                    ready: false
                    reasons:
                      - code: agent_not_published
                        message: Publish the agent in the console before placing calls.
                      - code: no_outbound_number
                        message: Assign a phone number to this agent for outbound calls in the console.
                    checked_at: 2026-10-21T09:30:00.000Z
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
          x-error-codes:
            - validation_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /phone-numbers:
    get:
      operationId: listPhoneNumbers
      summary: List phone numbers
      externalDocs:
        description: "Guide: Creating and preparing agents"
        url: https://docs.relationsai.com/guides/creating-and-preparing-agents
      description: |
        Lists the workspace's phone numbers and the agents that use them. Numbers are added and assigned
        in the console. A number is listed only when the workspace has proven it holds that number, so a
        number visible here can be used as a caller number.

        `outbound_agent_ids` are the agents that call from the number; a call without `phone_number_id`
        uses the agent's outbound number. `inbound_agent_id` answers calls to the number.
        Listed by number, in a stable order.
      tags:
        - Phone numbers
      x-required-scopes:
        - numbers:read
      x-idempotency: none
      x-rate-limit-class: read
      x-test-mode: Lists the workspace's real numbers plus the sample number `+12025550150` (`sample` true), assigned to the Sample agent.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: A page of phone numbers.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PhoneNumberList"
              examples:
                numbers:
                  summary: Numbers in test mode
                  value:
                    object: list
                    data:
                      - id: pn_6Vhm3sFrB5UpmXAnsvmDu
                        object: phone_number
                        livemode: false
                        number: "+12025550150"
                        label: Sample number
                        status: active
                        capabilities:
                          outbound: true
                          inbound: false
                        inbound_agent_id: null
                        outbound_agent_ids:
                          - agent_1ZltiWzxrXmMprGD6q63
                        sample: true
                      - id: pn_5Lq8Xc2Rk9TzW3mBv7Np4d
                        object: phone_number
                        livemode: false
                        number: "+918000000001"
                        label: Collections line
                        status: active
                        capabilities:
                          outbound: true
                          inbound: true
                        inbound_agent_id: null
                        outbound_agent_ids:
                          - agent_3hT9kQ2mVx7RbN4pLc8Wz1
                        sample: false
                    has_more: false
                    next_cursor: null
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_cursor`: Invalid pagination cursor.
          x-error-codes:
            - validation_error
            - invalid_cursor
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_cursor:
                  $ref: "#/components/examples/error_invalid_cursor"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /phone-numbers/{phone_number_id}:
    get:
      operationId: getPhoneNumber
      summary: Retrieve a phone number
      externalDocs:
        description: "Guide: Creating and preparing agents"
        url: https://docs.relationsai.com/guides/creating-and-preparing-agents
      description: Returns one phone number with its capabilities and agent assignments. There is no carrier or account information in this object.
      tags:
        - Phone numbers
      x-required-scopes:
        - numbers:read
      x-idempotency: none
      x-rate-limit-class: read
      x-test-mode: Returns real numbers and the sample number.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/PhoneNumberId"
      responses:
        "200":
          description: The phone number.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PhoneNumber"
              examples:
                number:
                  summary: An outbound number
                  value:
                    id: pn_5Lq8Xc2Rk9TzW3mBv7Np4d
                    object: phone_number
                    livemode: true
                    number: "+918000000001"
                    label: Collections line
                    status: active
                    capabilities:
                      outbound: true
                      inbound: true
                    inbound_agent_id: null
                    outbound_agent_ids:
                      - agent_3hT9kQ2mVx7RbN4pLc8Wz1
                    sample: false
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
          x-error-codes:
            - validation_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /calls:
    post:
      operationId: createCall
      summary: Place a call
      externalDocs:
        description: "Guide: Making an outbound call"
        url: https://docs.relationsai.com/guides/making-an-outbound-call
      description: |
        Places one outbound call from an agent to a phone number. The call runs after the request returns:
        the response is `202 Accepted` with the call in `queued` status.

        **What 202 means.** The call passed every check (agent readiness, account, balance and spend
        limits, the do-not-call list, consent, calling hours and the per-number daily limit) and is being
        started. It does not mean anyone has answered.
        Follow the call with the `call.ended` and `call.settled` webhooks, or poll
        `GET /v1/calls/{call_id}`. In rare cases the start is never confirmed; the call then ends with
        `outcome: failed` and `end_reason: not_confirmed` within about two minutes and is not charged.

        **Retries.** `Idempotency-Key` is optional. With a key, a retry with the same key returns the original
        response and never places a second call, even if the first response was lost. Without one, a retry places
        another call: if a response was lost, list calls by `to` and `created_after` before retrying.

        **Caller number.** Without `phone_number_id`, the agent's outbound number is used; when the agent
        has several, send `phone_number_id`.

        **Variables.** `variables` are passed to the agent for this call. When `to` matches a contact, the
        contact's name and custom fields are added as variables too (your values win).

        **Charges.** Live calls are charged per started minute of talk time at your workspace rate, from
        the workspace balance. A call that is not answered is not charged.
      tags:
        - Calls
      x-required-scopes:
        - calls:write
      x-idempotency: optional
      x-rate-limit-class: dial
      x-test-mode: Nothing is dialled or charged. The destination selects the simulated result (see Test mode). The call reaches `ended` in about 20 seconds and `settled` in about 30, and webhooks fire with `livemode` false. Do-not-call entries, consent, calling hours and the per-number daily limit are enforced exactly as in live mode, against test-mode contacts and do-not-call entries. Balance, spend limit, account status and the API daily call limit never apply. The Sample agent and sample number can be used; a real agent must be switched on and its setup finished in the console (publication and number assignment are not required in test mode).
      x-availability: preview
      parameters:
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CallCreateRequest"
            examples:
              minimal:
                summary: Test call with the Sample agent
                value:
                  agent_id: agent_1ZltiWzxrXmMprGD6q63
                  to: "+12025550100"
              full:
                summary: Live call with variables and metadata
                value:
                  agent_id: agent_3hT9kQ2mVx7RbN4pLc8Wz1
                  to: "+919000000001"
                  phone_number_id: pn_5Lq8Xc2Rk9TzW3mBv7Np4d
                  variables:
                    first_name: Asha
                    due_date: 2026-11-05
                  metadata:
                    crm_lead_id: L-20931
      responses:
        "202":
          description: The call was accepted and is queued. Its id is final; follow it by webhook or polling.
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Idempotent-Replayed:
              $ref: "#/components/headers/Idempotent-Replayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Call"
              examples:
                queued:
                  $ref: "#/components/examples/call_queued"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_json`: Invalid JSON body.
            - `invalid_idempotency_key`: Invalid Idempotency-Key.
            - `invalid_phone_number`: Invalid phone number.
          x-error-codes:
            - validation_error
            - invalid_json
            - invalid_idempotency_key
            - invalid_phone_number
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_json:
                  $ref: "#/components/examples/error_invalid_json"
                invalid_idempotency_key:
                  $ref: "#/components/examples/error_invalid_idempotency_key"
                invalid_phone_number:
                  $ref: "#/components/examples/error_invalid_phone_number"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "402":
          description: |-
            Payment required. One of:
            - `insufficient_balance`: Insufficient balance.
            - `spend_limit_reached`: Monthly spend limit reached.
          x-error-codes:
            - insufficient_balance
            - spend_limit_reached
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_balance:
                  $ref: "#/components/examples/error_insufficient_balance"
                spend_limit_reached:
                  $ref: "#/components/examples/error_spend_limit_reached"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
            - `account_inactive`: Workspace account inactive.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
            - account_inactive
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
                account_inactive:
                  $ref: "#/components/examples/error_account_inactive"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "409":
          description: |-
            Conflict. One of:
            - `idempotency_key_reused`: Idempotency-Key reused.
            - `idempotency_key_in_progress`: Request with this Idempotency-Key in progress.
            - `idempotency_outcome_unknown`: Outcome of the earlier request unknown.
          x-error-codes:
            - idempotency_key_reused
            - idempotency_key_in_progress
            - idempotency_outcome_unknown
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                idempotency_key_reused:
                  $ref: "#/components/examples/error_idempotency_key_reused"
                idempotency_key_in_progress:
                  $ref: "#/components/examples/error_idempotency_key_in_progress"
                idempotency_outcome_unknown:
                  $ref: "#/components/examples/error_idempotency_outcome_unknown"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "413":
          description: |-
            Payload too large. One of:
            - `payload_too_large`: Payload too large.
          x-error-codes:
            - payload_too_large
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                payload_too_large:
                  $ref: "#/components/examples/error_payload_too_large"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "415":
          description: |-
            Unsupported media type. One of:
            - `unsupported_media_type`: Unsupported media type.
          x-error-codes:
            - unsupported_media_type
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                unsupported_media_type:
                  $ref: "#/components/examples/error_unsupported_media_type"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "422":
          description: |-
            Unprocessable. One of:
            - `agent_not_ready`: Agent not ready to call.
            - `calling_not_configured`: Calling not set up.
            - `outside_calling_hours`: Outside calling hours.
            - `phone_number_not_usable`: Phone number cannot be used for this call.
            - `phone_number_required`: Caller number must be chosen.
            - `dnc_listed`: Number on the do-not-call list.
            - `consent_required`: Consent required.
            - `contact_daily_limit_reached`: Daily call limit for this number reached.
            - `call_not_accepted`: Call not accepted.
          x-error-codes:
            - agent_not_ready
            - calling_not_configured
            - outside_calling_hours
            - phone_number_not_usable
            - phone_number_required
            - dnc_listed
            - consent_required
            - contact_daily_limit_reached
            - call_not_accepted
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                agent_not_ready:
                  $ref: "#/components/examples/error_agent_not_ready"
                calling_not_configured:
                  $ref: "#/components/examples/error_calling_not_configured"
                outside_calling_hours:
                  $ref: "#/components/examples/error_outside_calling_hours"
                phone_number_not_usable:
                  $ref: "#/components/examples/error_phone_number_not_usable"
                phone_number_required:
                  $ref: "#/components/examples/error_phone_number_required"
                dnc_listed:
                  $ref: "#/components/examples/error_dnc_listed"
                consent_required:
                  $ref: "#/components/examples/error_consent_required"
                contact_daily_limit_reached:
                  $ref: "#/components/examples/error_contact_daily_limit_reached"
                call_not_accepted:
                  $ref: "#/components/examples/error_call_not_accepted"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
            - `daily_call_limit_reached`: Daily call limit reached.
            - `calling_capacity_reached`: Calling capacity reached.
          x-error-codes:
            - rate_limited
            - daily_call_limit_reached
            - calling_capacity_reached
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
                daily_call_limit_reached:
                  $ref: "#/components/examples/error_daily_call_limit_reached"
                calling_capacity_reached:
                  $ref: "#/components/examples/error_calling_capacity_reached"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
    get:
      operationId: listCalls
      summary: List calls
      externalDocs:
        description: "Guide: Tracking call progress"
        url: https://docs.relationsai.com/guides/tracking-call-progress
      description: |
        Lists calls, newest first, including calls placed from the console and by campaigns. Filter by
        agent, campaign, destination, status, outcome and creation time. List entries are the full call
        object without the transcript; read artifacts from their own endpoints.

        Calls appear here as soon as they are accepted. Status and outcome are refreshed as the call
        progresses, typically within seconds, occasionally a minute or more behind; `settled` marks a call
        whose details are final.

        When you filter by `status`, a page can hold fewer than `limit` calls while `has_more` is true; keep
        following `next_cursor` until it is null.
      tags:
        - Calls
      x-required-scopes:
        - calls:read
      x-idempotency: none
      x-rate-limit-class: read
      x-test-mode: Lists test-mode calls only.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
        - $ref: "#/components/parameters/CreatedAfter"
        - $ref: "#/components/parameters/CreatedBefore"
        - name: agent_id
          in: query
          required: false
          description: Only calls handled by this agent.
          schema:
            type: string
            pattern: ^agent_[A-Za-z0-9_-]{1,58}$
        - name: campaign_id
          in: query
          required: false
          description: Only calls placed by this campaign.
          schema:
            type: string
            pattern: ^cmp_[A-Za-z0-9_-]{1,60}$
        - name: to
          in: query
          required: false
          description: Only calls to this number (E.164).
          schema:
            type: string
            format: e164
            pattern: ^\+[1-9][0-9]{7,14}$
          example: "+919000000001"
        - name: status
          in: query
          required: false
          description: Only calls in this status.
          schema:
            type: string
            enum:
              - queued
              - ringing
              - in_progress
              - ended
              - unknown
        - name: outcome
          in: query
          required: false
          description: Only ended calls with this outcome.
          schema:
            type: string
            enum:
              - completed
              - no_response
              - no_answer
              - busy
              - failed
              - unknown
      responses:
        "200":
          description: A page of calls.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CallList"
              examples:
                calls:
                  summary: Two test-mode calls
                  value:
                    object: list
                    data:
                      - id: call_9Tg5Yh2Uj8Ik4Ol7Pm3Nb6
                        object: call
                        livemode: false
                        status: ended
                        outcome: no_answer
                        end_reason: no_answer
                        direction: outbound
                        source: api
                        agent_id: agent_1ZltiWzxrXmMprGD6q63
                        campaign_id: null
                        phone_number_id: pn_6Vhm3sFrB5UpmXAnsvmDu
                        from: "+12025550150"
                        to: "+12025550101"
                        metadata: {}
                        created_at: 2026-10-21T09:35:00.000Z
                        ended_at: 2026-10-21T09:35:18.000Z
                        duration_seconds: 0
                        billable_minutes: 0
                        cost:
                          amount: 0
                          currency: INR
                        artifacts:
                          transcript:
                            state: absent
                          recording:
                            state: absent
                          analysis:
                            state: absent
                        settled: true
                        settled_at: 2026-10-21T09:35:30.000Z
                      - id: call_6Vb3Nm8Qw2Er5Ty9Ui4Op7
                        object: call
                        livemode: false
                        status: queued
                        outcome: null
                        end_reason: null
                        direction: outbound
                        source: api
                        agent_id: agent_1ZltiWzxrXmMprGD6q63
                        campaign_id: null
                        phone_number_id: pn_6Vhm3sFrB5UpmXAnsvmDu
                        from: "+12025550150"
                        to: "+12025550100"
                        metadata:
                          crm_lead_id: L-20931
                        created_at: 2026-10-21T09:30:00.000Z
                        ended_at: null
                        duration_seconds: null
                        billable_minutes: null
                        cost: null
                        artifacts:
                          transcript:
                            state: pending
                          recording:
                            state: pending
                          analysis:
                            state: pending
                        settled: false
                        settled_at: null
                    has_more: false
                    next_cursor: null
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_cursor`: Invalid pagination cursor.
            - `invalid_phone_number`: Invalid phone number.
          x-error-codes:
            - validation_error
            - invalid_cursor
            - invalid_phone_number
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_cursor:
                  $ref: "#/components/examples/error_invalid_cursor"
                invalid_phone_number:
                  $ref: "#/components/examples/error_invalid_phone_number"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /calls/{call_id}:
    get:
      operationId: getCall
      summary: Retrieve a call
      externalDocs:
        description: "Guide: Tracking call progress"
        url: https://docs.relationsai.com/guides/tracking-call-progress
      description: |
        Returns one call with its status, outcome, timing, cost and the readiness of its artifacts.
        Poll it (no more than every few seconds) or, better, use webhooks. `outcome`, `duration_seconds`,
        `billable_minutes` and `cost` can still change until `settled` is true.
      tags:
        - Calls
      x-required-scopes:
        - calls:read
      x-idempotency: none
      x-rate-limit-class: read
      x-test-mode: Returns test-mode calls; status advances on the simulated timeline.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/CallId"
      responses:
        "200":
          description: The call.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Call"
              examples:
                settled:
                  $ref: "#/components/examples/call_settled"
                no_answer:
                  $ref: "#/components/examples/call_no_answer"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
          x-error-codes:
            - validation_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /calls/{call_id}/transcript:
    get:
      operationId: getCallTranscript
      summary: Retrieve a call transcript
      externalDocs:
        description: "Guide: Retrieving recordings and transcripts"
        url: https://docs.relationsai.com/guides/retrieving-recordings-and-transcripts
      description: |
        Returns the conversation turn by turn, verbatim. Transcripts are produced after the call ends
        (live transcripts are not available); until then `state` is `pending` and `turns` is empty. A call
        that was not connected has `state: absent`. Reading the transcript never changes the call.
      tags:
        - Calls
      x-required-scopes:
        - transcripts:read
      x-idempotency: none
      x-rate-limit-class: read
      x-test-mode: Returns a fixture transcript with `simulated` true for completed test calls.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/CallId"
      responses:
        "200":
          description: The transcript, or its state while not ready.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CallTranscript"
              examples:
                ready:
                  summary: A ready transcript
                  value:
                    object: call_transcript
                    livemode: true
                    call_id: call_2Hd8Ks4Lq7Mw3Nx9Pz5Rc1
                    state: ready
                    simulated: false
                    turns:
                      - index: 0
                        speaker: agent
                        text: Hello, this is an AI assistant calling from Acme Lending. Am I speaking with Asha?
                        start_ms: 400
                        end_ms: 4900
                      - index: 1
                        speaker: caller
                        text: Yes, speaking.
                        start_ms: 5600
                        end_ms: 6500
                pending:
                  summary: Not ready yet
                  value:
                    object: call_transcript
                    livemode: true
                    call_id: call_6Vb3Nm8Qw2Er5Ty9Ui4Op7
                    state: pending
                    simulated: false
                    turns: []
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
          x-error-codes:
            - validation_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /calls/{call_id}/recording:
    get:
      operationId: getCallRecording
      summary: Retrieve a call recording link
      externalDocs:
        description: "Guide: Retrieving recordings and transcripts"
        url: https://docs.relationsai.com/guides/retrieving-recordings-and-transcripts
      description: |
        Returns the recording's state and, when it is ready, a short-lived HTTPS link to the audio
        (about 15 minutes; see `expires_at`). The link needs no API key, so treat it like a password and do
        not log or store it; ask for a new one when you need it. Recordings are usually ready within a
        minute of the call ending. A call that was not answered has no recording (`state: absent`).
      tags:
        - Calls
      x-required-scopes:
        - recordings:read
      x-idempotency: none
      x-rate-limit-class: read
      x-test-mode: Completed test calls return a link to a short synthetic audio file with `simulated` true.
      x-availability: preview
      parameters:
        - $ref: "#/components/parameters/CallId"
      responses:
        "200":
          description: The recording state and, when ready, a fresh link.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CallRecording"
              examples:
                ready:
                  summary: Ready
                  value:
                    object: call_recording
                    livemode: true
                    call_id: call_2Hd8Ks4Lq7Mw3Nx9Pz5Rc1
                    state: ready
                    simulated: false
                    url: https://voice-api.relationsai.com/v1/recordings/rec_tok_Y2FsbF8ySGQ4S3M0THE3TXczTng5UHo1UmMx
                    expires_at: 2026-10-21T10:00:00.000Z
                    content_type: audio/ogg
                absent:
                  summary: No recording
                  value:
                    object: call_recording
                    livemode: false
                    call_id: call_9Tg5Yh2Uj8Ik4Ol7Pm3Nb6
                    state: absent
                    simulated: false
                    url: null
                    expires_at: null
                    content_type: null
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
          x-error-codes:
            - validation_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /calls/{call_id}/analysis:
    get:
      operationId: getCallAnalysis
      summary: Retrieve a call analysis
      externalDocs:
        description: "Guide: Working with analysis results"
        url: https://docs.relationsai.com/guides/working-with-analysis-results
      description: |
        Returns the call summary, the fields the agent extracts from the conversation (configured in the
        console), and whether the call met its goal. Analysis is produced after the call ends, usually
        within a minute; each part has its own `state`. Sentiment is not offered.
      tags:
        - Calls
      x-required-scopes:
        - analysis:read
      x-idempotency: none
      x-rate-limit-class: read
      x-test-mode: Completed test calls return a fixture analysis with `simulated` true.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/CallId"
      responses:
        "200":
          description: The analysis, or its state while not ready.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CallAnalysis"
              examples:
                ready:
                  summary: Ready
                  value:
                    object: call_analysis
                    livemode: true
                    call_id: call_2Hd8Ks4Lq7Mw3Nx9Pz5Rc1
                    state: ready
                    simulated: false
                    summary:
                      state: ready
                      text: The customer confirmed the renewal and asked for a callback on Friday afternoon.
                    extracted_fields:
                      - name: wants_renewal
                        type: boolean
                        state: ready
                        value: true
                      - name: callback_day
                        type: string
                        state: ready
                        value: Friday
                    goal_met: true
                pending:
                  summary: Still being produced
                  value:
                    object: call_analysis
                    livemode: true
                    call_id: call_6Vb3Nm8Qw2Er5Ty9Ui4Op7
                    state: pending
                    simulated: false
                    summary:
                      state: pending
                      text: null
                    extracted_fields: []
                    goal_met: null
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
          x-error-codes:
            - validation_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /recordings/{recording_token}:
    get:
      operationId: downloadRecording
      summary: Download recording audio
      externalDocs:
        description: "Guide: Retrieving recordings and transcripts"
        url: https://docs.relationsai.com/guides/retrieving-recordings-and-transcripts
      description: |
        Streams the audio of a recording. You do not build this URL yourself: it is the `url` returned by
        `GET /v1/calls/{call_id}/recording`. The token in the path is the credential, so no
        `Authorization` header is needed (it is ignored), and the link stops working at its `expires_at`.
        Scope: the key that calls `GET /v1/calls/{call_id}/recording` needs `recordings:read` to obtain the link;
        the download itself needs no key and no scope (`x-required-scopes` names the scope behind the link).
        Supports `Range` requests for seeking; a range that cannot be served is answered with the whole file (200).
      tags:
        - Calls
      security: []
      x-auth: signed-url
      x-required-scopes:
        - recordings:read
      x-idempotency: none
      x-rate-limit-class: read
      x-test-mode: Serves a short synthetic audio file (`audio/wav`, about one second).
      x-availability: preview
      parameters:
        - $ref: "#/components/parameters/RecordingToken"
        - name: Range
          in: header
          required: false
          description: A byte range, for example `bytes=0-65535`.
          schema:
            type: string
            pattern: ^bytes=[0-9]*-[0-9]*$
      responses:
        "200":
          description: The whole audio file. The media type is the recording's own (`content_type` on the recording object); test-mode recordings are `audio/wav`.
          content:
            audio/ogg:
              schema:
                type: string
                contentMediaType: audio/ogg
                description: Audio bytes.
            audio/mpeg:
              schema:
                type: string
                contentMediaType: audio/mpeg
                description: Audio bytes.
            audio/wav:
              schema:
                type: string
                contentMediaType: audio/wav
                description: Audio bytes (test-mode synthetic audio).
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "206":
          description: The requested byte range.
          content:
            audio/ogg:
              schema:
                type: string
                contentMediaType: audio/ogg
                description: Audio bytes.
            audio/mpeg:
              schema:
                type: string
                contentMediaType: audio/mpeg
                description: Audio bytes.
            audio/wav:
              schema:
                type: string
                contentMediaType: audio/wav
                description: Audio bytes (test-mode synthetic audio).
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "410":
          description: |-
            Error. One of:
            - `media_link_expired`: Recording link expired.
          x-error-codes:
            - media_link_expired
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                media_link_expired:
                  $ref: "#/components/examples/error_media_link_expired"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /campaigns:
    post:
      operationId: createCampaign
      summary: Create a campaign
      externalDocs:
        description: "Guide: Running campaigns"
        url: https://docs.relationsai.com/guides/running-campaigns
      description: |
        Creates a campaign in `draft` status. Nothing is dialled until you start it. You can add
        recipients now (`contact_ids`) or later with the recipients endpoint, while the campaign is a
        draft. Recipients are contacts: create them first, for example with the contact upsert.

        Do-not-call numbers are left out when a campaign starts and block a resume; there is no API option
        to include them. A campaign whose screening was switched off in the console is refused by start and
        resume (`409 campaign_dnc_override_enabled`).
      tags:
        - Campaigns
      x-required-scopes:
        - campaigns:write
      x-idempotency: optional
      x-rate-limit-class: write
      x-test-mode: Creates a test-mode campaign that can only use test-mode contacts.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CampaignCreateRequest"
            examples:
              campaign:
                summary: A campaign with two recipients
                value:
                  name: November renewals
                  agent_id: agent_1ZltiWzxrXmMprGD6q63
                  concurrency_limit: 5
                  budget_cap:
                    amount: 500000
                    currency: INR
                  contact_ids:
                    - ct_8Rw2Tq5Lm9Xc3Vb7Nz4Kp1
                    - ct_2Mh7Yd4Qs8Fv1Kc6Bx9Tn3
      responses:
        "201":
          description: The campaign was created as a draft.
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            ETag:
              $ref: "#/components/headers/ETag"
            Idempotent-Replayed:
              $ref: "#/components/headers/Idempotent-Replayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Campaign"
              examples:
                draft:
                  $ref: "#/components/examples/campaign_draft"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_json`: Invalid JSON body.
            - `invalid_idempotency_key`: Invalid Idempotency-Key.
          x-error-codes:
            - validation_error
            - invalid_json
            - invalid_idempotency_key
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_json:
                  $ref: "#/components/examples/error_invalid_json"
                invalid_idempotency_key:
                  $ref: "#/components/examples/error_invalid_idempotency_key"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "409":
          description: |-
            Conflict. One of:
            - `idempotency_key_reused`: Idempotency-Key reused.
            - `idempotency_key_in_progress`: Request with this Idempotency-Key in progress.
            - `idempotency_outcome_unknown`: Outcome of the earlier request unknown.
          x-error-codes:
            - idempotency_key_reused
            - idempotency_key_in_progress
            - idempotency_outcome_unknown
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                idempotency_key_reused:
                  $ref: "#/components/examples/error_idempotency_key_reused"
                idempotency_key_in_progress:
                  $ref: "#/components/examples/error_idempotency_key_in_progress"
                idempotency_outcome_unknown:
                  $ref: "#/components/examples/error_idempotency_outcome_unknown"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "413":
          description: |-
            Payload too large. One of:
            - `payload_too_large`: Payload too large.
          x-error-codes:
            - payload_too_large
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                payload_too_large:
                  $ref: "#/components/examples/error_payload_too_large"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "415":
          description: |-
            Unsupported media type. One of:
            - `unsupported_media_type`: Unsupported media type.
          x-error-codes:
            - unsupported_media_type
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                unsupported_media_type:
                  $ref: "#/components/examples/error_unsupported_media_type"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "422":
          description: |-
            Unprocessable. One of:
            - `recipient_contacts_not_found`: Contacts not found.
          x-error-codes:
            - recipient_contacts_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                recipient_contacts_not_found:
                  $ref: "#/components/examples/error_recipient_contacts_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
    get:
      operationId: listCampaigns
      summary: List campaigns
      externalDocs:
        description: "Guide: Running campaigns"
        url: https://docs.relationsai.com/guides/running-campaigns
      description: Lists campaigns, newest first. Filter by `status`. Status and progress are refreshed in the background and can be up to a minute behind; a terminal status reached by the run itself (`completed`, `failed`) can take longer to appear.
      tags:
        - Campaigns
      x-required-scopes:
        - campaigns:read
      x-idempotency: none
      x-rate-limit-class: read
      x-test-mode: Lists test-mode campaigns only.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
        - $ref: "#/components/parameters/CreatedAfter"
        - $ref: "#/components/parameters/CreatedBefore"
        - name: status
          in: query
          required: false
          description: Only campaigns in this status.
          schema:
            type: string
            enum:
              - draft
              - running
              - paused
              - stopped
              - completed
              - failed
              - unknown
      responses:
        "200":
          description: A page of campaigns.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CampaignList"
              examples:
                campaigns:
                  summary: One running campaign
                  value:
                    object: list
                    data:
                      - id: cmp_7Wq3Er9Ty2Ui5Op8As4Df6
                        object: campaign
                        livemode: true
                        name: November renewals
                        agent_id: agent_3hT9kQ2mVx7RbN4pLc8Wz1
                        status: running
                        capabilities:
                          start: false
                          pause: true
                          resume: false
                          stop: true
                          update: false
                          add_recipients: false
                        concurrency_limit: 5
                        budget_cap:
                          amount: 500000
                          currency: INR
                        recipient_count: 1200
                        progress:
                          calls: 640
                          connected: 410
                          no_answer: 190
                          failed: 35
                          in_progress: 5
                        spend:
                          amount: 246000
                          currency: INR
                        run_number: 1
                        dnc_screening: enforced
                        created_at: 2026-10-20T08:00:00.000Z
                    has_more: false
                    next_cursor: null
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_cursor`: Invalid pagination cursor.
          x-error-codes:
            - validation_error
            - invalid_cursor
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_cursor:
                  $ref: "#/components/examples/error_invalid_cursor"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /campaigns/{campaign_id}:
    get:
      operationId: getCampaign
      summary: Retrieve a campaign
      externalDocs:
        description: "Guide: Running campaigns"
        url: https://docs.relationsai.com/guides/running-campaigns
      description: Returns one campaign with its status, allowed actions (`capabilities`), progress and spend. The `ETag` header is the version to send as `If-Match` when you update it.
      tags:
        - Campaigns
      x-required-scopes:
        - campaigns:read
      x-idempotency: none
      x-rate-limit-class: read
      x-test-mode: Returns test-mode campaigns; their calls progress on the simulated timeline.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/CampaignId"
      responses:
        "200":
          description: The campaign.
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            ETag:
              $ref: "#/components/headers/ETag"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Campaign"
              examples:
                running:
                  $ref: "#/components/examples/campaign_running"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
          x-error-codes:
            - validation_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
    patch:
      operationId: updateCampaign
      summary: Update a campaign
      externalDocs:
        description: "Guide: Running campaigns"
        url: https://docs.relationsai.com/guides/running-campaigns
      description: |
        Changes a campaign's name, agent, concurrency or budget cap. Allowed in every status except
        `running` (pause it first). Changes take effect at the **next start**: a resume continues the paused
        run with the settings it began with. Requires `If-Match` with the campaign's current `ETag`.
      tags:
        - Campaigns
      x-required-scopes:
        - campaigns:write
      x-idempotency: none
      x-rate-limit-class: write
      x-test-mode: Updates a test-mode campaign.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/CampaignId"
        - $ref: "#/components/parameters/IfMatch"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CampaignUpdateRequest"
            examples:
              raise_cap:
                summary: Raise the budget cap
                value:
                  budget_cap:
                    amount: 750000
                    currency: INR
      responses:
        "200":
          description: The updated campaign, with its new `ETag`.
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            ETag:
              $ref: "#/components/headers/ETag"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Campaign"
              examples:
                updated:
                  $ref: "#/components/examples/campaign_paused"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_json`: Invalid JSON body.
          x-error-codes:
            - validation_error
            - invalid_json
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_json:
                  $ref: "#/components/examples/error_invalid_json"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "409":
          description: |-
            Conflict. One of:
            - `campaign_state_conflict`: Campaign is in the wrong state.
          x-error-codes:
            - campaign_state_conflict
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                campaign_state_conflict:
                  $ref: "#/components/examples/error_campaign_state_conflict"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "412":
          description: |-
            Precondition failed. One of:
            - `version_conflict`: Version conflict.
          x-error-codes:
            - version_conflict
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                version_conflict:
                  $ref: "#/components/examples/error_version_conflict"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "413":
          description: |-
            Payload too large. One of:
            - `payload_too_large`: Payload too large.
          x-error-codes:
            - payload_too_large
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                payload_too_large:
                  $ref: "#/components/examples/error_payload_too_large"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "415":
          description: |-
            Unsupported media type. One of:
            - `unsupported_media_type`: Unsupported media type.
          x-error-codes:
            - unsupported_media_type
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                unsupported_media_type:
                  $ref: "#/components/examples/error_unsupported_media_type"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "428":
          description: |-
            Precondition required. One of:
            - `precondition_required`: If-Match required.
          x-error-codes:
            - precondition_required
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                precondition_required:
                  $ref: "#/components/examples/error_precondition_required"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /campaigns/{campaign_id}/recipients:
    post:
      operationId: addCampaignRecipients
      summary: Add recipients
      externalDocs:
        description: "Guide: Running campaigns"
        url: https://docs.relationsai.com/guides/running-campaigns
      description: |
        Adds contacts to a `draft` campaign. Contacts already in the campaign are skipped. Once a campaign
        has started, its recipients are fixed: a later start calls the previous run's recipients again.
        To call a different audience, create a new campaign. Up to 1000 contacts per request and 10,000
        per campaign.
      tags:
        - Campaigns
      x-required-scopes:
        - campaigns:write
      x-idempotency: optional
      x-rate-limit-class: write
      x-test-mode: Adds test-mode contacts to a test-mode campaign.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/CampaignId"
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CampaignRecipientsAddRequest"
            examples:
              add:
                summary: Add two contacts
                value:
                  contact_ids:
                    - ct_8Rw2Tq5Lm9Xc3Vb7Nz4Kp1
                    - ct_2Mh7Yd4Qs8Fv1Kc6Bx9Tn3
      responses:
        "200":
          description: Recipients were added (or were already present).
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Idempotent-Replayed:
              $ref: "#/components/headers/Idempotent-Replayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CampaignRecipientsAddResult"
              examples:
                added:
                  summary: One new recipient
                  value:
                    object: campaign_recipients_added
                    livemode: false
                    campaign_id: cmp_2Kd7Fg4Hj9Lz3Xc8Vb5Nm1
                    added: 1
                    recipient_count: 3
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_json`: Invalid JSON body.
            - `invalid_idempotency_key`: Invalid Idempotency-Key.
          x-error-codes:
            - validation_error
            - invalid_json
            - invalid_idempotency_key
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_json:
                  $ref: "#/components/examples/error_invalid_json"
                invalid_idempotency_key:
                  $ref: "#/components/examples/error_invalid_idempotency_key"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "409":
          description: |-
            Conflict. One of:
            - `idempotency_key_reused`: Idempotency-Key reused.
            - `idempotency_key_in_progress`: Request with this Idempotency-Key in progress.
            - `idempotency_outcome_unknown`: Outcome of the earlier request unknown.
            - `campaign_state_conflict`: Campaign is in the wrong state.
          x-error-codes:
            - idempotency_key_reused
            - idempotency_key_in_progress
            - idempotency_outcome_unknown
            - campaign_state_conflict
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                idempotency_key_reused:
                  $ref: "#/components/examples/error_idempotency_key_reused"
                idempotency_key_in_progress:
                  $ref: "#/components/examples/error_idempotency_key_in_progress"
                idempotency_outcome_unknown:
                  $ref: "#/components/examples/error_idempotency_outcome_unknown"
                campaign_state_conflict:
                  $ref: "#/components/examples/error_campaign_state_conflict"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "413":
          description: |-
            Payload too large. One of:
            - `payload_too_large`: Payload too large.
          x-error-codes:
            - payload_too_large
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                payload_too_large:
                  $ref: "#/components/examples/error_payload_too_large"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "415":
          description: |-
            Unsupported media type. One of:
            - `unsupported_media_type`: Unsupported media type.
          x-error-codes:
            - unsupported_media_type
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                unsupported_media_type:
                  $ref: "#/components/examples/error_unsupported_media_type"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "422":
          description: |-
            Unprocessable. One of:
            - `recipient_contacts_not_found`: Contacts not found.
          x-error-codes:
            - recipient_contacts_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                recipient_contacts_not_found:
                  $ref: "#/components/examples/error_recipient_contacts_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
    get:
      operationId: listCampaignRecipients
      summary: List recipients
      externalDocs:
        description: "Guide: Running campaigns"
        url: https://docs.relationsai.com/guides/running-campaigns
      description: |
        Lists a campaign's recipients with what happened to each in the current or latest run: status,
        attempts, the last call and its outcome, or why the recipient was left out. Recipients are listed
        in a stable order (not by time). Use the cursor to page; do not rely on the order meaning anything
        else. Per-recipient results are refreshed in the background and can be
        up to a minute behind the calls themselves.
      tags:
        - Campaigns
      x-required-scopes:
        - campaigns:read
      x-idempotency: none
      x-rate-limit-class: read
      x-test-mode: Lists recipients of a test-mode campaign with simulated results.
      x-availability: preview
      parameters:
        - $ref: "#/components/parameters/CampaignId"
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
        - name: status
          in: query
          required: false
          description: Only recipients in this status.
          schema:
            type: string
            enum:
              - pending
              - in_progress
              - completed
              - failed
              - suppressed
              - cancelled
              - unknown
      responses:
        "200":
          description: A page of recipients.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CampaignRecipientList"
              examples:
                recipients:
                  summary: Two recipients
                  value:
                    object: list
                    data:
                      - id: rcp_3Gh8Jk2Lz5Xc9Vb4Nm7Qw1
                        object: campaign_recipient
                        livemode: true
                        campaign_id: cmp_7Wq3Er9Ty2Ui5Op8As4Df6
                        contact_id: ct_8Rw2Tq5Lm9Xc3Vb7Nz4Kp1
                        phone_number: "+919000000001"
                        status: completed
                        attempts: 1
                        last_call_id: call_2Hd8Ks4Lq7Mw3Nx9Pz5Rc1
                        outcome: completed
                        suppression_reason: null
                      - id: rcp_6Tr1Yu4Io7Pa2Sd5Fg8Hj3
                        object: campaign_recipient
                        livemode: true
                        campaign_id: cmp_7Wq3Er9Ty2Ui5Op8As4Df6
                        contact_id: ct_2Mh7Yd4Qs8Fv1Kc6Bx9Tn3
                        phone_number: "+919000000002"
                        status: suppressed
                        attempts: 0
                        last_call_id: null
                        outcome: null
                        suppression_reason: dnc_listed
                    has_more: true
                    next_cursor: eyJ2IjoxLCJrIjoicmNwXzZUcjFZdTRJbzdQYTJTZDVGZzhIajMifQ.4f7a2c
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_cursor`: Invalid pagination cursor.
          x-error-codes:
            - validation_error
            - invalid_cursor
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_cursor:
                  $ref: "#/components/examples/error_invalid_cursor"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /campaigns/{campaign_id}/start:
    post:
      operationId: startCampaign
      summary: Start a campaign
      externalDocs:
        description: "Guide: Running campaigns"
        url: https://docs.relationsai.com/guides/running-campaigns
      description: |
        Starts a run: from `draft` it calls the recipients you added; from `stopped`, `completed` or
        `paused` it begins a new run with the previous run's recipients (a paused run is abandoned; use
        resume to continue it instead).

        Before anything is dialled the API checks the agent, the account, balance and spend limits, the
        campaign budget cap, calling hours and the telephony connection, and screens every recipient
        against the do-not-call list, consent and the per-number daily limit. Blocked recipients are left
        out (see the recipients list); if that leaves nobody, the start is refused. Screening happens at the
        start: a number added to the do-not-call list while the run is going is still called by it (pause and
        resume to re-screen, or stop). A campaign whose do-not-call screening was switched off in the console
        is refused (`409 campaign_dnc_override_enabled`).

        **Daily call limit.** In live mode a start counts every recipient of the campaign against the
        workspace's daily limit of calls placed through the API (see `limits.daily_call_limit` on the
        workspace), before anything is dialled, because the run may call each of them. A start that would go
        past the limit is refused whole with `429 daily_call_limit_reached`, and the message says how many calls
        it needed. A start refused for any other reason before dialling does not count. Test mode has no limit.

        **What 200 means.** The run was started and the campaign is `running`; calls are placed at up to
        `concurrency_limit` at a time. **202** means the start was sent but its confirmation has not
        arrived yet; the campaign shows `running` and is reconciled automatically, so retrieve it in a
        minute rather than starting it again.
      tags:
        - Campaigns
      x-required-scopes:
        - campaigns:write
      x-idempotency: optional
      x-rate-limit-class: dial
      x-test-mode: Nothing is dialled or charged; each recipient gets a simulated call chosen by their number, and campaign webhooks fire with `livemode` false.
      x-availability: preview
      parameters:
        - $ref: "#/components/parameters/CampaignId"
        - $ref: "#/components/parameters/IdempotencyKey"
      responses:
        "200":
          description: The run started.
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            ETag:
              $ref: "#/components/headers/ETag"
            Idempotent-Replayed:
              $ref: "#/components/headers/Idempotent-Replayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Campaign"
              examples:
                started:
                  $ref: "#/components/examples/campaign_started_test"
        "202":
          description: The start was sent and is being confirmed. The campaign shows `running`; check it again shortly.
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            ETag:
              $ref: "#/components/headers/ETag"
            Idempotent-Replayed:
              $ref: "#/components/headers/Idempotent-Replayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Campaign"
              examples:
                unconfirmed:
                  $ref: "#/components/examples/campaign_running"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_idempotency_key`: Invalid Idempotency-Key.
          x-error-codes:
            - validation_error
            - invalid_idempotency_key
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_idempotency_key:
                  $ref: "#/components/examples/error_invalid_idempotency_key"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "402":
          description: |-
            Payment required. One of:
            - `insufficient_balance`: Insufficient balance.
            - `spend_limit_reached`: Monthly spend limit reached.
            - `campaign_budget_reached`: Campaign budget reached.
          x-error-codes:
            - insufficient_balance
            - spend_limit_reached
            - campaign_budget_reached
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_balance:
                  $ref: "#/components/examples/error_insufficient_balance"
                spend_limit_reached:
                  $ref: "#/components/examples/error_spend_limit_reached"
                campaign_budget_reached:
                  $ref: "#/components/examples/error_campaign_budget_reached"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
            - `account_inactive`: Workspace account inactive.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
            - account_inactive
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
                account_inactive:
                  $ref: "#/components/examples/error_account_inactive"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "409":
          description: |-
            Conflict. One of:
            - `idempotency_key_reused`: Idempotency-Key reused.
            - `idempotency_key_in_progress`: Request with this Idempotency-Key in progress.
            - `idempotency_outcome_unknown`: Outcome of the earlier request unknown.
            - `campaign_state_conflict`: Campaign is in the wrong state.
            - `campaign_operation_in_progress`: Another start or resume is in progress.
            - `campaign_outcome_unknown`: Campaign start or resume not confirmed.
            - `campaign_has_no_recipients`: Campaign has no recipients.
            - `campaign_dnc_override_enabled`: Campaign calls numbers on the do-not-call list.
          x-error-codes:
            - idempotency_key_reused
            - idempotency_key_in_progress
            - idempotency_outcome_unknown
            - campaign_state_conflict
            - campaign_operation_in_progress
            - campaign_outcome_unknown
            - campaign_has_no_recipients
            - campaign_dnc_override_enabled
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                idempotency_key_reused:
                  $ref: "#/components/examples/error_idempotency_key_reused"
                idempotency_key_in_progress:
                  $ref: "#/components/examples/error_idempotency_key_in_progress"
                idempotency_outcome_unknown:
                  $ref: "#/components/examples/error_idempotency_outcome_unknown"
                campaign_state_conflict:
                  $ref: "#/components/examples/error_campaign_state_conflict"
                campaign_operation_in_progress:
                  $ref: "#/components/examples/error_campaign_operation_in_progress"
                campaign_outcome_unknown:
                  $ref: "#/components/examples/error_campaign_outcome_unknown"
                campaign_has_no_recipients:
                  $ref: "#/components/examples/error_campaign_has_no_recipients"
                campaign_dnc_override_enabled:
                  $ref: "#/components/examples/error_campaign_dnc_override_enabled"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "422":
          description: |-
            Unprocessable. One of:
            - `agent_not_ready`: Agent not ready to call.
            - `calling_not_configured`: Calling not set up.
            - `outside_calling_hours`: Outside calling hours.
            - `campaign_recipients_suppressed`: Every recipient is suppressed.
            - `campaign_too_large`: Campaign too large.
            - `phone_number_required`: Caller number must be chosen.
            - `telephony_disconnected`: Telephony connection down.
          x-error-codes:
            - agent_not_ready
            - calling_not_configured
            - outside_calling_hours
            - campaign_recipients_suppressed
            - campaign_too_large
            - phone_number_required
            - telephony_disconnected
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                agent_not_ready:
                  $ref: "#/components/examples/error_agent_not_ready"
                calling_not_configured:
                  $ref: "#/components/examples/error_calling_not_configured"
                outside_calling_hours:
                  $ref: "#/components/examples/error_outside_calling_hours"
                campaign_recipients_suppressed:
                  $ref: "#/components/examples/error_campaign_recipients_suppressed"
                campaign_too_large:
                  $ref: "#/components/examples/error_campaign_too_large"
                phone_number_required:
                  $ref: "#/components/examples/error_phone_number_required"
                telephony_disconnected:
                  $ref: "#/components/examples/error_telephony_disconnected"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
            - `daily_call_limit_reached`: Daily call limit reached.
          x-error-codes:
            - rate_limited
            - daily_call_limit_reached
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
                daily_call_limit_reached:
                  $ref: "#/components/examples/error_daily_call_limit_reached"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
            - `campaign_recipients_unavailable`: Recipients could not be checked.
          x-error-codes:
            - service_unavailable
            - campaign_recipients_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
                campaign_recipients_unavailable:
                  $ref: "#/components/examples/error_campaign_recipients_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /campaigns/{campaign_id}/pause:
    post:
      operationId: pauseCampaign
      summary: Pause a campaign
      externalDocs:
        description: "Guide: Running campaigns"
        url: https://docs.relationsai.com/guides/running-campaigns
      description: |
        Pauses a `running` campaign: no new calls are started. Calls already connected finish normally and
        are charged as usual. The campaign is reported `paused` only once the pause is confirmed; if it is
        not confirmed you get `409 campaign_pause_not_confirmed` and the campaign may still be dialling.
      tags:
        - Campaigns
      x-required-scopes:
        - campaigns:write
      x-idempotency: optional
      x-rate-limit-class: write
      x-test-mode: Pauses the simulated run immediately.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/CampaignId"
        - $ref: "#/components/parameters/IdempotencyKey"
      responses:
        "200":
          description: The campaign is paused.
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            ETag:
              $ref: "#/components/headers/ETag"
            Idempotent-Replayed:
              $ref: "#/components/headers/Idempotent-Replayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Campaign"
              examples:
                paused:
                  $ref: "#/components/examples/campaign_paused"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_idempotency_key`: Invalid Idempotency-Key.
          x-error-codes:
            - validation_error
            - invalid_idempotency_key
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_idempotency_key:
                  $ref: "#/components/examples/error_invalid_idempotency_key"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "409":
          description: |-
            Conflict. One of:
            - `idempotency_key_reused`: Idempotency-Key reused.
            - `idempotency_key_in_progress`: Request with this Idempotency-Key in progress.
            - `idempotency_outcome_unknown`: Outcome of the earlier request unknown.
            - `campaign_state_conflict`: Campaign is in the wrong state.
            - `campaign_pause_not_confirmed`: Pause not confirmed.
          x-error-codes:
            - idempotency_key_reused
            - idempotency_key_in_progress
            - idempotency_outcome_unknown
            - campaign_state_conflict
            - campaign_pause_not_confirmed
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                idempotency_key_reused:
                  $ref: "#/components/examples/error_idempotency_key_reused"
                idempotency_key_in_progress:
                  $ref: "#/components/examples/error_idempotency_key_in_progress"
                idempotency_outcome_unknown:
                  $ref: "#/components/examples/error_idempotency_outcome_unknown"
                campaign_state_conflict:
                  $ref: "#/components/examples/error_campaign_state_conflict"
                campaign_pause_not_confirmed:
                  $ref: "#/components/examples/error_campaign_pause_not_confirmed"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /campaigns/{campaign_id}/resume:
    post:
      operationId: resumeCampaign
      summary: Resume a campaign
      externalDocs:
        description: "Guide: Running campaigns"
        url: https://docs.relationsai.com/guides/running-campaigns
      description: |
        Continues a `paused` campaign's run from where it stopped. Before anything is sent, the API checks
        the agent, the account, balance and spend limits, the budget cap, calling hours and the telephony
        connection, and screens **every recipient the run could still call** against the do-not-call list,
        consent and the per-number daily limit.

        A resume cannot drop recipients from a run. So if any remaining recipient is now blocked (for
        example added to the do-not-call list after the campaign started), nothing is resumed, the
        campaign stays `paused`, and you get `409 campaign_recipients_blocked` with the blocked contacts.
        To continue without them, list the recipients still `pending`, create a new campaign with those
        contacts minus the blocked ones, start it, and stop this one (stopping does not hang up calls in
        progress). Do not stop and start this campaign: a new start calls every recipient of the previous
        run again, including people already reached, and charges for those calls. If too many recipients
        remain to re-screen, the resume is refused with `422 campaign_too_large`.

        A resume continues a run its start already counted against the daily call limit, so it counts
        nothing again.
      tags:
        - Campaigns
      x-required-scopes:
        - campaigns:write
      x-idempotency: optional
      x-rate-limit-class: dial
      x-test-mode: Resumes the simulated run, with the same screening as live mode.
      x-availability: preview
      parameters:
        - $ref: "#/components/parameters/CampaignId"
        - $ref: "#/components/parameters/IdempotencyKey"
      responses:
        "200":
          description: The run resumed and the campaign is `running`.
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            ETag:
              $ref: "#/components/headers/ETag"
            Idempotent-Replayed:
              $ref: "#/components/headers/Idempotent-Replayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Campaign"
              examples:
                resumed:
                  $ref: "#/components/examples/campaign_running"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_idempotency_key`: Invalid Idempotency-Key.
          x-error-codes:
            - validation_error
            - invalid_idempotency_key
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_idempotency_key:
                  $ref: "#/components/examples/error_invalid_idempotency_key"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "402":
          description: |-
            Payment required. One of:
            - `insufficient_balance`: Insufficient balance.
            - `spend_limit_reached`: Monthly spend limit reached.
            - `campaign_budget_reached`: Campaign budget reached.
          x-error-codes:
            - insufficient_balance
            - spend_limit_reached
            - campaign_budget_reached
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_balance:
                  $ref: "#/components/examples/error_insufficient_balance"
                spend_limit_reached:
                  $ref: "#/components/examples/error_spend_limit_reached"
                campaign_budget_reached:
                  $ref: "#/components/examples/error_campaign_budget_reached"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
            - `account_inactive`: Workspace account inactive.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
            - account_inactive
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
                account_inactive:
                  $ref: "#/components/examples/error_account_inactive"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "409":
          description: |-
            Conflict. One of:
            - `idempotency_key_reused`: Idempotency-Key reused.
            - `idempotency_key_in_progress`: Request with this Idempotency-Key in progress.
            - `idempotency_outcome_unknown`: Outcome of the earlier request unknown.
            - `campaign_state_conflict`: Campaign is in the wrong state.
            - `campaign_operation_in_progress`: Another start or resume is in progress.
            - `campaign_outcome_unknown`: Campaign start or resume not confirmed.
            - `campaign_not_resumable`: Campaign cannot be resumed.
            - `campaign_recipients_blocked`: Recipients now blocked by compliance.
            - `campaign_dnc_override_enabled`: Campaign calls numbers on the do-not-call list.
          x-error-codes:
            - idempotency_key_reused
            - idempotency_key_in_progress
            - idempotency_outcome_unknown
            - campaign_state_conflict
            - campaign_operation_in_progress
            - campaign_outcome_unknown
            - campaign_not_resumable
            - campaign_recipients_blocked
            - campaign_dnc_override_enabled
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                idempotency_key_reused:
                  $ref: "#/components/examples/error_idempotency_key_reused"
                idempotency_key_in_progress:
                  $ref: "#/components/examples/error_idempotency_key_in_progress"
                idempotency_outcome_unknown:
                  $ref: "#/components/examples/error_idempotency_outcome_unknown"
                campaign_state_conflict:
                  $ref: "#/components/examples/error_campaign_state_conflict"
                campaign_operation_in_progress:
                  $ref: "#/components/examples/error_campaign_operation_in_progress"
                campaign_outcome_unknown:
                  $ref: "#/components/examples/error_campaign_outcome_unknown"
                campaign_not_resumable:
                  $ref: "#/components/examples/error_campaign_not_resumable"
                campaign_recipients_blocked:
                  $ref: "#/components/examples/error_campaign_recipients_blocked"
                campaign_dnc_override_enabled:
                  $ref: "#/components/examples/error_campaign_dnc_override_enabled"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "422":
          description: |-
            Unprocessable. One of:
            - `agent_not_ready`: Agent not ready to call.
            - `calling_not_configured`: Calling not set up.
            - `outside_calling_hours`: Outside calling hours.
            - `campaign_too_large`: Campaign too large.
            - `telephony_disconnected`: Telephony connection down.
          x-error-codes:
            - agent_not_ready
            - calling_not_configured
            - outside_calling_hours
            - campaign_too_large
            - telephony_disconnected
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                agent_not_ready:
                  $ref: "#/components/examples/error_agent_not_ready"
                calling_not_configured:
                  $ref: "#/components/examples/error_calling_not_configured"
                outside_calling_hours:
                  $ref: "#/components/examples/error_outside_calling_hours"
                campaign_too_large:
                  $ref: "#/components/examples/error_campaign_too_large"
                telephony_disconnected:
                  $ref: "#/components/examples/error_telephony_disconnected"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
            - `campaign_recipients_unavailable`: Recipients could not be checked.
          x-error-codes:
            - service_unavailable
            - campaign_recipients_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
                campaign_recipients_unavailable:
                  $ref: "#/components/examples/error_campaign_recipients_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /campaigns/{campaign_id}/stop:
    post:
      operationId: stopCampaign
      summary: Stop a campaign
      externalDocs:
        description: "Guide: Running campaigns"
        url: https://docs.relationsai.com/guides/running-campaigns
      description: |
        Stops a `draft`, `running` or `paused` campaign. No further calls are started; calls already
        connected finish normally. A stopped campaign can be started again, which begins a new run with
        the same recipients.
      tags:
        - Campaigns
      x-required-scopes:
        - campaigns:write
      x-idempotency: optional
      x-rate-limit-class: write
      x-test-mode: Stops the simulated run immediately.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/CampaignId"
        - $ref: "#/components/parameters/IdempotencyKey"
      responses:
        "200":
          description: The campaign is stopped.
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            ETag:
              $ref: "#/components/headers/ETag"
            Idempotent-Replayed:
              $ref: "#/components/headers/Idempotent-Replayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Campaign"
              examples:
                stopped:
                  $ref: "#/components/examples/campaign_stopped"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_idempotency_key`: Invalid Idempotency-Key.
          x-error-codes:
            - validation_error
            - invalid_idempotency_key
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_idempotency_key:
                  $ref: "#/components/examples/error_invalid_idempotency_key"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "409":
          description: |-
            Conflict. One of:
            - `idempotency_key_reused`: Idempotency-Key reused.
            - `idempotency_key_in_progress`: Request with this Idempotency-Key in progress.
            - `idempotency_outcome_unknown`: Outcome of the earlier request unknown.
            - `campaign_state_conflict`: Campaign is in the wrong state.
          x-error-codes:
            - idempotency_key_reused
            - idempotency_key_in_progress
            - idempotency_outcome_unknown
            - campaign_state_conflict
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                idempotency_key_reused:
                  $ref: "#/components/examples/error_idempotency_key_reused"
                idempotency_key_in_progress:
                  $ref: "#/components/examples/error_idempotency_key_in_progress"
                idempotency_outcome_unknown:
                  $ref: "#/components/examples/error_idempotency_outcome_unknown"
                campaign_state_conflict:
                  $ref: "#/components/examples/error_campaign_state_conflict"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /contacts:
    post:
      operationId: createContact
      summary: Create a contact
      externalDocs:
        description: "Guide: Managing contacts"
        url: https://docs.relationsai.com/guides/managing-contacts
      description: |
        Creates a contact. Phone numbers are unique within a workspace and mode; creating a second contact
        with the same number is `409 contact_already_exists` (use the upsert to create-or-update).

        Setting `consent_granted: true` records that the person consented to be called, with the time and
        the API as its source. Only set it when they really did: when the workspace requires consent, it
        is what allows calls to this contact.
      tags:
        - Contacts
      x-required-scopes:
        - contacts:write
      x-idempotency: optional
      x-rate-limit-class: write
      x-test-mode: Creates a test-mode contact, visible only to test keys.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ContactCreateRequest"
            examples:
              contact:
                summary: A contact with consent and custom fields
                value:
                  phone_number: "+12025550100"
                  name: Asha Rao
                  language: en
                  country_code: US
                  consent_granted: true
                  custom_fields:
                    policy_number: PN-55012
                    due_date: 2026-11-05
      responses:
        "201":
          description: The contact was created.
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            ETag:
              $ref: "#/components/headers/ETag"
            Idempotent-Replayed:
              $ref: "#/components/headers/Idempotent-Replayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Contact"
              examples:
                created:
                  $ref: "#/components/examples/contact"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_json`: Invalid JSON body.
            - `invalid_idempotency_key`: Invalid Idempotency-Key.
            - `invalid_phone_number`: Invalid phone number.
          x-error-codes:
            - validation_error
            - invalid_json
            - invalid_idempotency_key
            - invalid_phone_number
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_json:
                  $ref: "#/components/examples/error_invalid_json"
                invalid_idempotency_key:
                  $ref: "#/components/examples/error_invalid_idempotency_key"
                invalid_phone_number:
                  $ref: "#/components/examples/error_invalid_phone_number"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "409":
          description: |-
            Conflict. One of:
            - `idempotency_key_reused`: Idempotency-Key reused.
            - `idempotency_key_in_progress`: Request with this Idempotency-Key in progress.
            - `idempotency_outcome_unknown`: Outcome of the earlier request unknown.
            - `contact_already_exists`: Contact already exists.
            - `contact_limit_reached`: Contact limit reached.
          x-error-codes:
            - idempotency_key_reused
            - idempotency_key_in_progress
            - idempotency_outcome_unknown
            - contact_already_exists
            - contact_limit_reached
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                idempotency_key_reused:
                  $ref: "#/components/examples/error_idempotency_key_reused"
                idempotency_key_in_progress:
                  $ref: "#/components/examples/error_idempotency_key_in_progress"
                idempotency_outcome_unknown:
                  $ref: "#/components/examples/error_idempotency_outcome_unknown"
                contact_already_exists:
                  $ref: "#/components/examples/error_contact_already_exists"
                contact_limit_reached:
                  $ref: "#/components/examples/error_contact_limit_reached"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "413":
          description: |-
            Payload too large. One of:
            - `payload_too_large`: Payload too large.
          x-error-codes:
            - payload_too_large
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                payload_too_large:
                  $ref: "#/components/examples/error_payload_too_large"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "415":
          description: |-
            Unsupported media type. One of:
            - `unsupported_media_type`: Unsupported media type.
          x-error-codes:
            - unsupported_media_type
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                unsupported_media_type:
                  $ref: "#/components/examples/error_unsupported_media_type"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "422":
          description: |-
            Unprocessable. One of:
            - `custom_field_not_found`: Custom field not found.
          x-error-codes:
            - custom_field_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                custom_field_not_found:
                  $ref: "#/components/examples/error_custom_field_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
    get:
      operationId: listContacts
      summary: List contacts
      externalDocs:
        description: "Guide: Managing contacts"
        url: https://docs.relationsai.com/guides/managing-contacts
      description: Lists contacts, newest first. Filter by exact phone number, consent or do-not-call status.
      tags:
        - Contacts
      x-required-scopes:
        - contacts:read
      x-idempotency: none
      x-rate-limit-class: read
      x-test-mode: Lists test-mode contacts only.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
        - $ref: "#/components/parameters/CreatedAfter"
        - $ref: "#/components/parameters/CreatedBefore"
        - name: phone_number
          in: query
          required: false
          description: Only the contact with this number (E.164). Matches the same way the do-not-call check does.
          schema:
            type: string
            format: e164
          example: "+919000000001"
        - name: consent_granted
          in: query
          required: false
          description: Only contacts with (`true`) or without (`false`) recorded consent.
          schema:
            type: boolean
        - name: do_not_call
          in: query
          required: false
          description: Only contacts on (`true`) or off (`false`) the do-not-call list.
          schema:
            type: boolean
      responses:
        "200":
          description: A page of contacts.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ContactList"
              examples:
                contacts:
                  summary: One contact
                  value:
                    object: list
                    data:
                      - id: ct_8Rw2Tq5Lm9Xc3Vb7Nz4Kp1
                        object: contact
                        livemode: false
                        phone_number: "+12025550100"
                        name: Asha Rao
                        language: en
                        country_code: US
                        consent_granted: true
                        do_not_call: false
                        custom_fields:
                          policy_number: PN-55012
                          due_date: 2026-11-05
                        created_at: 2026-10-21T08:30:00.000Z
                    has_more: false
                    next_cursor: null
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_cursor`: Invalid pagination cursor.
            - `invalid_phone_number`: Invalid phone number.
          x-error-codes:
            - validation_error
            - invalid_cursor
            - invalid_phone_number
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_cursor:
                  $ref: "#/components/examples/error_invalid_cursor"
                invalid_phone_number:
                  $ref: "#/components/examples/error_invalid_phone_number"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /contacts/upsert:
    post:
      operationId: upsertContact
      summary: Create or update a contact by phone number
      externalDocs:
        description: "Guide: Managing contacts"
        url: https://docs.relationsai.com/guides/managing-contacts
      description: |
        Creates the contact with this phone number, or updates it if one exists, in one request. The
        number is matched the same way the do-not-call check matches numbers, so a contact entered
        without the `+` and country code in the console is found too. Fields you omit are left unchanged
        on an existing contact. The response is `201` when a contact was created and `200` when one was
        updated. This is the recommended way to sync contacts from your CRM.
      tags:
        - Contacts
      x-required-scopes:
        - contacts:write
      x-idempotency: optional
      x-rate-limit-class: write
      x-test-mode: Upserts a test-mode contact.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ContactUpsertRequest"
            examples:
              upsert:
                summary: Sync from a CRM
                value:
                  phone_number: "+919000000001"
                  name: Asha Rao
                  consent_granted: true
                  custom_fields:
                    policy_number: PN-55012
      responses:
        "200":
          description: An existing contact was updated.
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            ETag:
              $ref: "#/components/headers/ETag"
            Idempotent-Replayed:
              $ref: "#/components/headers/Idempotent-Replayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Contact"
              examples:
                updated:
                  $ref: "#/components/examples/contact_live"
        "201":
          description: A new contact was created.
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            ETag:
              $ref: "#/components/headers/ETag"
            Idempotent-Replayed:
              $ref: "#/components/headers/Idempotent-Replayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Contact"
              examples:
                created:
                  $ref: "#/components/examples/contact"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_json`: Invalid JSON body.
            - `invalid_idempotency_key`: Invalid Idempotency-Key.
            - `invalid_phone_number`: Invalid phone number.
          x-error-codes:
            - validation_error
            - invalid_json
            - invalid_idempotency_key
            - invalid_phone_number
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_json:
                  $ref: "#/components/examples/error_invalid_json"
                invalid_idempotency_key:
                  $ref: "#/components/examples/error_invalid_idempotency_key"
                invalid_phone_number:
                  $ref: "#/components/examples/error_invalid_phone_number"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "409":
          description: |-
            Conflict. One of:
            - `idempotency_key_reused`: Idempotency-Key reused.
            - `idempotency_key_in_progress`: Request with this Idempotency-Key in progress.
            - `idempotency_outcome_unknown`: Outcome of the earlier request unknown.
            - `contact_limit_reached`: Contact limit reached.
          x-error-codes:
            - idempotency_key_reused
            - idempotency_key_in_progress
            - idempotency_outcome_unknown
            - contact_limit_reached
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                idempotency_key_reused:
                  $ref: "#/components/examples/error_idempotency_key_reused"
                idempotency_key_in_progress:
                  $ref: "#/components/examples/error_idempotency_key_in_progress"
                idempotency_outcome_unknown:
                  $ref: "#/components/examples/error_idempotency_outcome_unknown"
                contact_limit_reached:
                  $ref: "#/components/examples/error_contact_limit_reached"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "413":
          description: |-
            Payload too large. One of:
            - `payload_too_large`: Payload too large.
          x-error-codes:
            - payload_too_large
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                payload_too_large:
                  $ref: "#/components/examples/error_payload_too_large"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "415":
          description: |-
            Unsupported media type. One of:
            - `unsupported_media_type`: Unsupported media type.
          x-error-codes:
            - unsupported_media_type
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                unsupported_media_type:
                  $ref: "#/components/examples/error_unsupported_media_type"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "422":
          description: |-
            Unprocessable. One of:
            - `custom_field_not_found`: Custom field not found.
          x-error-codes:
            - custom_field_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                custom_field_not_found:
                  $ref: "#/components/examples/error_custom_field_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /contacts/{contact_id}:
    get:
      operationId: getContact
      summary: Retrieve a contact
      externalDocs:
        description: "Guide: Managing contacts"
        url: https://docs.relationsai.com/guides/managing-contacts
      description: Returns one contact, with its consent, do-not-call status and custom field values. The `ETag` header is the version to send as `If-Match` when you update it.
      tags:
        - Contacts
      x-required-scopes:
        - contacts:read
      x-idempotency: none
      x-rate-limit-class: read
      x-test-mode: Returns test-mode contacts.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/ContactId"
      responses:
        "200":
          description: The contact.
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            ETag:
              $ref: "#/components/headers/ETag"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Contact"
              examples:
                contact:
                  $ref: "#/components/examples/contact_live"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
          x-error-codes:
            - validation_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
    patch:
      operationId: updateContact
      summary: Update a contact
      externalDocs:
        description: "Guide: Managing contacts"
        url: https://docs.relationsai.com/guides/managing-contacts
      description: |
        Changes the fields you send. `custom_fields` merges: listed fields are set, a null value clears a
        field, omitted fields are kept. `consent_granted` records consent (true) or its withdrawal (false)
        with the time and the API as source. The do-not-call status cannot be changed here; use the
        do-not-call endpoints. Requires `If-Match` with the contact's current `ETag`.
      tags:
        - Contacts
      x-required-scopes:
        - contacts:write
      x-idempotency: none
      x-rate-limit-class: write
      x-test-mode: Updates a test-mode contact.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/ContactId"
        - $ref: "#/components/parameters/IfMatch"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ContactUpdateRequest"
            examples:
              withdraw:
                summary: Record that consent was withdrawn
                value:
                  consent_granted: false
              fields:
                summary: Update a custom field and clear another
                value:
                  custom_fields:
                    due_date: 2026-12-05
                    policy_number: null
      responses:
        "200":
          description: The updated contact, with its new `ETag`.
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            ETag:
              $ref: "#/components/headers/ETag"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Contact"
              examples:
                updated:
                  $ref: "#/components/examples/contact_live"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_json`: Invalid JSON body.
            - `invalid_phone_number`: Invalid phone number.
          x-error-codes:
            - validation_error
            - invalid_json
            - invalid_phone_number
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_json:
                  $ref: "#/components/examples/error_invalid_json"
                invalid_phone_number:
                  $ref: "#/components/examples/error_invalid_phone_number"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "409":
          description: |-
            Conflict. One of:
            - `contact_already_exists`: Contact already exists.
          x-error-codes:
            - contact_already_exists
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                contact_already_exists:
                  $ref: "#/components/examples/error_contact_already_exists"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "412":
          description: |-
            Precondition failed. One of:
            - `version_conflict`: Version conflict.
          x-error-codes:
            - version_conflict
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                version_conflict:
                  $ref: "#/components/examples/error_version_conflict"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "413":
          description: |-
            Payload too large. One of:
            - `payload_too_large`: Payload too large.
          x-error-codes:
            - payload_too_large
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                payload_too_large:
                  $ref: "#/components/examples/error_payload_too_large"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "415":
          description: |-
            Unsupported media type. One of:
            - `unsupported_media_type`: Unsupported media type.
          x-error-codes:
            - unsupported_media_type
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                unsupported_media_type:
                  $ref: "#/components/examples/error_unsupported_media_type"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "422":
          description: |-
            Unprocessable. One of:
            - `custom_field_not_found`: Custom field not found.
          x-error-codes:
            - custom_field_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                custom_field_not_found:
                  $ref: "#/components/examples/error_custom_field_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "428":
          description: |-
            Precondition required. One of:
            - `precondition_required`: If-Match required.
          x-error-codes:
            - precondition_required
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                precondition_required:
                  $ref: "#/components/examples/error_precondition_required"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
    delete:
      operationId: deleteContact
      summary: Delete a contact
      externalDocs:
        description: "Guide: Managing contacts"
        url: https://docs.relationsai.com/guides/managing-contacts
      description: |
        Permanently deletes a contact, its custom field values and its consent history, and removes it
        from every campaign's recipient list (a campaign that has already started keeps calling the
        recipients its run began with). Calls to the contact remain in the call list. A contact on
        the do-not-call list cannot be deleted (`409 contact_on_dnc_list`), so a deletion never removes a
        do-not-call protection.
      tags:
        - Contacts
      x-required-scopes:
        - contacts:write
      x-idempotency: optional
      x-rate-limit-class: write
      x-test-mode: Deletes a test-mode contact.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/ContactId"
        - $ref: "#/components/parameters/IdempotencyKey"
      responses:
        "200":
          description: The contact was deleted.
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Idempotent-Replayed:
              $ref: "#/components/headers/Idempotent-Replayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeletedObject"
              examples:
                deleted:
                  summary: Deleted
                  value:
                    id: ct_8Rw2Tq5Lm9Xc3Vb7Nz4Kp1
                    object: contact
                    livemode: false
                    deleted: true
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_idempotency_key`: Invalid Idempotency-Key.
          x-error-codes:
            - validation_error
            - invalid_idempotency_key
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_idempotency_key:
                  $ref: "#/components/examples/error_invalid_idempotency_key"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "409":
          description: |-
            Conflict. One of:
            - `idempotency_key_reused`: Idempotency-Key reused.
            - `idempotency_key_in_progress`: Request with this Idempotency-Key in progress.
            - `idempotency_outcome_unknown`: Outcome of the earlier request unknown.
            - `contact_on_dnc_list`: Contact is on the do-not-call list.
          x-error-codes:
            - idempotency_key_reused
            - idempotency_key_in_progress
            - idempotency_outcome_unknown
            - contact_on_dnc_list
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                idempotency_key_reused:
                  $ref: "#/components/examples/error_idempotency_key_reused"
                idempotency_key_in_progress:
                  $ref: "#/components/examples/error_idempotency_key_in_progress"
                idempotency_outcome_unknown:
                  $ref: "#/components/examples/error_idempotency_outcome_unknown"
                contact_on_dnc_list:
                  $ref: "#/components/examples/error_contact_on_dnc_list"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /dnc-entries:
    post:
      operationId: createDncEntry
      summary: Add a number to the do-not-call list
      externalDocs:
        description: "Guide: Consent and the do-not-call list"
        url: https://docs.relationsai.com/guides/consent-and-dnc
      description: |
        Adds a number to the workspace do-not-call list, in the key's mode. From then on calls to it are
        refused, campaigns leave it out when they start, and a paused campaign that still holds it cannot be
        resumed. A campaign that is already running is not screened again: pause and resume it (the resume
        is then refused while the number is a remaining recipient) or stop it.

        If a contact has this number, it is marked `do_not_call: true` and its consent is withdrawn. If no
        contact has it, a contact holding only the number is created so the number is visible in the
        console. Adding a number that is already on the list returns the existing entry with `200`.
      tags:
        - Do-not-call list
      x-required-scopes:
        - dnc:write
      x-idempotency: optional
      x-rate-limit-class: write
      x-test-mode: Adds the number to the test-mode list, which blocks test calls exactly like live mode.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DncEntryCreateRequest"
            examples:
              add:
                summary: Block a number
                value:
                  phone_number: "+919000000003"
      responses:
        "200":
          description: The number was already on the list; the existing entry is returned.
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Idempotent-Replayed:
              $ref: "#/components/headers/Idempotent-Replayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DncEntry"
              examples:
                existing:
                  summary: Already listed
                  value:
                    id: dnc_4Ty8Ui2Op6As3Df9Gh7Jk5
                    object: dnc_entry
                    livemode: true
                    phone_number: "+919000000003"
                    contact_id: ct_5Qw8Er2Ty6Ui9Op3As7Df4
                    created_at: null
        "201":
          description: The number was added.
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Idempotent-Replayed:
              $ref: "#/components/headers/Idempotent-Replayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DncEntry"
              examples:
                created:
                  summary: Added
                  value:
                    id: dnc_4Ty8Ui2Op6As3Df9Gh7Jk5
                    object: dnc_entry
                    livemode: true
                    phone_number: "+919000000003"
                    contact_id: ct_5Qw8Er2Ty6Ui9Op3As7Df4
                    created_at: null
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_json`: Invalid JSON body.
            - `invalid_idempotency_key`: Invalid Idempotency-Key.
            - `invalid_phone_number`: Invalid phone number.
          x-error-codes:
            - validation_error
            - invalid_json
            - invalid_idempotency_key
            - invalid_phone_number
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_json:
                  $ref: "#/components/examples/error_invalid_json"
                invalid_idempotency_key:
                  $ref: "#/components/examples/error_invalid_idempotency_key"
                invalid_phone_number:
                  $ref: "#/components/examples/error_invalid_phone_number"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "409":
          description: |-
            Conflict. One of:
            - `idempotency_key_reused`: Idempotency-Key reused.
            - `idempotency_key_in_progress`: Request with this Idempotency-Key in progress.
            - `idempotency_outcome_unknown`: Outcome of the earlier request unknown.
            - `contact_limit_reached`: Contact limit reached.
          x-error-codes:
            - idempotency_key_reused
            - idempotency_key_in_progress
            - idempotency_outcome_unknown
            - contact_limit_reached
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                idempotency_key_reused:
                  $ref: "#/components/examples/error_idempotency_key_reused"
                idempotency_key_in_progress:
                  $ref: "#/components/examples/error_idempotency_key_in_progress"
                idempotency_outcome_unknown:
                  $ref: "#/components/examples/error_idempotency_outcome_unknown"
                contact_limit_reached:
                  $ref: "#/components/examples/error_contact_limit_reached"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "413":
          description: |-
            Payload too large. One of:
            - `payload_too_large`: Payload too large.
          x-error-codes:
            - payload_too_large
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                payload_too_large:
                  $ref: "#/components/examples/error_payload_too_large"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "415":
          description: |-
            Unsupported media type. One of:
            - `unsupported_media_type`: Unsupported media type.
          x-error-codes:
            - unsupported_media_type
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                unsupported_media_type:
                  $ref: "#/components/examples/error_unsupported_media_type"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
    get:
      operationId: listDncEntries
      summary: List or look up do-not-call entries
      externalDocs:
        description: "Guide: Consent and the do-not-call list"
        url: https://docs.relationsai.com/guides/consent-and-dnc
      description: |
        Lists the do-not-call list: in test mode newest entry first; in live mode by the contact,
        newest first (live mode does not record when an entry was added). To check one number, pass `phone_number`: the result has
        one entry if the number is on the list and none if it is not, using the same matching as the call
        check (formatting is ignored).
      tags:
        - Do-not-call list
      x-required-scopes:
        - dnc:read
      x-idempotency: none
      x-rate-limit-class: read
      x-test-mode: Lists the test-mode list only.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
        - name: phone_number
          in: query
          required: false
          description: Look up one number (E.164).
          schema:
            type: string
            format: e164
          example: "+919000000003"
      responses:
        "200":
          description: A page of entries.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DncEntryList"
              examples:
                lookup_hit:
                  summary: The number is listed
                  value:
                    object: list
                    data:
                      - id: dnc_4Ty8Ui2Op6As3Df9Gh7Jk5
                        object: dnc_entry
                        livemode: true
                        phone_number: "+919000000003"
                        contact_id: ct_5Qw8Er2Ty6Ui9Op3As7Df4
                        created_at: null
                    has_more: false
                    next_cursor: null
                lookup_miss:
                  summary: The number is not listed
                  value:
                    object: list
                    data: []
                    has_more: false
                    next_cursor: null
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_cursor`: Invalid pagination cursor.
            - `invalid_phone_number`: Invalid phone number.
          x-error-codes:
            - validation_error
            - invalid_cursor
            - invalid_phone_number
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_cursor:
                  $ref: "#/components/examples/error_invalid_cursor"
                invalid_phone_number:
                  $ref: "#/components/examples/error_invalid_phone_number"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /dnc-entries/{dnc_entry_id}:
    delete:
      operationId: deleteDncEntry
      summary: Remove a number from the do-not-call list
      externalDocs:
        description: "Guide: Consent and the do-not-call list"
        url: https://docs.relationsai.com/guides/consent-and-dnc
      description: |
        Removes a number from the do-not-call list, so it can be called again. The removal is recorded in
        the workspace audit log with the API key that made it. Consent is not restored: if the workspace
        requires consent, record it again on the contact only if the person gives it.
      tags:
        - Do-not-call list
      x-required-scopes:
        - dnc:write
      x-idempotency: optional
      x-rate-limit-class: write
      x-test-mode: Removes a test-mode entry.
      x-availability: ga-candidate
      parameters:
        - $ref: "#/components/parameters/DncEntryId"
        - $ref: "#/components/parameters/IdempotencyKey"
      responses:
        "200":
          description: The number is no longer on the list.
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Idempotent-Replayed:
              $ref: "#/components/headers/Idempotent-Replayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeletedObject"
              examples:
                deleted:
                  summary: Removed
                  value:
                    id: dnc_4Ty8Ui2Op6As3Df9Gh7Jk5
                    object: dnc_entry
                    livemode: true
                    deleted: true
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_idempotency_key`: Invalid Idempotency-Key.
          x-error-codes:
            - validation_error
            - invalid_idempotency_key
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_idempotency_key:
                  $ref: "#/components/examples/error_invalid_idempotency_key"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "409":
          description: |-
            Conflict. One of:
            - `idempotency_key_reused`: Idempotency-Key reused.
            - `idempotency_key_in_progress`: Request with this Idempotency-Key in progress.
            - `idempotency_outcome_unknown`: Outcome of the earlier request unknown.
          x-error-codes:
            - idempotency_key_reused
            - idempotency_key_in_progress
            - idempotency_outcome_unknown
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                idempotency_key_reused:
                  $ref: "#/components/examples/error_idempotency_key_reused"
                idempotency_key_in_progress:
                  $ref: "#/components/examples/error_idempotency_key_in_progress"
                idempotency_outcome_unknown:
                  $ref: "#/components/examples/error_idempotency_outcome_unknown"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /webhook-endpoints:
    post:
      operationId: createWebhookEndpoint
      externalDocs:
        description: "Guide: Receiving webhooks"
        url: https://docs.relationsai.com/guides/receiving-webhooks
      summary: Create a webhook endpoint
      description: |
        Registers an HTTPS URL to receive events of the key's mode. The response contains the signing
        secret (`whsec_...`) **once**; store it to verify signatures. A replay with the same Idempotency-Key
        returns the same endpoint with `secret: null` (the secret is never stored in readable form; if it was lost,
        rotate it). Every delivery is a POST with the
        event as JSON and these headers: `RelationsAI-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of
        "<t>.<raw body>" with the secret>`, `RelationsAI-Event-Id`, `RelationsAI-Event-Type`,
        `RelationsAI-Delivery-Id` and `User-Agent: RelationsAI-Webhooks/1.0`. Reject a signature older
        than 5 minutes.

        Answer with any 2xx within 10 seconds. Anything else is retried after about 10 seconds, 1 minute,
        5 minutes, 30 minutes, 2 hours, 6 hours and 12 hours, then marked `failed`. Delivery is
        at-least-once and unordered. Redirects are not followed. The URL must be public HTTPS on port 443.
        Back-pressure: at most 2 attempts are in flight to one endpoint at a time; after 5 failed attempts in a
        row an endpoint is paused (1 minute, doubling up to 1 hour) and its waiting deliveries are attempted
        after the pause, without using up their attempts; one success resumes it. The endpoint is never
        disabled automatically. Live-mode deliveries are attempted before test-mode ones, and a workspace's
        test-mode deliveries are limited to 60 attempts a minute.
      tags:
        - Webhook endpoints
      x-required-scopes:
        - webhooks:write
      x-idempotency: optional
      x-rate-limit-class: write
      x-test-mode: Creates a test-mode endpoint that receives only test-mode events (`livemode` false).
      x-availability: preview
      parameters:
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WebhookEndpointCreateRequest"
            examples:
              endpoint:
                summary: Call and campaign events
                value:
                  url: https://example.com/webhooks/relationsai
                  description: CRM sync (test)
                  events:
                    - call.ended
                    - call.settled
                    - campaign.completed
      responses:
        "201":
          description: The endpoint was created. Store `secret` now; it is not shown again.
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Idempotent-Replayed:
              $ref: "#/components/headers/Idempotent-Replayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookEndpointWithSecret"
              examples:
                created:
                  $ref: "#/components/examples/endpoint_with_secret"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_json`: Invalid JSON body.
            - `invalid_idempotency_key`: Invalid Idempotency-Key.
          x-error-codes:
            - validation_error
            - invalid_json
            - invalid_idempotency_key
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_json:
                  $ref: "#/components/examples/error_invalid_json"
                invalid_idempotency_key:
                  $ref: "#/components/examples/error_invalid_idempotency_key"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
            - `webhooks_not_enabled`: Webhooks not enabled.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
            - webhooks_not_enabled
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
                webhooks_not_enabled:
                  $ref: "#/components/examples/error_webhooks_not_enabled"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "409":
          description: |-
            Conflict. One of:
            - `idempotency_key_reused`: Idempotency-Key reused.
            - `idempotency_key_in_progress`: Request with this Idempotency-Key in progress.
            - `idempotency_outcome_unknown`: Outcome of the earlier request unknown.
            - `webhook_endpoint_limit_reached`: Webhook endpoint limit reached.
          x-error-codes:
            - idempotency_key_reused
            - idempotency_key_in_progress
            - idempotency_outcome_unknown
            - webhook_endpoint_limit_reached
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                idempotency_key_reused:
                  $ref: "#/components/examples/error_idempotency_key_reused"
                idempotency_key_in_progress:
                  $ref: "#/components/examples/error_idempotency_key_in_progress"
                idempotency_outcome_unknown:
                  $ref: "#/components/examples/error_idempotency_outcome_unknown"
                webhook_endpoint_limit_reached:
                  $ref: "#/components/examples/error_webhook_endpoint_limit_reached"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "413":
          description: |-
            Payload too large. One of:
            - `payload_too_large`: Payload too large.
          x-error-codes:
            - payload_too_large
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                payload_too_large:
                  $ref: "#/components/examples/error_payload_too_large"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "415":
          description: |-
            Unsupported media type. One of:
            - `unsupported_media_type`: Unsupported media type.
          x-error-codes:
            - unsupported_media_type
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                unsupported_media_type:
                  $ref: "#/components/examples/error_unsupported_media_type"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "422":
          description: |-
            Unprocessable. One of:
            - `webhook_url_not_allowed`: Webhook URL not allowed.
          x-error-codes:
            - webhook_url_not_allowed
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                webhook_url_not_allowed:
                  $ref: "#/components/examples/error_webhook_url_not_allowed"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
    get:
      operationId: listWebhookEndpoints
      externalDocs:
        description: "Guide: Receiving webhooks"
        url: https://docs.relationsai.com/guides/receiving-webhooks
      summary: List webhook endpoints
      description: Lists the webhook endpoints of the key's mode, newest first. Secrets are never listed, only their last four characters.
      tags:
        - Webhook endpoints
      x-required-scopes:
        - webhooks:read
      x-idempotency: none
      x-rate-limit-class: read
      x-test-mode: Lists test-mode endpoints only.
      x-availability: preview
      parameters:
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: A page of endpoints.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookEndpointList"
              examples:
                endpoints:
                  summary: One endpoint
                  value:
                    object: list
                    data:
                      - id: we_9Pl3Ok7Ij2Uh6Yg4Tf8Rd1
                        object: webhook_endpoint
                        livemode: false
                        url: https://example.com/webhooks/relationsai
                        description: CRM sync (test)
                        events:
                          - call.ended
                          - call.settled
                          - campaign.completed
                        status: enabled
                        secret_last4: x9Qa
                        created_at: 2026-10-21T08:00:00.000Z
                        updated_at: 2026-10-21T08:00:00.000Z
                        last_delivery: null
                    has_more: false
                    next_cursor: null
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_cursor`: Invalid pagination cursor.
          x-error-codes:
            - validation_error
            - invalid_cursor
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_cursor:
                  $ref: "#/components/examples/error_invalid_cursor"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /webhook-endpoints/{webhook_endpoint_id}:
    get:
      operationId: getWebhookEndpoint
      externalDocs:
        description: "Guide: Receiving webhooks"
        url: https://docs.relationsai.com/guides/receiving-webhooks
      summary: Retrieve a webhook endpoint
      description: Returns one webhook endpoint with a summary of its most recent delivery.
      tags:
        - Webhook endpoints
      x-required-scopes:
        - webhooks:read
      x-idempotency: none
      x-rate-limit-class: read
      x-test-mode: Returns test-mode endpoints.
      x-availability: preview
      parameters:
        - $ref: "#/components/parameters/WebhookEndpointId"
      responses:
        "200":
          description: The endpoint.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookEndpoint"
              examples:
                endpoint:
                  $ref: "#/components/examples/endpoint"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
          x-error-codes:
            - validation_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
    patch:
      operationId: updateWebhookEndpoint
      externalDocs:
        description: "Guide: Receiving webhooks"
        url: https://docs.relationsai.com/guides/receiving-webhooks
      summary: Update a webhook endpoint
      description: Changes the URL, description, subscribed events or status. Disabling an endpoint stops new deliveries to it; events that occur while it is disabled are not delivered later.
      tags:
        - Webhook endpoints
      x-required-scopes:
        - webhooks:write
      x-idempotency: none
      x-rate-limit-class: write
      x-test-mode: Updates a test-mode endpoint.
      x-availability: preview
      parameters:
        - $ref: "#/components/parameters/WebhookEndpointId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WebhookEndpointUpdateRequest"
            examples:
              disable:
                summary: Disable the endpoint
                value:
                  status: disabled
      responses:
        "200":
          description: The updated endpoint.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookEndpoint"
              examples:
                endpoint:
                  $ref: "#/components/examples/endpoint"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_json`: Invalid JSON body.
          x-error-codes:
            - validation_error
            - invalid_json
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_json:
                  $ref: "#/components/examples/error_invalid_json"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "413":
          description: |-
            Payload too large. One of:
            - `payload_too_large`: Payload too large.
          x-error-codes:
            - payload_too_large
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                payload_too_large:
                  $ref: "#/components/examples/error_payload_too_large"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "415":
          description: |-
            Unsupported media type. One of:
            - `unsupported_media_type`: Unsupported media type.
          x-error-codes:
            - unsupported_media_type
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                unsupported_media_type:
                  $ref: "#/components/examples/error_unsupported_media_type"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "422":
          description: |-
            Unprocessable. One of:
            - `webhook_url_not_allowed`: Webhook URL not allowed.
          x-error-codes:
            - webhook_url_not_allowed
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                webhook_url_not_allowed:
                  $ref: "#/components/examples/error_webhook_url_not_allowed"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
    delete:
      operationId: deleteWebhookEndpoint
      externalDocs:
        description: "Guide: Receiving webhooks"
        url: https://docs.relationsai.com/guides/receiving-webhooks
      summary: Delete a webhook endpoint
      description: Deletes the endpoint. Pending deliveries to it are cancelled. This cannot be undone.
      tags:
        - Webhook endpoints
      x-required-scopes:
        - webhooks:write
      x-idempotency: optional
      x-rate-limit-class: write
      x-test-mode: Deletes a test-mode endpoint.
      x-availability: preview
      parameters:
        - $ref: "#/components/parameters/WebhookEndpointId"
        - $ref: "#/components/parameters/IdempotencyKey"
      responses:
        "200":
          description: The endpoint was deleted.
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Idempotent-Replayed:
              $ref: "#/components/headers/Idempotent-Replayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeletedObject"
              examples:
                deleted:
                  summary: Deleted
                  value:
                    id: we_9Pl3Ok7Ij2Uh6Yg4Tf8Rd1
                    object: webhook_endpoint
                    livemode: false
                    deleted: true
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_idempotency_key`: Invalid Idempotency-Key.
          x-error-codes:
            - validation_error
            - invalid_idempotency_key
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_idempotency_key:
                  $ref: "#/components/examples/error_invalid_idempotency_key"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "409":
          description: |-
            Conflict. One of:
            - `idempotency_key_reused`: Idempotency-Key reused.
            - `idempotency_key_in_progress`: Request with this Idempotency-Key in progress.
            - `idempotency_outcome_unknown`: Outcome of the earlier request unknown.
          x-error-codes:
            - idempotency_key_reused
            - idempotency_key_in_progress
            - idempotency_outcome_unknown
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                idempotency_key_reused:
                  $ref: "#/components/examples/error_idempotency_key_reused"
                idempotency_key_in_progress:
                  $ref: "#/components/examples/error_idempotency_key_in_progress"
                idempotency_outcome_unknown:
                  $ref: "#/components/examples/error_idempotency_outcome_unknown"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /webhook-endpoints/{webhook_endpoint_id}/rotate-secret:
    post:
      operationId: rotateWebhookEndpointSecret
      externalDocs:
        description: "Guide: Verifying webhook signatures"
        url: https://docs.relationsai.com/guides/verifying-webhook-signatures
      summary: Rotate a webhook signing secret
      description: |
        Issues a new signing secret, returned once. During the grace period every delivery carries two
        `v1=` signatures, one per secret, so you can deploy the new secret without missing events; after
        it, only the new secret signs. At most two secrets ever sign a delivery.

        Rotating again while a grace period runs:
        - `grace_period_hours: 0` is always allowed and retires EVERY previous secret immediately: use it when a
          secret may have leaked, and deploy the new one at once.
        - a grace period above 0 keeps the OLDEST secret still signing (the one your receiver most likely uses)
          until its original grace end, discards the secret issued by the rotation in between, and issues a new
          one. Use it when the response to a rotation was lost.

        A replay of this request with the same Idempotency-Key returns the endpoint with `secret: null`: the
        secret is shown only in the first response and is never stored in readable form. To recover a secret
        you did not receive, rotate again (with a grace period, as above).
      tags:
        - Webhook endpoints
      x-required-scopes:
        - webhooks:write
      x-idempotency: optional
      x-rate-limit-class: write
      x-test-mode: Rotates a test-mode endpoint's secret.
      x-availability: preview
      parameters:
        - $ref: "#/components/parameters/WebhookEndpointId"
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WebhookSecretRotateRequest"
            examples:
              day:
                summary: Keep the old secret for 24 hours
                value:
                  grace_period_hours: 24
      responses:
        "200":
          description: The endpoint with its new secret. Store it now.
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Idempotent-Replayed:
              $ref: "#/components/headers/Idempotent-Replayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookEndpointWithSecret"
              examples:
                rotated:
                  $ref: "#/components/examples/endpoint_with_secret"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_json`: Invalid JSON body.
            - `invalid_idempotency_key`: Invalid Idempotency-Key.
          x-error-codes:
            - validation_error
            - invalid_json
            - invalid_idempotency_key
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_json:
                  $ref: "#/components/examples/error_invalid_json"
                invalid_idempotency_key:
                  $ref: "#/components/examples/error_invalid_idempotency_key"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "409":
          description: |-
            Conflict. One of:
            - `idempotency_key_reused`: Idempotency-Key reused.
            - `idempotency_key_in_progress`: Request with this Idempotency-Key in progress.
            - `idempotency_outcome_unknown`: Outcome of the earlier request unknown.
          x-error-codes:
            - idempotency_key_reused
            - idempotency_key_in_progress
            - idempotency_outcome_unknown
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                idempotency_key_reused:
                  $ref: "#/components/examples/error_idempotency_key_reused"
                idempotency_key_in_progress:
                  $ref: "#/components/examples/error_idempotency_key_in_progress"
                idempotency_outcome_unknown:
                  $ref: "#/components/examples/error_idempotency_outcome_unknown"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "413":
          description: |-
            Payload too large. One of:
            - `payload_too_large`: Payload too large.
          x-error-codes:
            - payload_too_large
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                payload_too_large:
                  $ref: "#/components/examples/error_payload_too_large"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "415":
          description: |-
            Unsupported media type. One of:
            - `unsupported_media_type`: Unsupported media type.
          x-error-codes:
            - unsupported_media_type
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                unsupported_media_type:
                  $ref: "#/components/examples/error_unsupported_media_type"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /webhook-endpoints/{webhook_endpoint_id}/test:
    post:
      operationId: sendWebhookEndpointTestEvent
      externalDocs:
        description: "Guide: Verifying webhook signatures"
        url: https://docs.relationsai.com/guides/verifying-webhook-signatures
      summary: Send a test event
      description: Creates a `webhook_endpoint.test` event and delivers it to this endpoint only, signed like any other event. The response is the delivery, usually `pending`; read the deliveries list to see the result.
      tags:
        - Webhook endpoints
      x-required-scopes:
        - webhooks:write
      x-idempotency: optional
      x-rate-limit-class: write
      x-test-mode: Works the same in both modes; the event has the endpoint's mode.
      x-availability: preview
      parameters:
        - $ref: "#/components/parameters/WebhookEndpointId"
        - $ref: "#/components/parameters/IdempotencyKey"
      responses:
        "202":
          description: The test event was created and its delivery scheduled.
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Idempotent-Replayed:
              $ref: "#/components/headers/Idempotent-Replayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookDelivery"
              examples:
                scheduled:
                  $ref: "#/components/examples/delivery_pending"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_idempotency_key`: Invalid Idempotency-Key.
          x-error-codes:
            - validation_error
            - invalid_idempotency_key
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_idempotency_key:
                  $ref: "#/components/examples/error_invalid_idempotency_key"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
            - `webhooks_not_enabled`: Webhooks not enabled.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
            - webhooks_not_enabled
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
                webhooks_not_enabled:
                  $ref: "#/components/examples/error_webhooks_not_enabled"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "409":
          description: |-
            Conflict. One of:
            - `idempotency_key_reused`: Idempotency-Key reused.
            - `idempotency_key_in_progress`: Request with this Idempotency-Key in progress.
            - `idempotency_outcome_unknown`: Outcome of the earlier request unknown.
            - `webhook_endpoint_disabled`: Webhook endpoint disabled.
          x-error-codes:
            - idempotency_key_reused
            - idempotency_key_in_progress
            - idempotency_outcome_unknown
            - webhook_endpoint_disabled
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                idempotency_key_reused:
                  $ref: "#/components/examples/error_idempotency_key_reused"
                idempotency_key_in_progress:
                  $ref: "#/components/examples/error_idempotency_key_in_progress"
                idempotency_outcome_unknown:
                  $ref: "#/components/examples/error_idempotency_outcome_unknown"
                webhook_endpoint_disabled:
                  $ref: "#/components/examples/error_webhook_endpoint_disabled"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /webhook-endpoints/{webhook_endpoint_id}/deliveries:
    get:
      operationId: listWebhookDeliveries
      externalDocs:
        description: "Guide: Receiving webhooks"
        url: https://docs.relationsai.com/guides/receiving-webhooks
      summary: List deliveries
      description: Lists deliveries to this endpoint, newest first, for troubleshooting. Deliveries are kept for 30 days.
      tags:
        - Webhook endpoints
      x-required-scopes:
        - webhooks:read
      x-idempotency: none
      x-rate-limit-class: read
      x-test-mode: Lists deliveries of a test-mode endpoint.
      x-availability: preview
      parameters:
        - $ref: "#/components/parameters/WebhookEndpointId"
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
        - name: status
          in: query
          required: false
          description: Only deliveries in this status.
          schema:
            type: string
            enum:
              - pending
              - retrying
              - succeeded
              - failed
      responses:
        "200":
          description: A page of deliveries.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookDeliveryList"
              examples:
                deliveries:
                  summary: One delivery
                  value:
                    object: list
                    data:
                      - id: wd_1Qa5Ws9Ed3Rf7Tg2Yh6Uj4
                        object: webhook_delivery
                        livemode: false
                        webhook_endpoint_id: we_9Pl3Ok7Ij2Uh6Yg4Tf8Rd1
                        event_id: evt_5Zx9Cv3Bn7Mq2Wl8Ek4Rt6
                        event_type: call.ended
                        status: succeeded
                        attempts: 1
                        last_attempt_at: 2026-10-21T09:31:02.000Z
                        next_attempt_at: null
                        response_status: 200
                        duration_ms: 184
                        error: null
                        created_at: 2026-10-21T09:31:01.000Z
                    has_more: false
                    next_cursor: null
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_cursor`: Invalid pagination cursor.
          x-error-codes:
            - validation_error
            - invalid_cursor
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_cursor:
                  $ref: "#/components/examples/error_invalid_cursor"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
  /webhook-deliveries/{webhook_delivery_id}/retry:
    post:
      operationId: retryWebhookDelivery
      externalDocs:
        description: "Guide: Receiving webhooks"
        url: https://docs.relationsai.com/guides/receiving-webhooks
      summary: Retry a delivery
      description: Schedules an immediate new attempt of a `failed` or `retrying` delivery. The event and its id are unchanged, so your duplicate check still works.
      tags:
        - Webhook endpoints
      x-required-scopes:
        - webhooks:write
      x-idempotency: optional
      x-rate-limit-class: write
      x-test-mode: Retries a test-mode delivery.
      x-availability: preview
      parameters:
        - $ref: "#/components/parameters/WebhookDeliveryId"
        - $ref: "#/components/parameters/IdempotencyKey"
      responses:
        "202":
          description: A new attempt was scheduled.
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Idempotent-Replayed:
              $ref: "#/components/headers/Idempotent-Replayed"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookDelivery"
              examples:
                scheduled:
                  $ref: "#/components/examples/delivery_pending"
        "400":
          description: |-
            Bad request. One of:
            - `validation_error`: Validation failed.
            - `invalid_idempotency_key`: Invalid Idempotency-Key.
          x-error-codes:
            - validation_error
            - invalid_idempotency_key
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                validation_error:
                  $ref: "#/components/examples/error_validation_error"
                invalid_idempotency_key:
                  $ref: "#/components/examples/error_invalid_idempotency_key"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "401":
          description: |-
            Unauthorized. One of:
            - `authentication_required`: Authentication required.
            - `invalid_api_key`: Invalid API key.
            - `api_key_expired`: API key expired.
            - `api_key_revoked`: API key revoked.
            - `legacy_api_key_not_supported`: Legacy API key not supported.
          x-error-codes:
            - authentication_required
            - invalid_api_key
            - api_key_expired
            - api_key_revoked
            - legacy_api_key_not_supported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                authentication_required:
                  $ref: "#/components/examples/error_authentication_required"
                invalid_api_key:
                  $ref: "#/components/examples/error_invalid_api_key"
                api_key_expired:
                  $ref: "#/components/examples/error_api_key_expired"
                api_key_revoked:
                  $ref: "#/components/examples/error_api_key_revoked"
                legacy_api_key_not_supported:
                  $ref: "#/components/examples/error_legacy_api_key_not_supported"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "403":
          description: |-
            Forbidden. One of:
            - `insufficient_scope`: Insufficient scope.
            - `insufficient_permissions`: Key creator lacks permission.
            - `api_access_not_enabled`: API access not enabled.
            - `ip_not_allowed`: IP address not allowed.
            - `live_key_not_allowed_in_browser`: Live key used from a browser.
            - `webhooks_not_enabled`: Webhooks not enabled.
          x-error-codes:
            - insufficient_scope
            - insufficient_permissions
            - api_access_not_enabled
            - ip_not_allowed
            - live_key_not_allowed_in_browser
            - webhooks_not_enabled
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                insufficient_scope:
                  $ref: "#/components/examples/error_insufficient_scope"
                insufficient_permissions:
                  $ref: "#/components/examples/error_insufficient_permissions"
                api_access_not_enabled:
                  $ref: "#/components/examples/error_api_access_not_enabled"
                ip_not_allowed:
                  $ref: "#/components/examples/error_ip_not_allowed"
                live_key_not_allowed_in_browser:
                  $ref: "#/components/examples/error_live_key_not_allowed_in_browser"
                webhooks_not_enabled:
                  $ref: "#/components/examples/error_webhooks_not_enabled"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "404":
          description: |-
            Not found. One of:
            - `resource_not_found`: Resource not found.
          x-error-codes:
            - resource_not_found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                resource_not_found:
                  $ref: "#/components/examples/error_resource_not_found"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "409":
          description: |-
            Conflict. One of:
            - `idempotency_key_reused`: Idempotency-Key reused.
            - `idempotency_key_in_progress`: Request with this Idempotency-Key in progress.
            - `idempotency_outcome_unknown`: Outcome of the earlier request unknown.
            - `webhook_endpoint_disabled`: Webhook endpoint disabled.
            - `webhook_delivery_not_retryable`: Delivery cannot be retried.
          x-error-codes:
            - idempotency_key_reused
            - idempotency_key_in_progress
            - idempotency_outcome_unknown
            - webhook_endpoint_disabled
            - webhook_delivery_not_retryable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                idempotency_key_reused:
                  $ref: "#/components/examples/error_idempotency_key_reused"
                idempotency_key_in_progress:
                  $ref: "#/components/examples/error_idempotency_key_in_progress"
                idempotency_outcome_unknown:
                  $ref: "#/components/examples/error_idempotency_outcome_unknown"
                webhook_endpoint_disabled:
                  $ref: "#/components/examples/error_webhook_endpoint_disabled"
                webhook_delivery_not_retryable:
                  $ref: "#/components/examples/error_webhook_delivery_not_retryable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "429":
          description: |-
            Too many requests. One of:
            - `rate_limited`: Rate limit exceeded.
          x-error-codes:
            - rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                rate_limited:
                  $ref: "#/components/examples/error_rate_limited"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
        "500":
          description: |-
            Internal error. One of:
            - `internal_error`: Internal error.
          x-error-codes:
            - internal_error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                internal_error:
                  $ref: "#/components/examples/error_internal_error"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
        "503":
          description: |-
            Service unavailable. One of:
            - `service_unavailable`: Service temporarily unavailable.
          x-error-codes:
            - service_unavailable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                service_unavailable:
                  $ref: "#/components/examples/error_service_unavailable"
          headers:
            X-Request-Id:
              $ref: "#/components/headers/X-Request-Id"
            RateLimit-Limit:
              $ref: "#/components/headers/RateLimit-Limit"
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimit-Remaining"
            RateLimit-Reset:
              $ref: "#/components/headers/RateLimit-Reset"
            Retry-After:
              $ref: "#/components/headers/Retry-After"
webhooks:
  call.ended:
    post:
      operationId: onCallEnded
      summary: Call ended
      description: Sent when a call ends, whatever the outcome. `outcome`, `end_reason` and `duration_seconds` are known; the transcript, recording, analysis and charge may still be pending (see `call.settled`). In live mode it is sent once the end is observed, usually within seconds and at most a few minutes after the call ends. Delivered only to enabled endpoints subscribed to `call.ended`, in the event's mode, while webhooks are enabled for the workspace.
      tags:
        - Webhook endpoints
      parameters:
        - name: RelationsAI-Signature
          in: header
          required: true
          description: "`t=<unix seconds>,v1=<hex HMAC-SHA256>`. The HMAC is of `<t>.<raw body>` keyed with the endpoint secret. During a secret rotation a second `v1=` is present; accept the event if any matches. Reject `t` older than 5 minutes."
          schema:
            type: string
            pattern: ^t=[0-9]+(,v1=[0-9a-f]{64})+$
        - name: RelationsAI-Event-Id
          in: header
          required: true
          description: The event id; the same as `id` in the body. Use it to discard duplicates.
          schema:
            type: string
        - name: RelationsAI-Event-Type
          in: header
          required: true
          description: The event type; the same as `type` in the body.
          schema:
            type: string
        - name: RelationsAI-Delivery-Id
          in: header
          required: true
          description: The delivery id (`wd_...`), different for each endpoint and unchanged across retries.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CallEvent"
            examples:
              event:
                summary: Call ended
                value:
                  id: evt_5Zx9Cv3Bn7Mq2Wl8Ek4Rt6
                  object: event
                  type: call.ended
                  created_at: 2026-10-21T09:32:15.000Z
                  livemode: true
                  api_version: 2026-10-21
                  data:
                    object:
                      id: call_2Hd8Ks4Lq7Mw3Nx9Pz5Rc1
                      object: call
                      livemode: true
                      status: ended
                      outcome: completed
                      end_reason: hangup
                      direction: outbound
                      source: api
                      agent_id: agent_3hT9kQ2mVx7RbN4pLc8Wz1
                      campaign_id: null
                      phone_number_id: pn_5Lq8Xc2Rk9TzW3mBv7Np4d
                      from: "+918000000001"
                      to: "+919000000001"
                      metadata:
                        crm_lead_id: L-20931
                      created_at: 2026-10-21T09:30:00.000Z
                      ended_at: 2026-10-21T09:32:14.000Z
                      duration_seconds: 118
                      billable_minutes: null
                      cost: null
                      artifacts:
                        transcript:
                          state: pending
                        recording:
                          state: pending
                        analysis:
                          state: pending
                      settled: false
                      settled_at: null
      responses:
        "200":
          description: Any 2xx answer within 10 seconds acknowledges the event. The body is ignored. Any other answer, a timeout or a redirect is retried.
  call.settled:
    post:
      operationId: onCallSettled
      summary: Call settled
      description: "Sent once everything about a call is final: outcome, duration, transcript, recording, analysis and the charge. This can be several minutes after `call.ended`. Use it to sync final results to your systems. Delivered only to enabled endpoints subscribed to `call.settled`, in the event's mode, while webhooks are enabled for the workspace."
      tags:
        - Webhook endpoints
      parameters:
        - name: RelationsAI-Signature
          in: header
          required: true
          description: "`t=<unix seconds>,v1=<hex HMAC-SHA256>`. The HMAC is of `<t>.<raw body>` keyed with the endpoint secret. During a secret rotation a second `v1=` is present; accept the event if any matches. Reject `t` older than 5 minutes."
          schema:
            type: string
            pattern: ^t=[0-9]+(,v1=[0-9a-f]{64})+$
        - name: RelationsAI-Event-Id
          in: header
          required: true
          description: The event id; the same as `id` in the body. Use it to discard duplicates.
          schema:
            type: string
        - name: RelationsAI-Event-Type
          in: header
          required: true
          description: The event type; the same as `type` in the body.
          schema:
            type: string
        - name: RelationsAI-Delivery-Id
          in: header
          required: true
          description: The delivery id (`wd_...`), different for each endpoint and unchanged across retries.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CallEvent"
            examples:
              event:
                summary: Call settled
                value:
                  id: evt_8Nm4Bv1Cx6Zl3Kj9Hg2Fd5
                  object: event
                  type: call.settled
                  created_at: 2026-10-21T09:41:02.000Z
                  livemode: true
                  api_version: 2026-10-21
                  data:
                    object:
                      id: call_2Hd8Ks4Lq7Mw3Nx9Pz5Rc1
                      object: call
                      livemode: true
                      status: ended
                      outcome: completed
                      end_reason: hangup
                      direction: outbound
                      source: api
                      agent_id: agent_3hT9kQ2mVx7RbN4pLc8Wz1
                      campaign_id: null
                      phone_number_id: pn_5Lq8Xc2Rk9TzW3mBv7Np4d
                      from: "+918000000001"
                      to: "+919000000001"
                      metadata:
                        crm_lead_id: L-20931
                      created_at: 2026-10-21T09:30:00.000Z
                      ended_at: 2026-10-21T09:32:14.000Z
                      duration_seconds: 118
                      billable_minutes: 2
                      cost:
                        amount: 600
                        currency: INR
                      artifacts:
                        transcript:
                          state: ready
                        recording:
                          state: ready
                        analysis:
                          state: ready
                      settled: true
                      settled_at: 2026-10-21T09:41:02.000Z
      responses:
        "200":
          description: Any 2xx answer within 10 seconds acknowledges the event. The body is ignored. Any other answer, a timeout or a redirect is retried.
  campaign.started:
    post:
      operationId: onCampaignStarted
      summary: Campaign started
      description: Sent when a campaign run starts dialling, after a start request or when a start that was being confirmed is confirmed. Delivered only to enabled endpoints subscribed to `campaign.started`, in the event's mode, while webhooks are enabled for the workspace.
      tags:
        - Webhook endpoints
      parameters:
        - name: RelationsAI-Signature
          in: header
          required: true
          description: "`t=<unix seconds>,v1=<hex HMAC-SHA256>`. The HMAC is of `<t>.<raw body>` keyed with the endpoint secret. During a secret rotation a second `v1=` is present; accept the event if any matches. Reject `t` older than 5 minutes."
          schema:
            type: string
            pattern: ^t=[0-9]+(,v1=[0-9a-f]{64})+$
        - name: RelationsAI-Event-Id
          in: header
          required: true
          description: The event id; the same as `id` in the body. Use it to discard duplicates.
          schema:
            type: string
        - name: RelationsAI-Event-Type
          in: header
          required: true
          description: The event type; the same as `type` in the body.
          schema:
            type: string
        - name: RelationsAI-Delivery-Id
          in: header
          required: true
          description: The delivery id (`wd_...`), different for each endpoint and unchanged across retries.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CampaignEvent"
            examples:
              event:
                summary: Campaign started
                value:
                  id: evt_1Aq2Sw3De4Fr5Gt6Hy7Ju8
                  object: event
                  type: campaign.started
                  created_at: 2026-10-20T08:05:00.000Z
                  livemode: true
                  api_version: 2026-10-21
                  data:
                    object:
                      id: cmp_7Wq3Er9Ty2Ui5Op8As4Df6
                      object: campaign
                      livemode: true
                      name: November renewals
                      agent_id: agent_3hT9kQ2mVx7RbN4pLc8Wz1
                      dnc_screening: enforced
                      status: running
                      capabilities:
                        start: false
                        pause: true
                        resume: false
                        stop: true
                        update: false
                        add_recipients: false
                      concurrency_limit: 5
                      budget_cap:
                        amount: 500000
                        currency: INR
                      recipient_count: 1200
                      progress:
                        calls: 702
                        connected: 451
                        no_answer: 210
                        failed: 41
                        in_progress: 0
                      spend:
                        amount: 270600
                        currency: INR
                      run_number: 1
                      created_at: 2026-10-20T08:00:00.000Z
                    reason: null
      responses:
        "200":
          description: Any 2xx answer within 10 seconds acknowledges the event. The body is ignored. Any other answer, a timeout or a redirect is retried.
  campaign.paused:
    post:
      operationId: onCampaignPaused
      summary: Campaign paused
      description: Sent when a campaign is paused, by a request or automatically. `data.reason` says why, for example `budget_cap_reached` or `insufficient_balance`. A campaign paused automatically can be resumed once the cause is fixed. Delivered only to enabled endpoints subscribed to `campaign.paused`, in the event's mode, while webhooks are enabled for the workspace.
      tags:
        - Webhook endpoints
      parameters:
        - name: RelationsAI-Signature
          in: header
          required: true
          description: "`t=<unix seconds>,v1=<hex HMAC-SHA256>`. The HMAC is of `<t>.<raw body>` keyed with the endpoint secret. During a secret rotation a second `v1=` is present; accept the event if any matches. Reject `t` older than 5 minutes."
          schema:
            type: string
            pattern: ^t=[0-9]+(,v1=[0-9a-f]{64})+$
        - name: RelationsAI-Event-Id
          in: header
          required: true
          description: The event id; the same as `id` in the body. Use it to discard duplicates.
          schema:
            type: string
        - name: RelationsAI-Event-Type
          in: header
          required: true
          description: The event type; the same as `type` in the body.
          schema:
            type: string
        - name: RelationsAI-Delivery-Id
          in: header
          required: true
          description: The delivery id (`wd_...`), different for each endpoint and unchanged across retries.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CampaignEvent"
            examples:
              event:
                summary: Campaign paused
                value:
                  id: evt_2Ws3Ed4Rf5Tg6Yh7Uj8Ik9
                  object: event
                  type: campaign.paused
                  created_at: 2026-10-20T11:42:00.000Z
                  livemode: true
                  api_version: 2026-10-21
                  data:
                    object:
                      id: cmp_7Wq3Er9Ty2Ui5Op8As4Df6
                      object: campaign
                      livemode: true
                      name: November renewals
                      agent_id: agent_3hT9kQ2mVx7RbN4pLc8Wz1
                      dnc_screening: enforced
                      status: paused
                      capabilities:
                        start: true
                        pause: false
                        resume: true
                        stop: true
                        update: true
                        add_recipients: false
                      concurrency_limit: 5
                      budget_cap:
                        amount: 500000
                        currency: INR
                      recipient_count: 1200
                      progress:
                        calls: 702
                        connected: 451
                        no_answer: 210
                        failed: 41
                        in_progress: 0
                      spend:
                        amount: 270600
                        currency: INR
                      run_number: 1
                      created_at: 2026-10-20T08:00:00.000Z
                    reason: budget_cap_reached
      responses:
        "200":
          description: Any 2xx answer within 10 seconds acknowledges the event. The body is ignored. Any other answer, a timeout or a redirect is retried.
  campaign.resumed:
    post:
      operationId: onCampaignResumed
      summary: Campaign resumed
      description: Sent when a paused campaign resumes its run. Delivered only to enabled endpoints subscribed to `campaign.resumed`, in the event's mode, while webhooks are enabled for the workspace.
      tags:
        - Webhook endpoints
      parameters:
        - name: RelationsAI-Signature
          in: header
          required: true
          description: "`t=<unix seconds>,v1=<hex HMAC-SHA256>`. The HMAC is of `<t>.<raw body>` keyed with the endpoint secret. During a secret rotation a second `v1=` is present; accept the event if any matches. Reject `t` older than 5 minutes."
          schema:
            type: string
            pattern: ^t=[0-9]+(,v1=[0-9a-f]{64})+$
        - name: RelationsAI-Event-Id
          in: header
          required: true
          description: The event id; the same as `id` in the body. Use it to discard duplicates.
          schema:
            type: string
        - name: RelationsAI-Event-Type
          in: header
          required: true
          description: The event type; the same as `type` in the body.
          schema:
            type: string
        - name: RelationsAI-Delivery-Id
          in: header
          required: true
          description: The delivery id (`wd_...`), different for each endpoint and unchanged across retries.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CampaignEvent"
            examples:
              event:
                summary: Campaign resumed
                value:
                  id: evt_3Ed4Rf5Tg6Yh7Uj8Ik9Ol1
                  object: event
                  type: campaign.resumed
                  created_at: 2026-10-20T12:10:00.000Z
                  livemode: true
                  api_version: 2026-10-21
                  data:
                    object:
                      id: cmp_7Wq3Er9Ty2Ui5Op8As4Df6
                      object: campaign
                      livemode: true
                      name: November renewals
                      agent_id: agent_3hT9kQ2mVx7RbN4pLc8Wz1
                      dnc_screening: enforced
                      status: running
                      capabilities:
                        start: false
                        pause: true
                        resume: false
                        stop: true
                        update: false
                        add_recipients: false
                      concurrency_limit: 5
                      budget_cap:
                        amount: 500000
                        currency: INR
                      recipient_count: 1200
                      progress:
                        calls: 702
                        connected: 451
                        no_answer: 210
                        failed: 41
                        in_progress: 0
                      spend:
                        amount: 270600
                        currency: INR
                      run_number: 1
                      created_at: 2026-10-20T08:00:00.000Z
                    reason: null
      responses:
        "200":
          description: Any 2xx answer within 10 seconds acknowledges the event. The body is ignored. Any other answer, a timeout or a redirect is retried.
  campaign.stopped:
    post:
      operationId: onCampaignStopped
      summary: Campaign stopped
      description: Sent when a campaign is stopped. `data.reason` is `requested` for a stop request. Delivered only to enabled endpoints subscribed to `campaign.stopped`, in the event's mode, while webhooks are enabled for the workspace.
      tags:
        - Webhook endpoints
      parameters:
        - name: RelationsAI-Signature
          in: header
          required: true
          description: "`t=<unix seconds>,v1=<hex HMAC-SHA256>`. The HMAC is of `<t>.<raw body>` keyed with the endpoint secret. During a secret rotation a second `v1=` is present; accept the event if any matches. Reject `t` older than 5 minutes."
          schema:
            type: string
            pattern: ^t=[0-9]+(,v1=[0-9a-f]{64})+$
        - name: RelationsAI-Event-Id
          in: header
          required: true
          description: The event id; the same as `id` in the body. Use it to discard duplicates.
          schema:
            type: string
        - name: RelationsAI-Event-Type
          in: header
          required: true
          description: The event type; the same as `type` in the body.
          schema:
            type: string
        - name: RelationsAI-Delivery-Id
          in: header
          required: true
          description: The delivery id (`wd_...`), different for each endpoint and unchanged across retries.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CampaignEvent"
            examples:
              event:
                summary: Campaign stopped
                value:
                  id: evt_4Rf5Tg6Yh7Uj8Ik9Ol1Pm2
                  object: event
                  type: campaign.stopped
                  created_at: 2026-10-20T15:00:00.000Z
                  livemode: true
                  api_version: 2026-10-21
                  data:
                    object:
                      id: cmp_7Wq3Er9Ty2Ui5Op8As4Df6
                      object: campaign
                      livemode: true
                      name: November renewals
                      agent_id: agent_3hT9kQ2mVx7RbN4pLc8Wz1
                      dnc_screening: enforced
                      status: stopped
                      capabilities:
                        start: true
                        pause: false
                        resume: false
                        stop: false
                        update: true
                        add_recipients: false
                      concurrency_limit: 5
                      budget_cap:
                        amount: 500000
                        currency: INR
                      recipient_count: 1200
                      progress:
                        calls: 702
                        connected: 451
                        no_answer: 210
                        failed: 41
                        in_progress: 0
                      spend:
                        amount: 270600
                        currency: INR
                      run_number: 1
                      created_at: 2026-10-20T08:00:00.000Z
                    reason: requested
      responses:
        "200":
          description: Any 2xx answer within 10 seconds acknowledges the event. The body is ignored. Any other answer, a timeout or a redirect is retried.
  campaign.completed:
    post:
      operationId: onCampaignCompleted
      summary: Campaign completed
      description: Sent when a campaign run has worked through every recipient. In live mode it can arrive up to about 15 minutes after the last call ends. Delivered only to enabled endpoints subscribed to `campaign.completed`, in the event's mode, while webhooks are enabled for the workspace.
      tags:
        - Webhook endpoints
      parameters:
        - name: RelationsAI-Signature
          in: header
          required: true
          description: "`t=<unix seconds>,v1=<hex HMAC-SHA256>`. The HMAC is of `<t>.<raw body>` keyed with the endpoint secret. During a secret rotation a second `v1=` is present; accept the event if any matches. Reject `t` older than 5 minutes."
          schema:
            type: string
            pattern: ^t=[0-9]+(,v1=[0-9a-f]{64})+$
        - name: RelationsAI-Event-Id
          in: header
          required: true
          description: The event id; the same as `id` in the body. Use it to discard duplicates.
          schema:
            type: string
        - name: RelationsAI-Event-Type
          in: header
          required: true
          description: The event type; the same as `type` in the body.
          schema:
            type: string
        - name: RelationsAI-Delivery-Id
          in: header
          required: true
          description: The delivery id (`wd_...`), different for each endpoint and unchanged across retries.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CampaignEvent"
            examples:
              event:
                summary: Campaign completed
                value:
                  id: evt_5Tg6Yh7Uj8Ik9Ol1Pm2Nb3
                  object: event
                  type: campaign.completed
                  created_at: 2026-10-20T16:20:00.000Z
                  livemode: true
                  api_version: 2026-10-21
                  data:
                    object:
                      id: cmp_7Wq3Er9Ty2Ui5Op8As4Df6
                      object: campaign
                      livemode: true
                      name: November renewals
                      agent_id: agent_3hT9kQ2mVx7RbN4pLc8Wz1
                      dnc_screening: enforced
                      status: completed
                      capabilities:
                        start: true
                        pause: false
                        resume: false
                        stop: false
                        update: true
                        add_recipients: false
                      concurrency_limit: 5
                      budget_cap:
                        amount: 500000
                        currency: INR
                      recipient_count: 1200
                      progress:
                        calls: 702
                        connected: 451
                        no_answer: 210
                        failed: 41
                        in_progress: 0
                      spend:
                        amount: 270600
                        currency: INR
                      run_number: 1
                      created_at: 2026-10-20T08:00:00.000Z
                    reason: null
      responses:
        "200":
          description: Any 2xx answer within 10 seconds acknowledges the event. The body is ignored. Any other answer, a timeout or a redirect is retried.
  campaign.failed:
    post:
      operationId: onCampaignFailed
      summary: Campaign failed
      description: Sent when a campaign run ends in failure before working through its recipients. In live mode it can arrive up to about 15 minutes after the run ends. Retrieve the recipients list to see who was reached. Delivered only to enabled endpoints subscribed to `campaign.failed`, in the event's mode, while webhooks are enabled for the workspace.
      tags:
        - Webhook endpoints
      parameters:
        - name: RelationsAI-Signature
          in: header
          required: true
          description: "`t=<unix seconds>,v1=<hex HMAC-SHA256>`. The HMAC is of `<t>.<raw body>` keyed with the endpoint secret. During a secret rotation a second `v1=` is present; accept the event if any matches. Reject `t` older than 5 minutes."
          schema:
            type: string
            pattern: ^t=[0-9]+(,v1=[0-9a-f]{64})+$
        - name: RelationsAI-Event-Id
          in: header
          required: true
          description: The event id; the same as `id` in the body. Use it to discard duplicates.
          schema:
            type: string
        - name: RelationsAI-Event-Type
          in: header
          required: true
          description: The event type; the same as `type` in the body.
          schema:
            type: string
        - name: RelationsAI-Delivery-Id
          in: header
          required: true
          description: The delivery id (`wd_...`), different for each endpoint and unchanged across retries.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CampaignEvent"
            examples:
              event:
                summary: Campaign failed
                value:
                  id: evt_6Yh7Uj8Ik9Ol1Pm2Nb3Vc4
                  object: event
                  type: campaign.failed
                  created_at: 2026-10-20T16:20:00.000Z
                  livemode: true
                  api_version: 2026-10-21
                  data:
                    object:
                      id: cmp_7Wq3Er9Ty2Ui5Op8As4Df6
                      object: campaign
                      livemode: true
                      name: November renewals
                      agent_id: agent_3hT9kQ2mVx7RbN4pLc8Wz1
                      dnc_screening: enforced
                      status: failed
                      capabilities:
                        start: true
                        pause: false
                        resume: false
                        stop: false
                        update: true
                        add_recipients: false
                      concurrency_limit: 5
                      budget_cap:
                        amount: 500000
                        currency: INR
                      recipient_count: 1200
                      progress:
                        calls: 702
                        connected: 451
                        no_answer: 210
                        failed: 41
                        in_progress: 0
                      spend:
                        amount: 270600
                        currency: INR
                      run_number: 1
                      created_at: 2026-10-20T08:00:00.000Z
                    reason: null
      responses:
        "200":
          description: Any 2xx answer within 10 seconds acknowledges the event. The body is ignored. Any other answer, a timeout or a redirect is retried.
  webhook_endpoint.test:
    post:
      operationId: onWebhookEndpointTest
      summary: Test event
      description: Sent only when you call POST /v1/webhook-endpoints/{webhook_endpoint_id}/test, and only to that endpoint (which must be enabled). It cannot be subscribed to. `data.object` is the endpoint, never its secret. Use it to check your signature verification.
      tags:
        - Webhook endpoints
      parameters:
        - name: RelationsAI-Signature
          in: header
          required: true
          description: "`t=<unix seconds>,v1=<hex HMAC-SHA256>`. The HMAC is of `<t>.<raw body>` keyed with the endpoint secret. During a secret rotation a second `v1=` is present; accept the event if any matches. Reject `t` older than 5 minutes."
          schema:
            type: string
            pattern: ^t=[0-9]+(,v1=[0-9a-f]{64})+$
        - name: RelationsAI-Event-Id
          in: header
          required: true
          description: The event id; the same as `id` in the body. Use it to discard duplicates.
          schema:
            type: string
        - name: RelationsAI-Event-Type
          in: header
          required: true
          description: The event type; the same as `type` in the body.
          schema:
            type: string
        - name: RelationsAI-Delivery-Id
          in: header
          required: true
          description: The delivery id (`wd_...`), different for each endpoint and unchanged across retries.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WebhookTestEvent"
            examples:
              event:
                summary: Test event
                value:
                  id: evt_3Df7Gh1Jk5Lz9Xc2Vb6Nm8
                  object: event
                  type: webhook_endpoint.test
                  created_at: 2026-10-21T09:45:00.000Z
                  livemode: false
                  api_version: 2026-10-21
                  data:
                    object:
                      id: we_9Pl3Ok7Ij2Uh6Yg4Tf8Rd1
                      object: webhook_endpoint
                      livemode: false
                      url: https://example.com/webhooks/relationsai
                      description: CRM sync (test)
                      events:
                        - call.ended
                        - call.settled
                        - campaign.completed
                      status: enabled
                      secret_last4: x9Qa
                      created_at: 2026-10-21T08:00:00.000Z
                      updated_at: 2026-10-21T08:00:00.000Z
                      last_delivery: null
      responses:
        "200":
          description: Any 2xx answer within 10 seconds acknowledges the event. The body is ignored. Any other answer, a timeout or a redirect is retried.
