{
  "openapi": "3.1.0",
  "info": {
    "title": "CallPlatform API",
    "version": "1.0.0",
    "description": "Estate-scoped API for partner integrations and CallPlatform applications (v1).\n\nEnables an external system to:\n- List, create and edit the partner's accounts (sub-accounts)\n- Search available phone number inventory\n- Quote and order stock or supported supplier numbers when partner provisioning is enabled\n- Create inbound services routed to a SIP destination, with a number attached\n- Manage portal users and routing resources\n- Read call reports and retrieve authorised media\n- Discover the current estate's enabled capabilities\n\nInbound services support rich call routing — multi-target routes,\ntime-of-day gating, failover, voicemail, recording and more. The full\nconfiguration is documented in this single reference under the **Services**\nsection (`POST /services`, `GET /services/capabilities`).\n\n## Authentication\nAll requests require a Bearer token: `Authorization: Bearer vvp_xxxxxxxx`.\nAn account may hold multiple tokens, each with its own label, scopes\n(`accounts:read`, `accounts:write`, `users:read`, `users:write`,\n`numbers:read`, `numbers:write`, `services:read`, `services:write`,\n`reports:read`, `media:read`, `media:write`, `agents:read`, `agents:write`, `conferences:write`), IP allowlist and expiry — e.g. a read-only token for\nreporting alongside a full provisioning token. Tokens are individually\nrevocable and all activity is audit-logged per token. Sandbox and\nproduction use different tokens and base URLs; the contract is identical.\n\nCallPlatform applications sign in through the portal. Partner integrations use a\nseparate administrator-owned API token. Keep that token on your server, never in\nbrowser code. Its scopes, owner permissions and account hierarchy limit access.\n\n## Availability\nRead access and provisioning access are separate. Provisioning must be enabled\nfor the account that owns your token; enabling a parent does not enable tokens\nowned by its child accounts. Check `GET /capabilities` before showing write actions.\n`data.read_only` describes the caller's effective release access. Individual\ncapabilities and token scopes still apply. A write scope alone does not enable writes.\n\nApproved partners can create child accounts with rate plans, create users,\nconfigure services, search stock and supported supplier inventory, quote/order\nnumbers and read reports. Number ordering is a separate quote-and-order flow;\nthe legacy `/numbers/{number_id}/allocate` endpoint remains unavailable.\nMedia and other optional capabilities depend on your account and deployment.\n\n## Tenancy\nEvery resource belongs to an account in the partner's hierarchy.\n`account_id` is validated against the authenticated partner's account\ntree on every request; requests for accounts outside the tree return 404.\n\n## Idempotency\nPartner provisioning requests require an `Idempotency-Key` header (UUID). Retrying a\nrequest with the same key replays its result or reconciles the same pending order.\nKeep both the key and payload unchanged until the result is confirmed.\nUse a new key for a changed request, including one rebased on a newer revision:\nreusing a key with a different method, path, body or `If-Match` returns\n`422 idempotency_key_conflict`. Results below 500, including errors, are replayed.\nA claim still pending after ten minutes is treated as abandoned and the next\nidentical retry executes it. Keys are retained for at least seven days. Keys are\nscoped to the token; CallPlatform app sessions, which always send a key, are\nscoped to the signed-in portal session so retries survive token renewal.\n\n## Rate limiting\nResponses include `X-RateLimit-Limit`, `X-RateLimit-Remaining` and\n`X-RateLimit-Reset`. Exceeding the limit returns 429 with `Retry-After`.\n\n## Pagination\nMost list endpoints accept `page` (default 1) and `per_page` (default 25,\nmax 100), and return `meta.page`, `meta.per_page` and `meta.total`.\nCall reports instead return `meta.has_more`; they use live offset paging,\nso pages are not a consistent export snapshot. List-entry endpoints return\ntheir active entries without pagination.\n\n## Applications\nStart with `GET /me` and `GET /capabilities` to discover identity and enabled\nestate features. Tokens represent an estate account hierarchy; never embed a\nlong-lived partner token in a publicly distributed mobile or browser app.\nUse your application's server to retain the secret and enforce its own user\nsession permissions. First-party companion sessions use the separate estate portal PKCE sign-in\nand automatically rotated API tokens; API access for partners is configured in the portal.\n\n## Model\nAn inbound service answers calls to one or more of your phone numbers and\ndecides what happens next: who it rings, in what order, and what to do when\nnobody answers or the office is closed. You describe the behaviour you want\nas a structured configuration — a **route** plus any optional **sections**\nyou switch on (open-hours gating, call recording, voicemail, and so on). The\nplatform assembles them into the correct running order for you; you never\nhave to wire steps together by hand.\n\n## Account scoping\nEvery account-scoped id you reference (address book, audio file, linked\nservice, AI agent, access/area/IP/date list, firewall profile) is checked\nagainst your account tree before anything is created. An id that does not\nbelong to your account or a sub-account fails the whole request — no partial\nservice is left behind. Phone numbers are attached to the service in a\nseparate step (`POST /v1/services/{id}/numbers`).\n\n## Phone number format\nEvery phone number you supply must be in **E.164** format — a leading `+`\nfollowed by country code and subscriber number, with no spaces or\npunctuation (for example `+441632960001`).\n\n## Secrets\nDelivery credentials (for example an SFTP password) are **write-only**: you\ncan set them, but the API never reads them back. Reading a service back\nomits stored secrets entirely.\n"
  },
  "servers": [
    {
      "url": "/v1",
      "description": "This deployment (the host you opened this reference from)"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Discovery"
    },
    {
      "name": "Users"
    },
    {
      "name": "Reports"
    },
    {
      "name": "Media"
    },
    {
      "name": "Conferences",
      "description": "**Requires estate enablement, runtime readiness and an explicitly scoped caller.**\nDrive an in-progress conference room in real time —\nlist who is on the call, **mute/unmute** (stop them speaking) or\n**deaf/undeaf** (stop them hearing) a participant, kick or hang up a leg,\nor **dial a new party straight into the room** (for example, escalate an AI\ncall to a human). Authenticated and ownership-checked; scope\n`conferences:write`.\n"
    },
    {
      "name": "Accounts"
    },
    {
      "name": "Numbers"
    },
    {
      "name": "Services"
    },
    {
      "name": "Audio"
    },
    {
      "name": "Resources"
    }
  ],
  "x-tagGroups": [
    {
      "name": "Getting started",
      "tags": [
        "Discovery"
      ]
    },
    {
      "name": "Provisioning",
      "tags": [
        "Accounts",
        "Users",
        "Numbers",
        "Services",
        "Audio",
        "Resources"
      ]
    },
    {
      "name": "Calls and media",
      "tags": [
        "Reports",
        "Media",
        "Conferences"
      ]
    }
  ],
  "paths": {
    "/number-orders/search": {
      "get": {
        "operationId": "searchNumberOrders",
        "tags": [
          "Numbers"
        ],
        "summary": "Search platform and supplier stock with account prices",
        "description": "Requires an approved partner account. Search UK geographic prefixes using source=all for platform and supported supplier stock. Supplier availability is deployment-specific. Prices use the target account currency and rates; integer amounts are in minor currency units. No number is reserved by a search.",
        "x-required-scopes": [
          "numbers:read"
        ],
        "parameters": [
          {
            "name": "account_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "prefix",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0191"
            }
          },
          {
            "name": "source",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "stock",
                "magrathea",
                "all"
              ],
              "default": "stock"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "numbers": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/NumberOrderCandidate"
                          }
                        },
                        "supplier_available": {
                          "type": "boolean"
                        },
                        "supplier_error": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/number-orders/quote": {
      "post": {
        "operationId": "quoteNumberOrder",
        "tags": [
          "Numbers"
        ],
        "summary": "Refresh a selected number quote",
        "description": "Recalculates the signed candidate using current account pricing and returns a new expiry. Review the refreshed price before ordering.",
        "x-required-scopes": [
          "numbers:read",
          "numbers:write"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "account_id",
                  "quote"
                ],
                "properties": {
                  "account_id": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "quote": {
                    "type": "string",
                    "description": "Opaque account-bound quote returned by search or quote. Send it unchanged."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/NumberOrderCandidate"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/number-orders": {
      "post": {
        "operationId": "createNumberOrder",
        "tags": [
          "Numbers"
        ],
        "summary": "Order the number in a reviewed quote",
        "description": "Use one UUID for the entire order, including retries after a timeout or token replacement. The durable order identity is scoped to your root and target account. Reusing it with a different quote fails. Completed orders return allocation and billing references. Pending or review means the result is not yet confirmed: read its status and retry only the original request with the same key. Never submit a second key to work around an uncertain purchase. A number is initially unassigned; attach it to a provisioned service after completion.",
        "x-required-scopes": [
          "numbers:write"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "account_id",
                  "quote"
                ],
                "properties": {
                  "account_id": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "quote": {
                    "type": "string",
                    "description": "Opaque account-bound quote returned by search or quote. Send it unchanged."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/NumberOrder"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "202": {
            "description": "Order pending or awaiting review; no duplicate purchase is submitted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/NumberOrder"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/number-orders/{order_id}": {
      "get": {
        "operationId": "getNumberOrder",
        "tags": [
          "Numbers"
        ],
        "summary": "Read an order result",
        "description": "Read-only status for this root and target account. This request does not buy, charge, or retry supplier actions.",
        "x-required-scopes": [
          "numbers:read"
        ],
        "parameters": [
          {
            "name": "account_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "order_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/NumberOrder"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/services/editor/catalog": {
      "get": {
        "operationId": "get_service_editor_catalog",
        "x-required-scopes": [
          "services:read"
        ],
        "tags": [
          "Services"
        ],
        "summary": "Discover available Simple, Flexible and IVR branch routing controls",
        "description": "Returns current account entitlements and enabled portal modules, with labelled typed fields. Required before creating a service.",
        "parameters": [
          {
            "name": "account_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ServiceEditorCatalog"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/services/editor/resources/{kind}": {
      "get": {
        "operationId": "get_service_editor_resources",
        "x-required-scopes": [
          "services:read"
        ],
        "tags": [
          "Services"
        ],
        "summary": "Find a destination or saved routing resource",
        "description": "Names and IDs only, scoped to the exact owning account. AI selections additionally require current agent permissions and package entitlement. Pages contain at most 50 records; meta.page and meta.has_more support pagination.",
        "parameters": [
          {
            "name": "account_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "kind",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "audio",
                "address_book",
                "service",
                "acl",
                "abr",
                "dex",
                "ip",
                "firewall",
                "device",
                "agent",
                "regex",
                "summary"
              ]
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "selected",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EditorResource"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "page": {
                          "type": "integer"
                        },
                        "has_more": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/services/editor": {
      "post": {
        "operationId": "create_service_editor",
        "x-required-scopes": [
          "services:write"
        ],
        "tags": [
          "Services"
        ],
        "summary": "Create a Simple or Flexible Routing service",
        "description": "Creates an unassigned service and its reviewed option batch atomically, including service history. Requires the estate service_writes gate. Does not move or allocate any number.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ServiceEditorDocument"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ServiceEditorCreate"
              }
            }
          }
        }
      }
    },
    "/services/{service_id}/editor": {
      "get": {
        "operationId": "get_service_editor",
        "x-required-scopes": [
          "services:read"
        ],
        "tags": [
          "Services"
        ],
        "summary": "Read labelled service settings for incremental editing",
        "description": "Passwords are never returned. Unknown, private or ambiguous legacy options are preserved and marked non-editable. Branching flows cannot use this editor.",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "account_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ServiceEditorDocument"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "operationId": "update_service_editor",
        "x-required-scopes": [
          "services:write"
        ],
        "tags": [
          "Services"
        ],
        "summary": "Add, amend, remove or reorder service settings atomically",
        "description": "Requires base_config_hash from the reviewed document (or If-Match), explicit account_id and estate service_writes. All changes roll back on stale revision (412), invalid reference or validation error. At least one main destination must remain. Unsubmitted fields, including saved passwords, are preserved. New destinations can use negative client_id values referenced by destination_order.",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ServiceEditorDocument"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ServiceEditorPatch"
              }
            }
          }
        }
      }
    },
    "/accounts/{account_id}/management": {
      "get": {
        "operationId": "get_account_management",
        "x-required-scopes": [
          "accounts:read"
        ],
        "tags": [
          "Accounts"
        ],
        "summary": "Read account details and removal eligibility",
        "description": "Returns contact details, remaining asset counts and a revision for review. Account 1 cannot be removed. Only an account-1 platform administrator can remove an empty child account.",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AccountManagement"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/accounts": {
      "get": {
        "operationId": "get_accounts",
        "x-required-scopes": [
          "accounts:read"
        ],
        "tags": [
          "Accounts"
        ],
        "summary": "List your accounts",
        "description": "Returns descendant accounts (not your own account). Use /me for your current account. Scope accounts:read.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "name": "search",
            "in": "query",
            "description": "Match company name or contact name. Pending verification accounts are included.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Account list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Account"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "post_accounts",
        "x-required-scopes": [
          "accounts:write"
        ],
        "tags": [
          "Accounts"
        ],
        "summary": "Create an account",
        "description": "Creates a child under an authorised reseller parent. Companion requests use the portal country/timezone/payment/retention/welcome controls and canonical published rate-plan or parent-rate-copy transaction. An account and its hierarchy, rates, plan provenance and prepay setup commit together; a failed plan leaves no partial account. Welcome emails use the current estate portal branding and 24-hour activation. Skipping the email explicitly verifies the account. Approved partner integrations use the same account setup and rate-plan contract.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompanionAccountCreate"
              }
            }
          }
        },
        "responses": {
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "201": {
            "description": "Account created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "anyOf": [
                        {
                          "$ref": "#/components/schemas/Account"
                        },
                        {
                          "$ref": "#/components/schemas/CompanionAccountCreated"
                        }
                      ]
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          }
        }
      }
    },
    "/accounts/{account_id}": {
      "delete": {
        "operationId": "delete_account",
        "x-required-scopes": [
          "accounts:write"
        ],
        "tags": [
          "Accounts"
        ],
        "summary": "Remove an empty child account",
        "description": "Soft-deletes only an empty child account, preserving financial history. Requires the account_writes gate, account-1 administrator and a fresh management revision. Active numbers, services, users, children, devices, packages or credit block removal. Does not send messages.",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "204": {
            "description": "Account removed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "409": {
            "description": "Account still owns live assets"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "revision"
                ],
                "properties": {
                  "revision": {
                    "$ref": "#/components/schemas/EditorRevision"
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "patch_accounts_account_id",
        "x-required-scopes": [
          "accounts:write"
        ],
        "tags": [
          "Accounts"
        ],
        "summary": "Edit an account",
        "description": "Default-on read-only release guard: when `GET /capabilities` reports\n`data.read_only=true`, this operation returns `403 api_read_only` even\nfor a write-scoped token. When false, token scopes and individual estate\nfeature gates still apply.\n\nUpdates an account's details. The target must be a sub-account (descendant)\nin your hierarchy; your own account cannot be edited here (404). Partial\nupdate — only supplied fields change. Scope `accounts:write`.\n",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AccountUpdate"
              }
            }
          }
        },
        "responses": {
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "200": {
            "description": "Account updated",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Account"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          }
        }
      }
    },
    "/numbers/available": {
      "get": {
        "operationId": "get_numbers_available",
        "x-required-scopes": [
          "numbers:read"
        ],
        "tags": [
          "Numbers"
        ],
        "summary": "Search available number inventory",
        "description": "Inventory discovery, not a binding quote or reservation. Supplier-less and\nWhatsApp-held numbers are excluded. Use the portal checkout for a current\naccount-specific setup/rental quote and purchase. API allocation is not\navailable in v1. Scope `numbers:read`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "name": "country",
            "in": "query",
            "description": "ISO 3166-1 alpha-2 country code (e.g. GB, AU)",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2
            }
          },
          {
            "name": "prefix",
            "in": "query",
            "description": "Match numbers starting with this prefix (digits, E.164 without +)",
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{1,15}$"
            }
          },
          {
            "name": "grade",
            "in": "query",
            "description": "Number grade filter",
            "schema": {
              "type": "string",
              "enum": [
                "platinum",
                "gold",
                "silver",
                "bronze"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Available numbers",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AvailableNumber"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/numbers": {
      "get": {
        "operationId": "get_numbers",
        "x-required-scopes": [
          "numbers:read"
        ],
        "tags": [
          "Numbers"
        ],
        "summary": "List allocated numbers",
        "description": "Numbers allocated to your accounts. Scope `numbers:read`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "name": "account_id",
            "in": "query",
            "description": "Filter to one account",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Literal substring of the allocated number or description; a leading + is accepted.",
            "schema": {
              "type": "string",
              "maxLength": 128
            }
          },
          {
            "name": "unassigned",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "When true, include only numbers already allocated to the selected account with no active service attachment. This is not purchasable stock."
          }
        ],
        "responses": {
          "200": {
            "description": "Allocated numbers",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Number"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/numbers/{number_id}": {
      "get": {
        "operationId": "get_numbers_number_id",
        "x-required-scopes": [
          "numbers:read"
        ],
        "tags": [
          "Numbers"
        ],
        "summary": "Get an allocated number",
        "description": "Reads the current in-tree allocation, service link, cancellation and\nactual rental snapshot. Missing or ambiguous rental data is not guessed.\nA number with multiple current allocations fails with 409\nnumber_allocation_conflict. Unallocated/out-of-tree numbers return 404.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/NumberId"
          }
        ],
        "responses": {
          "200": {
            "description": "Current allocated number",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Number"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/audio": {
      "get": {
        "operationId": "get_audio",
        "x-required-scopes": [
          "services:read"
        ],
        "tags": [
          "Audio"
        ],
        "summary": "List audio files",
        "description": "Lists the pre-recorded and text-to-speech audio files your account can\nreference by `audio_id` when building services (whisper, greetings,\nannouncements, voicemail greetings, queue music, and so on). Audio is\ncreated and managed in the portal; this endpoint lets an API client\ndiscover the ids it may use. Scope `services:read`.\nRequires `capabilities.features.media_reads=true`; otherwise authenticated\nrequests return `403 feature_unavailable`, including this legacy alias.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "name": "account_id",
            "in": "query",
            "description": "Filter to one account in your tree.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Audio files",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AudioFile"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/agents": {
      "get": {
        "operationId": "get_agents",
        "x-required-scopes": [
          "services:read"
        ],
        "tags": [
          "Resources"
        ],
        "summary": "List attachable AI agents",
        "description": "Lists the AI agents you can attach as a destination — those on the account\nthat ALSO have an active call package (the same condition required to\nattach one). Use an agent's `id` as `ai_agent_id` in a route/target.\nAgents are created/managed in the portal. Scope `services:read`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "name": "account_id",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Filter to one account in your tree."
          }
        ],
        "responses": {
          "200": {
            "description": "Attachable agents",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Agent"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/lists": {
      "get": {
        "operationId": "get_lists",
        "x-required-scopes": [
          "services:read"
        ],
        "tags": [
          "Resources"
        ],
        "summary": "List routing lists (ACL / ABR / DEX / IP)",
        "description": "Lists the routing lists you can reference by `list_id` when building\nservices: ACL (number allow/block), ABR (area/prefix), DEX (date) and IP\nlists. Lists are created/managed in the portal. Scope `services:read`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "name": "account_id",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Filter to one account in your tree."
          },
          {
            "name": "type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "acl",
                "abr",
                "dex",
                "ip"
              ]
            },
            "description": "Filter to one list type."
          }
        ],
        "responses": {
          "200": {
            "description": "Routing lists",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/RoutingList"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "post_lists",
        "x-required-scopes": [
          "services:write"
        ],
        "tags": [
          "Resources"
        ],
        "summary": "Create a routing list",
        "description": "Default-on read-only release guard: when `GET /capabilities` reports\n`data.read_only=true`, this operation returns `403 api_read_only` even\nfor a write-scoped token. When false, token scopes and individual estate\nfeature gates still apply.\n\nCreates an ACL/ABR/DEX/IP list for an account, optionally with entries.\n`mode` sets the acl list behaviour as CallPilot applies it (see ListCreate). Entry shape depends on\n`type`: acl `{number}`, abr `{area}`, ip `{ip}`,\ndex `{name,start_date,end_date}`. Scope `services:write`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListCreate"
              }
            }
          }
        },
        "responses": {
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "201": {
            "description": "List created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/RoutingList"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          }
        }
      }
    },
    "/address-book": {
      "get": {
        "operationId": "get_address_book",
        "x-required-scopes": [
          "services:read"
        ],
        "tags": [
          "Resources"
        ],
        "summary": "List address-book contacts",
        "description": "Lists the address-book contacts you can reference by `address_book_id` as\na routing destination. Contacts are created/managed in the portal.\nScope `services:read`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "name": "account_id",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Filter to one account in your tree."
          }
        ],
        "responses": {
          "200": {
            "description": "Address-book contacts",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AddressBookContact"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "post_address_book",
        "x-required-scopes": [
          "services:write"
        ],
        "tags": [
          "Resources"
        ],
        "summary": "Create an address-book contact",
        "description": "Default-on read-only release guard: when `GET /capabilities` reports\n`data.read_only=true`, this operation returns `403 api_read_only` even\nfor a write-scoped token. When false, token scopes and individual estate\nfeature gates still apply.\n\nCreates a contact for an account, optionally with destinations. Each\ndestination's type is derived from its `target` (a SIP URI containing `@`\nis treated as SIP, otherwise a phone number). Scope `services:write`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddressBookCreate"
              }
            }
          }
        },
        "responses": {
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "201": {
            "description": "Contact created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AddressBookContact"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          }
        }
      }
    },
    "/numbers/{number_id}/service": {
      "put": {
        "operationId": "put_number_service",
        "tags": [
          "Numbers"
        ],
        "summary": "Change an allocated number's service",
        "x-required-scopes": [
          "services:write",
          "numbers:read"
        ],
        "description": "Moves an allocated number between services in the same verified owning account.\nRequires the estate service_writes switch and read_only=false. No billing or allocation changes.\nRead both service config_hash values before reviewing this change. Both service revisions are\nchecked and written to the portal history in one transaction. Stale routing or revisions return\n412 with no partial change. Use expected_service_id=null for an unassigned number.\n",
        "parameters": [
          {
            "name": "number_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "account_id",
                  "service_id",
                  "expected_service_id",
                  "config_hash"
                ],
                "properties": {
                  "account_id": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "service_id": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "expected_service_id": {
                    "type": "integer",
                    "nullable": true,
                    "minimum": 1
                  },
                  "config_hash": {
                    "type": "string",
                    "pattern": "^[a-f0-9]{64}$",
                    "description": "Reviewed target service config_hash."
                  },
                  "previous_config_hash": {
                    "type": "string",
                    "nullable": true,
                    "pattern": "^[a-f0-9]{64}$",
                    "description": "Required when expected_service_id is non-null."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Routing saved (including an idempotent replay).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "required": [
                        "number_id",
                        "service_id",
                        "account_id"
                      ],
                      "properties": {
                        "number_id": {
                          "type": "integer"
                        },
                        "service_id": {
                          "type": "integer"
                        },
                        "account_id": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "412": {
            "description": "Routing or either service revision changed. Reload and review again. A stale service revision carries the ConflictError details for that service_id; a moved number carries none.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConflictError"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/numbers/{number_id}/allocate": {
      "post": {
        "operationId": "post_numbers_number_id_allocate",
        "x-required-scopes": [
          "numbers:write"
        ],
        "tags": [
          "Numbers"
        ],
        "summary": "Number allocation (unavailable in v1)",
        "description": "Default-on read-only release guard: when `GET /capabilities` reports\n`data.read_only=true`, this operation returns `403 api_read_only` even\nfor a write-scoped token. When false, token scopes and individual estate\nfeature gates still apply.\n\nCompatibility route only. A valid in-scope request returns 503\nnumber_allocation_unavailable; no allocation, rental or charge is written.\nUse the portal checkout, which owns setup prices, recurring quotes,\nbespoke rates and prepay receipts. Enabling number_writes does not enable\nthis operation. Scope `numbers:write`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/NumberId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "account_id"
                ],
                "properties": {
                  "account_id": {
                    "type": "integer",
                    "description": "The account receiving the number"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "503": {
            "description": "number_allocation_unavailable — use the portal checkout",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Idempotency key conflicts with an earlier request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          }
        }
      }
    },
    "/numbers/{number_id}/release": {
      "post": {
        "operationId": "post_numbers_number_id_release",
        "x-required-scopes": [
          "numbers:write"
        ],
        "tags": [
          "Numbers"
        ],
        "summary": "Immediate number release (unavailable in v1)",
        "description": "Default-on read-only release guard: when `GET /capabilities` reports\n`data.read_only=true`, this operation returns `403 api_read_only` even\nfor a write-scoped token. When false, token scopes and individual estate\nfeature gates still apply.\n\nCompatibility route only. A valid current in-scope allocation returns\n503 number_release_unavailable without changing routing, allocation or\nbilling. Use /numbers/{number_id}/cancel for scheduled cancellation,\nor the portal for immediate teardown. Enabling number_writes does not\nenable this operation. Scope `numbers:write`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/NumberId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "account_id"
                ],
                "properties": {
                  "account_id": {
                    "type": "integer",
                    "description": "The account the number is currently allocated to.\n"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "503": {
            "description": "number_release_unavailable — use scheduled cancellation or the portal",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/DestructiveRateLimited"
          }
        }
      }
    },
    "/services": {
      "get": {
        "operationId": "get_services",
        "x-required-scopes": [
          "services:read"
        ],
        "tags": [
          "Services"
        ],
        "summary": "List inbound services",
        "description": "Scope `services:read`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "name": "account_id",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 128
            },
            "description": "Service name or attached E.164 number substring."
          }
        ],
        "responses": {
          "200": {
            "description": "Service list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Service"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "operationId": "post_services",
        "x-required-scopes": [
          "services:write"
        ],
        "tags": [
          "Services"
        ],
        "summary": "Create an inbound service",
        "description": "Default-on read-only release guard: when `GET /capabilities` reports\n`data.read_only=true`, this operation returns `403 api_read_only` even\nfor a write-scoped token. When false, token scopes and individual estate\nfeature gates still apply.\n\nCreates an inbound service for an account, optionally attaching\nan allocated number and routing it in one call. The common flow\n\"this number should ring this SIP destination\" is a single request:\n\n```json\n{\n  \"account_id\": 123,\n  \"name\": \"Support line\",\n  \"number_id\": 456,\n  \"route\": { \"type\": \"sip\", \"sip_uri\": \"sip:agent42@sip.client-platform.com\" }\n}\n```\nScope `services:write`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/InboundServiceCreate"
                  },
                  {
                    "$ref": "#/components/schemas/ConferenceServiceCreate"
                  },
                  {
                    "$ref": "#/components/schemas/IvrServiceCreate"
                  },
                  {
                    "$ref": "#/components/schemas/FlowServiceCreate"
                  },
                  {
                    "$ref": "#/components/schemas/AbrServiceCreate"
                  }
                ]
              },
              "examples": {
                "simpleSip": {
                  "summary": "Route to one SIP destination",
                  "value": {
                    "account_id": 2,
                    "name": "Support Line",
                    "route": {
                      "type": "sip",
                      "sip_uri": "sip:reception@example.com"
                    }
                  }
                },
                "sipWithFailoverToVoicemail": {
                  "summary": "Ring an agent then a backup number, fall back to voicemail out of hours",
                  "value": {
                    "account_id": 2,
                    "name": "Support Line",
                    "route": {
                      "strategy": "sequential",
                      "targets": [
                        {
                          "type": "sip",
                          "sip_uri": "sip:agent@acme.com",
                          "ring_time": 30
                        },
                        {
                          "type": "number",
                          "number": "+441632960001",
                          "ring_time": 20
                        }
                      ]
                    },
                    "time_of_day": {
                      "timezone": "Europe/London",
                      "schedule": "1,09:00,17:00;2,09:00,17:00",
                      "closed_route": {
                        "type": "voicemail"
                      }
                    },
                    "failover": {
                      "type": "voicemail"
                    },
                    "voicemail": {
                      "greeting_audio_id": 8,
                      "delivery": {
                        "type": "email",
                        "to": "support@acme.com",
                        "from": "noreply@acme.com"
                      }
                    }
                  }
                },
                "ringGroupWithRecording": {
                  "summary": "Ring two contacts at once, record the call",
                  "value": {
                    "account_id": 2,
                    "name": "Sales Hunt Group",
                    "route": {
                      "strategy": "simultaneous",
                      "targets": [
                        {
                          "type": "address_book",
                          "address_book_id": 41,
                          "ring_time": 25
                        },
                        {
                          "type": "ai_agent",
                          "ai_agent_id": "agent_abc123",
                          "ring_time": 25
                        }
                      ]
                    },
                    "recording": {
                      "mode": "auto",
                      "delivery": {
                        "type": "email",
                        "to": "compliance@acme.com",
                        "from": "noreply@acme.com"
                      }
                    }
                  }
                },
                "ivrMenu": {
                  "summary": "IVR menu (service_type 11) — press 1 for a service, 2 for voicemail",
                  "value": {
                    "account_id": 2,
                    "name": "Main Menu",
                    "service_type": 11,
                    "ivr": {
                      "greeting_audio_id": "8",
                      "max_repeats": 3,
                      "menu": [
                        {
                          "digit": "1",
                          "name": "Sales",
                          "action": "linked_service",
                          "linked_service_id": 101
                        },
                        {
                          "digit": "2",
                          "name": "Leave a message",
                          "action": "flexible",
                          "actions": [
                            {
                              "type": "voicemail",
                              "params": {
                                "greeting_audio_id": "9",
                                "delivery": "email",
                                "email_to": "vm@acme.com",
                                "email_from": "noreply@acme.com"
                              }
                            }
                          ]
                        }
                      ]
                    }
                  }
                },
                "audioConference": {
                  "summary": "Audio Conference (service_type 2) — a PIN-protected conference room, recorded to email",
                  "value": {
                    "account_id": 2,
                    "name": "Team Bridge",
                    "service_type": 2,
                    "conference": {
                      "guest_pins": "246810",
                      "moderator_pin": "13579",
                      "max_participants": 20,
                      "audio_id": 8,
                      "record": {
                        "enabled": true,
                        "delivery": {
                          "type": "email",
                          "to": "minutes@acme.com",
                          "from": "noreply@acme.com"
                        }
                      },
                      "dial_out": {
                        "type": "sip",
                        "target": "sip:reception@pbx.acme.com",
                        "cli": "+441632960001"
                      },
                      "webhook_url": "https://hooks.acme.com/conference/joined"
                    }
                  }
                },
                "callerControllerConference": {
                  "summary": "Two-person caller-controller room (service_type 2) — 2-party lock, auto dial-out, join webhook + live caller controls",
                  "value": {
                    "account_id": 2,
                    "name": "Support bridge",
                    "service_type": 2,
                    "conference": {
                      "max_participants": 2,
                      "lock": true,
                      "direct_join": true,
                      "end_on_caller_exit": true,
                      "dial_out": {
                        "type": "sip",
                        "target": "sip:agent@pbx.acme.com",
                        "cli_type": "inbound"
                      },
                      "webhook_url": "https://hooks.acme.com/conference/joined",
                      "webhook_payload": {
                        "queue": "support"
                      }
                    }
                  }
                },
                "abrPrefixRouting": {
                  "summary": "Advanced ABR (service_type 14) — route by caller prefix to a linked service",
                  "value": {
                    "account_id": 2,
                    "name": "Geographic Routing",
                    "service_type": 14,
                    "abr": {
                      "rules": [
                        {
                          "rule_type": "list",
                          "area_list_id": 5,
                          "name": "London",
                          "linked_service_id": 101
                        },
                        {
                          "rule_type": "direct",
                          "match_value": "44161",
                          "match_descriptions": "Manchester",
                          "linked_service_id": 102
                        }
                      ],
                      "default": {
                        "linked_service_id": 103
                      }
                    }
                  }
                },
                "flowGraph": {
                  "summary": "Flow Builder (service_type 13) — a node graph",
                  "value": {
                    "account_id": 2,
                    "name": "Visual Flow",
                    "service_type": 13,
                    "flow": {
                      "entry": "n1",
                      "nodes": [
                        {
                          "id": "n1",
                          "type": "play_audio",
                          "params": {
                            "audio_id": "8"
                          },
                          "next": {
                            "out": "n2"
                          }
                        },
                        {
                          "id": "n2",
                          "type": "terminate",
                          "params": {
                            "strategy": "sequential",
                            "targets": [
                              {
                                "target_type": "sip",
                                "sip_uri": "sip:agent@acme.com",
                                "ring_time": 30
                              }
                            ]
                          }
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Service created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Service"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/services/{service_id}": {
      "get": {
        "operationId": "get_services_service_id",
        "x-required-scopes": [
          "services:read"
        ],
        "tags": [
          "Services"
        ],
        "summary": "Get a service",
        "parameters": [
          {
            "$ref": "#/components/parameters/ServiceId"
          }
        ],
        "responses": {
          "200": {
            "description": "Service detail",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ServiceWithConfiguration"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "operationId": "patch_services_service_id",
        "x-required-scopes": [
          "services:write"
        ],
        "tags": [
          "Services"
        ],
        "summary": "Update a service",
        "description": "Default-on read-only release guard: when `GET /capabilities` reports\n`data.read_only=true`, this operation returns `403 api_read_only` even\nfor a write-scoped token. When false, token scopes and individual estate\nfeature gates still apply.\n\nApply only fields in the service's supported_updates. Name is independently\neditable; simple route updates require an unambiguous linear SIP service.\nA complete flow graph may replace an existing API-shaped graph. Portal\nnode-list graphs and rich configuration sections remain read-only.\nSupply the reviewed config_hash via If-Match or base_config_hash.\nMissing precondition returns 428; stale configuration returns 412.\nUnsupported configuration replacement returns 422 configuration_update_unsupported.\nExisting flexible/linear controls returned in editable_options may be patched\nvia option_edits. IDs must belong to this service; type, order, branches,\nsecret parameters and omitted fields are preserved. Cannot be mixed with route/flow.\nRing strategy applies to every compatible main target. Hours use service timezone;\nuse non-overlapping same-day windows (empty means closed all week).\nScope services:write.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfMatch"
          },
          {
            "$ref": "#/components/parameters/ServiceId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "account_id"
                ],
                "additionalProperties": false,
                "example": {
                  "account_id": 2,
                  "name": "Support Line"
                },
                "properties": {
                  "base_config_hash": {
                    "$ref": "#/components/schemas/ConfigHash"
                  },
                  "account_id": {
                    "type": "integer",
                    "description": "The account that owns the service. The update only applies if\nthe service belongs to this account.\n"
                  },
                  "name": {
                    "type": "string",
                    "maxLength": 100
                  },
                  "service_type": {
                    "type": "integer",
                    "description": "Must match the existing service type when supplied."
                  },
                  "option_edits": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 100,
                    "items": {
                      "$ref": "#/components/schemas/ServiceOptionEdit"
                    }
                  },
                  "flow": {
                    "type": "object",
                    "required": [
                      "entry",
                      "nodes"
                    ],
                    "description": "Complete graph replacement only when supported_updates contains flow.\nThe complete graph must encode to at most 256 KiB (262144 bytes)\nin stored JSON, including JSON escaping.\n",
                    "properties": {
                      "entry": {
                        "type": "string"
                      },
                      "nodes": {
                        "type": "array",
                        "items": {
                          "$ref": "#/components/schemas/FlowNode"
                        }
                      }
                    }
                  },
                  "route": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "type",
                      "sip_uri"
                    ],
                    "properties": {
                      "type": {
                        "type": "string",
                        "enum": [
                          "sip"
                        ]
                      },
                      "sip_uri": {
                        "type": "string",
                        "maxLength": 255,
                        "description": "New SIP destination, e.g. sip:user@host."
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "503": {
            "$ref": "#/components/responses/ServiceHistoryUnavailable"
          },
          "200": {
            "description": "Service updated",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Service"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          }
        }
      },
      "delete": {
        "operationId": "delete_services_service_id",
        "x-required-scopes": [
          "services:write"
        ],
        "tags": [
          "Services"
        ],
        "summary": "Delete a service",
        "description": "Default-on read-only release guard: when `GET /capabilities` reports\n`data.read_only=true`, this operation returns `403 api_read_only` even\nfor a write-scoped token. When false, token scopes and individual estate\nfeature gates still apply.\n\nDetaches numbers and records a recoverable service version. Requires the reviewed config_hash through If-Match or base_config_hash. Scope services:write.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfMatch"
          },
          {
            "$ref": "#/components/parameters/ServiceId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "account_id"
                ],
                "properties": {
                  "base_config_hash": {
                    "$ref": "#/components/schemas/ConfigHash"
                  },
                  "account_id": {
                    "type": "integer",
                    "description": "The account that owns the service. The delete only applies if\nthe service belongs to this account.\n"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "503": {
            "$ref": "#/components/responses/ServiceHistoryUnavailable"
          },
          "204": {
            "description": "Service deleted"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/DestructiveRateLimited"
          }
        }
      }
    },
    "/services/{service_id}/numbers": {
      "post": {
        "operationId": "post_services_service_id_numbers",
        "x-required-scopes": [
          "services:write"
        ],
        "tags": [
          "Services"
        ],
        "summary": "Attach a number to a service",
        "description": "Attach an already allocated, currently unassigned number to an owned service using the reviewed If-Match/base_config_hash. Number and service must belong to the exact same account. Current companion scopes, role, editor permission and estate service-writes gate apply. Numbers already assigned elsewhere are refused; this does not purchase stock or move an assigned number between services.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfMatch"
          },
          {
            "$ref": "#/components/parameters/ServiceId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "account_id",
                  "number_id"
                ],
                "properties": {
                  "base_config_hash": {
                    "$ref": "#/components/schemas/ConfigHash"
                  },
                  "account_id": {
                    "type": "integer",
                    "description": "The account that owns both the service and the number. The\nattach only applies if the service belongs to this account.\n"
                  },
                  "number_id": {
                    "type": "integer"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "503": {
            "$ref": "#/components/responses/ServiceHistoryUnavailable"
          },
          "200": {
            "description": "Number attached",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Service"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Number is already attached to another service",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/services/capabilities": {
      "get": {
        "x-required-scopes": [
          "services:read"
        ],
        "tags": [
          "Services"
        ],
        "summary": "List what you can provision",
        "operationId": "getServiceCapabilities",
        "description": "Returns the service types your account is entitled to create (and\nwhether each can be built through this API), plus feature flags resolved\nfrom your account's permissions. Use this to decide which options to\noffer before calling `POST /v1/services`. Requires the `services:read`\nscope.\n",
        "responses": {
          "200": {
            "description": "Capabilities for the calling account",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Capabilities"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/conferences/{conference_id}/actions": {
      "post": {
        "x-required-scopes": [
          "conferences:write"
        ],
        "tags": [
          "Conferences"
        ],
        "summary": "Control a live conference — mute/deaf, kick, or dial a party in",
        "operationId": "conferenceAction",
        "description": "Control an existing live conference using `list`, `mute`, `unmute`, `deaf`,\n`undeaf`, `kick`, `hup`, `kill` or `dial`. No room move, transfer, call\ndiscovery or conference event subscription/delivery API is supported.\n\nRequires an explicit `conferences:write` token grant, the estate conference\nfeature and runtime readiness. This integration grant is independent of\npartner provisioning approval. Global API read-only mode, the current\ntoken owner's restrictions and account hierarchy still apply. All actions,\nincluding `list`, use POST and require a UUID `Idempotency-Key` header.\nCheck `GET /capabilities` for this estate and caller before offering actions.\n\nSupply a safe room token in `conference_id` and a full live channel UUID in\n`fs_uuid`, obtained from an independently verified estate integration.\nThe server resolves the anchor's owning account/node, checks the current\npermitted account hierarchy and reads the named room's members. It verifies\nthe owned anchor belongs to that room before returning room data or sending\nany mutating action, and preflights targeted membership before dispatch.\nKnowing a room name or an unrelated live leg does not authorise control.\nMissing or inaccessible anchors/rooms return a generic `404`.\n\nTo control a dialled SIP or AI leg, retain the original caller's owned live\nUUID in `fs_uuid` and put the target leg's UUID in `member`. A dialled leg\nwithout its own account-owned call-state record cannot serve as the anchor\nand returns `404`.\n\nTargeted actions require a positive member ID or member channel UUID;\n`kill` sends only the server-verified channel UUID to the executor. Dial targets accept conservative PSTN digits with\nan optional leading plus, or a safe SIP URI; command fragments, whitespace\nand URI parameters are rejected. Dial can originate a billable call.\nThe executor uses the verified anchor's billing/routing context. For `dial`,\nprovide `ddi` unless the room has a numeric DDI prefix; `cli` defaults to `ddi`.\n\nA successful `dial` returns `sip_leg_uuid`, the channel UUID the server\nassigns to the new leg before originating it, so you know the leg's ID\nstraight away. Pass it as `member` to mute, kick, hang up or kill that leg\nlater. The response is returned once the call is started, before it is\nanswered: until the leg joins the room, or if it is never answered,\nactions targeting it return `409 call_ended`.\n\nA disabled estate feature returns `403 feature_unavailable`; incomplete\ncall-state, executor credential, allowed hosts or required routing context returns\n`503 conference_unavailable`. Capability readiness is not a live health\nprobe or acceptance evidence. A sandbox needs isolated test call-state\nand an isolated executor; production call-state is not a sandbox fallback.\n\nReuse the same idempotency key for the identical request. Recorded results\ncan be replayed, but an external action can have executed before a timeout\nor lost response. Reconcile live call state before retrying a billable or\ndestructive action after an ambiguous timeout or 5xx.\n",
        "parameters": [
          {
            "name": "conference_id",
            "in": "path",
            "required": true,
            "description": "Safe conference room token; no whitespace or executor command syntax.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9][A-Za-z0-9_.+@-]{0,127}$",
              "example": "DDI-12345678-1234-4234-8234-123456789abc-support"
            }
          },
          {
            "$ref": "#/components/parameters/ConferenceIdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConferenceAction"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Action executed; the node's reply is echoed under `data`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "description": "Executor result; fields vary by action (e.g. esl_reply, members, member_id, sip_leg_uuid).",
                      "properties": {
                        "sip_leg_uuid": {
                          "type": "string",
                          "format": "uuid",
                          "description": "`dial` only. Channel UUID assigned to the new leg before it is originated. Use it as `member` in later actions on that leg.",
                          "example": "3f1c2b7a-9d4e-4c61-8a2f-5b6e7d8c9a01"
                        }
                      },
                      "additionalProperties": true
                    }
                  }
                },
                "example": {
                  "data": {
                    "conference_id": "DDI-12345678-1234-4234-8234-123456789abc-support",
                    "status": "ok",
                    "action": "dial",
                    "room": "DDI-12345678-1234-4234-8234-123456789abc-support",
                    "number": "+447700900123",
                    "sip_leg_uuid": "3f1c2b7a-9d4e-4c61-8a2f-5b6e7d8c9a01",
                    "esl_reply": "+OK Job-UUID: 9b8a7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/CallControlUnavailable"
          }
        }
      }
    },
    "/users": {
      "get": {
        "operationId": "get_users",
        "tags": [
          "Users"
        ],
        "summary": "List portal users",
        "x-required-scopes": [
          "users:read"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/User"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "$ref": "#/components/parameters/AccountFilter"
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 128
            },
            "description": "Literal substring of email, first name or last name."
          }
        ]
      },
      "post": {
        "operationId": "post_users",
        "tags": [
          "Users"
        ],
        "summary": "Create a portal user",
        "x-required-scopes": [
          "users:write"
        ],
        "responses": {
          "201": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/User"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "503": {
            "$ref": "#/components/responses/UserPermissionsUnavailable"
          }
        },
        "description": "Creates a portal identity within the current hierarchy. Manual password setup marks the email verified and sends no invitation. Companion administrators may instead request send_invite=true: the existing branded portal invitation is sent and the identity remains pending verification. Current role ordering and delegated permissions apply; a failed baseline trigger rolls the creation back. Email transport failure is reported explicitly without duplicating the created user.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserCreate"
              }
            }
          }
        }
      }
    },
    "/users/{user_id}": {
      "parameters": [
        {
          "name": "user_id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 1
          }
        }
      ],
      "get": {
        "operationId": "get_users_user_id",
        "tags": [
          "Users"
        ],
        "summary": "Get a portal user",
        "x-required-scopes": [
          "users:read"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/User"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "operationId": "patch_users_user_id",
        "tags": [
          "Users"
        ],
        "summary": "Update a portal user",
        "x-required-scopes": [
          "users:write"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/User"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          }
        },
        "description": "Reviewed partial identity update. Companion sessions require account_id plus the current revision and may edit lower-ranked users in their own account or equal/lower-ranked users in descendants. Self identity is not edited here. Email, phone, password, role, disabling sign-in or permissions changes revoke existing login credentials and API tokens. Phone changes clear SMS MFA. Omitted permissions are preserved; supplied IDs must be grantable by the actor.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserUpdate"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "delete_users_user_id",
        "tags": [
          "Users"
        ],
        "summary": "Delete a portal user",
        "x-required-scopes": [
          "users:write"
        ],
        "requestBody": {
          "description": "Required for companion sessions; integrations retain their existing deletion contract.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "account_id",
                  "revision"
                ],
                "properties": {
                  "account_id": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "revision": {
                    "$ref": "#/components/schemas/EditorRevision"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "User deleted"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/DestructiveRateLimited"
          }
        },
        "description": "Remove a current in-tree user using the reviewed account and revision. Companion portal role ordering is enforced; same-account peers and the signed-in identity are protected. Integration tokens cannot delete administrator roles. Existing login sessions and API tokens are revoked.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      }
    },
    "/users/{user_id}/invite": {
      "post": {
        "operationId": "post_users_user_id_invite",
        "tags": [
          "Users"
        ],
        "summary": "Resend a pending portal user invitation",
        "x-required-scopes": [
          "users:write"
        ],
        "description": "Companion administrators may resend an invitation for an editable, unverified user. Requires the current reviewed account and revision. The portal rechecks ownership, role and revision before using its existing activation mailer. Delivery failure is returned explicitly; use a new operation key only after a confirmed failed result. Retry ambiguous failures with the same key. Verified users and protected identities cannot be invited through this endpoint.",
        "parameters": [
          {
            "name": "user_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "account_id",
                  "revision"
                ],
                "properties": {
                  "account_id": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "revision": {
                    "$ref": "#/components/schemas/EditorRevision"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Invitation delivery attempted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "required": [
                        "id",
                        "invitation_email"
                      ],
                      "properties": {
                        "id": {
                          "type": "integer",
                          "minimum": 1
                        },
                        "invitation_email": {
                          "type": "string",
                          "enum": [
                            "sent",
                            "failed"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "Invitation service unavailable or delivery result not confirmed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/numbers/{number_id}/cancel": {
      "post": {
        "operationId": "post_numbers_number_id_cancel",
        "tags": [
          "Numbers"
        ],
        "summary": "Schedule number cancellation",
        "x-required-scopes": [
          "numbers:write"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/NumberCancellation"
                    }
                  }
                }
              }
            }
          },
          "202": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/NumberCancellation"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Conflicting current allocations (number_allocation_conflict)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/DestructiveRateLimited"
          }
        },
        "description": "Default-on read-only release guard: when `GET /capabilities` reports\n`data.read_only=true`, this operation returns `403 api_read_only` even\nfor a write-scoped token. When false, token scopes and individual estate\nfeature gates still apply.\n\nRecords the portal's 30-day notice intent on the exact current allocation and marks applicable WhatsApp registrations removal_requested in the same transaction. Existing quarantine/reuse holds are not cleared or shortened. The estate cancellation job owns later teardown and reuse eligibility; this request does not detach routing. A repeated pending request returns 200. Conflicting active allocations return 409 number_allocation_conflict. Requires number_writes enabled and numbers:write. Immediate cancellation is unavailable (422 not_available).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/NumberId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NumberCancellationRequest"
              }
            }
          }
        }
      }
    },
    "/lists/{type}/{id}": {
      "parameters": [
        {
          "name": "type",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "enum": [
              "acl",
              "abr",
              "dex",
              "ip"
            ]
          }
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 1
          }
        }
      ],
      "patch": {
        "description": "Default-on read-only release guard: when `GET /capabilities` reports\n`data.read_only=true`, this operation returns `403 api_read_only` even\nfor a write-scoped token. When false, token scopes and individual estate\nfeature gates still apply.\n",
        "operationId": "patch_lists_type_id",
        "tags": [
          "Resources"
        ],
        "summary": "Rename a routing list",
        "x-required-scopes": [
          "services:write"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/RoutingList"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResourceNameUpdate"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "delete_lists_type_id",
        "tags": [
          "Resources"
        ],
        "summary": "Delete a routing list",
        "x-required-scopes": [
          "services:write"
        ],
        "responses": {
          "204": {
            "description": "Resource deleted"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/DestructiveRateLimited"
          }
        },
        "description": "Default-on read-only release guard: when `GET /capabilities` reports\n`data.read_only=true`, this operation returns `403 api_read_only` even\nfor a write-scoped token. When false, token scopes and individual estate\nfeature gates still apply.\n\nSoft-deletes the resource and its entries.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      }
    },
    "/lists/{type}/{id}/entries": {
      "parameters": [
        {
          "name": "type",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "enum": [
              "acl",
              "abr",
              "dex",
              "ip"
            ]
          }
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 1
          }
        }
      ],
      "get": {
        "operationId": "get_lists_type_id_entries",
        "tags": [
          "Resources"
        ],
        "summary": "List entries in a routing list",
        "x-required-scopes": [
          "services:read"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/RoutingListEntry"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "description": "Returns every active entry ordered by id. This endpoint is not paginated."
      },
      "post": {
        "operationId": "post_lists_type_id_entries",
        "tags": [
          "Resources"
        ],
        "summary": "Add an entry to a routing list",
        "x-required-scopes": [
          "services:write"
        ],
        "responses": {
          "201": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/RoutingListEntry"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The acl number is already active on this list (list_entry_exists); details.entry_id identifies it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          }
        },
        "description": "Default-on read-only release guard: when `GET /capabilities` reports\n`data.read_only=true`, this operation returns `403 api_read_only` even\nfor a write-scoped token. When false, token scopes and individual estate\nfeature gates still apply.\n\nFields depend on the path type: acl requires number; abr requires area; ip requires ip; dex requires start_date and end_date, with optional name.\n\nAn acl number already active on the list returns `409 list_entry_exists`\nwith `details.entry_id`; a previously removed one is reactivated (201).\nCallPilot matches acl entries exactly or as a caller-number prefix.\n\nCallPlatform app sessions may only add a number of 7–20 digits (optional\nleading plus) to an acl list whose `mode` is `deny`, need the portal\nConfigs permission, and require `capabilities.features.caller_blocking`.\nThis changes live routing wherever the list is used.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RoutingListEntryWrite"
              }
            }
          }
        }
      }
    },
    "/lists/{type}/{id}/entries/{entryId}": {
      "parameters": [
        {
          "name": "type",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "enum": [
              "acl",
              "abr",
              "dex",
              "ip"
            ]
          }
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 1
          }
        },
        {
          "name": "entryId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 1
          }
        }
      ],
      "patch": {
        "operationId": "patch_lists_type_id_entries_entryId",
        "tags": [
          "Resources"
        ],
        "summary": "Update an entry in a routing list",
        "x-required-scopes": [
          "services:write"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/RoutingListEntry"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "description": "Default-on read-only release guard: when `GET /capabilities` reports\n`data.read_only=true`, this operation returns `403 api_read_only` even\nfor a write-scoped token. When false, token scopes and individual estate\nfeature gates still apply.\n\nPartial update; provide at least one writable field appropriate for this entry type.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RoutingListEntryWrite"
              }
            }
          }
        }
      },
      "delete": {
        "description": "Default-on read-only release guard: when `GET /capabilities` reports\n`data.read_only=true`, this operation returns `403 api_read_only` even\nfor a write-scoped token. When false, token scopes and individual estate\nfeature gates still apply.\n",
        "operationId": "delete_lists_type_id_entries_entryId",
        "tags": [
          "Resources"
        ],
        "summary": "Delete an entry from a routing list",
        "x-required-scopes": [
          "services:write"
        ],
        "responses": {
          "204": {
            "description": "Entry deleted"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/DestructiveRateLimited"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      }
    },
    "/address-book/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 1
          }
        }
      ],
      "patch": {
        "description": "Default-on read-only release guard: when `GET /capabilities` reports\n`data.read_only=true`, this operation returns `403 api_read_only` even\nfor a write-scoped token. When false, token scopes and individual estate\nfeature gates still apply.\n",
        "operationId": "patch_address_book_id",
        "tags": [
          "Resources"
        ],
        "summary": "Rename a address-book contact",
        "x-required-scopes": [
          "services:write"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AddressBookContact"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResourceNameUpdate"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "delete_address_book_id",
        "tags": [
          "Resources"
        ],
        "summary": "Delete a address-book contact",
        "x-required-scopes": [
          "services:write"
        ],
        "responses": {
          "204": {
            "description": "Resource deleted"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/DestructiveRateLimited"
          }
        },
        "description": "Default-on read-only release guard: when `GET /capabilities` reports\n`data.read_only=true`, this operation returns `403 api_read_only` even\nfor a write-scoped token. When false, token scopes and individual estate\nfeature gates still apply.\n\nSoft-deletes the resource and its entries.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      }
    },
    "/address-book/{id}/entries": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 1
          }
        }
      ],
      "get": {
        "operationId": "get_address_book_id_entries",
        "tags": [
          "Resources"
        ],
        "summary": "List entries in a address-book contact",
        "x-required-scopes": [
          "services:read"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AddressBookEntry"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "description": "Returns every active entry ordered by id. This endpoint is not paginated."
      },
      "post": {
        "operationId": "post_address_book_id_entries",
        "tags": [
          "Resources"
        ],
        "summary": "Add an entry to a address-book contact",
        "x-required-scopes": [
          "services:write"
        ],
        "responses": {
          "201": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AddressBookEntry"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          }
        },
        "description": "Default-on read-only release guard: when `GET /capabilities` reports\n`data.read_only=true`, this operation returns `403 api_read_only` even\nfor a write-scoped token. When false, token scopes and individual estate\nfeature gates still apply.\n\ntarget is required. SIP/number target type is derived by the server; schedule defaults to all days open.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddressBookEntryWrite"
              }
            }
          }
        }
      }
    },
    "/address-book/{id}/entries/{entryId}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 1
          }
        },
        {
          "name": "entryId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 1
          }
        }
      ],
      "patch": {
        "operationId": "patch_address_book_id_entries_entryId",
        "tags": [
          "Resources"
        ],
        "summary": "Update an entry in a address-book contact",
        "x-required-scopes": [
          "services:write"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AddressBookEntry"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "description": "Default-on read-only release guard: when `GET /capabilities` reports\n`data.read_only=true`, this operation returns `403 api_read_only` even\nfor a write-scoped token. When false, token scopes and individual estate\nfeature gates still apply.\n\nPartial update; provide at least one writable field appropriate for this entry type.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddressBookEntryWrite"
              }
            }
          }
        }
      },
      "delete": {
        "description": "Default-on read-only release guard: when `GET /capabilities` reports\n`data.read_only=true`, this operation returns `403 api_read_only` even\nfor a write-scoped token. When false, token scopes and individual estate\nfeature gates still apply.\n",
        "operationId": "delete_address_book_id_entries_entryId",
        "tags": [
          "Resources"
        ],
        "summary": "Delete an entry from a address-book contact",
        "x-required-scopes": [
          "services:write"
        ],
        "responses": {
          "204": {
            "description": "Entry deleted"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/DestructiveRateLimited"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      }
    },
    "/reports/active-calls/overview": {
      "get": {
        "operationId": "get_reports_active_calls_overview",
        "x-required-scopes": [
          "reports:read"
        ],
        "tags": [
          "Reports"
        ],
        "summary": "Current SIP connections grouped by authorised account",
        "description": "Additive estate-gated overview of SBC dialog connections, not unique phone calls. Requires active_calls_overview capability. Current account is the default; include_children=true or selecting a child root additionally requires a bound administrator, effective accounts:read and reports:read scopes and current Live Stats permission. Ordinary companion users can read only their own account. Hierarchy and permissions are revalidated on every request. No unrelated account names or SIP details are returned. Zero-activity accounts are included. Accounts sort by total connections descending, case-insensitive account name ascending, then account ID. q is a literal case-insensitive account-name substring; totals ignore search and pagination. Each offset page is a fresh snapshot, so activity may reorder accounts between pages. Limits are 1,000 accounts (selected root first, then ID), 10,000 newest account-owned dialog connections and a two-second database statement deadline. is_complete describes aggregation completeness, independently of page has_more; truncated totals are lower bounds and omitted activity must not be presented as zero. When both bounds apply, truncation_reason is account_limit. scoped_accounts and matching_accounts describe only sampled accounts. Errors are never empty snapshots. Database state can lag calls. Estates without this feature retain /reports/active-calls. Unknown query parameters are rejected.",
        "parameters": [
          {
            "name": "account_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "include_children",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "One-based live snapshot page; (page - 1) times per_page must be less than 1,000.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1000,
              "default": 1
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Bounded account connection snapshot",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActiveCallOverview"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "Active connection snapshot unavailable or exceeded its statement deadline; error code active_calls_unavailable. Retry later; do not infer zero activity.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/reports/active-calls": {
      "get": {
        "operationId": "get_reports_active_calls",
        "x-required-scopes": [
          "reports:read"
        ],
        "tags": [
          "Reports"
        ],
        "summary": "Current SIP connections for one account",
        "description": "Read-only SBC dialog snapshot, limited to 100 newest connections. Companion users also need the portal Live Stats permission. Delayed database state may lag the live call. Does not control calls or promise a unique session count across call legs.",
        "parameters": [
          {
            "name": "account_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "SIP connection snapshot",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ActiveCall"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "has_more": {
                          "type": "boolean"
                        },
                        "source": {
                          "type": "string",
                          "const": "sbc_dialogs"
                        },
                        "updated_at": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "refresh_after_seconds": {
                          "type": "integer",
                          "const": 20
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          }
        }
      }
    },
    "/reports/calls": {
      "get": {
        "operationId": "get_reports_calls",
        "tags": [
          "Reports"
        ],
        "summary": "List calls",
        "x-required-scopes": [
          "reports:read"
        ],
        "responses": {
          "200": {
            "description": "Report result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CallReportPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "$ref": "#/components/responses/ReportingBadResponse"
          },
          "503": {
            "$ref": "#/components/responses/ReportingUnavailable"
          }
        },
        "description": "Uses the estate reporting service. Account scope defaults to the token hierarchy, or an exact verified account_id. Dates are inclusive calendar days in `timezone` (an IANA zone, default UTC), defaulting to the last seven days including today in that zone and bounded to 31 days. Call times in results stay UTC. Caller/destination are literal substring filters. Unknown query parameters are rejected. No pricing, raw CDR JSON or custom SQL is exposed. Live offset pagination has a 10,000-row offset ceiling; narrow dates for deeper results. Inbound records represent sessions; outbound records represent call legs.",
        "parameters": [
          {
            "$ref": "#/components/parameters/AccountFilter"
          },
          {
            "$ref": "#/components/parameters/ReportDirection"
          },
          {
            "$ref": "#/components/parameters/ReportStartDate"
          },
          {
            "$ref": "#/components/parameters/ReportEndDate"
          },
          {
            "$ref": "#/components/parameters/ReportTimezone"
          },
          {
            "$ref": "#/components/parameters/ReportCaller"
          },
          {
            "$ref": "#/components/parameters/ReportDestination"
          },
          {
            "$ref": "#/components/parameters/ReportMinDuration"
          },
          {
            "$ref": "#/components/parameters/ReportMaxDuration"
          },
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          }
        ]
      }
    },
    "/reports/summary": {
      "get": {
        "operationId": "get_reports_summary",
        "tags": [
          "Reports"
        ],
        "summary": "Summarise calls",
        "x-required-scopes": [
          "reports:read"
        ],
        "responses": {
          "200": {
            "description": "Report result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CallReportSummary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "$ref": "#/components/responses/ReportingBadResponse"
          },
          "503": {
            "$ref": "#/components/responses/ReportingUnavailable"
          }
        },
        "description": "Uses the estate reporting service. Account scope defaults to the token hierarchy, or an exact verified account_id. Dates are inclusive calendar days in `timezone` (an IANA zone, default UTC), defaulting to the last seven days including today in that zone and bounded to 31 days. Call times in results stay UTC. Caller/destination are literal substring filters. Unknown query parameters are rejected. No pricing, raw CDR JSON or custom SQL is exposed. Status meanings match the existing portal call logs; Connected is the log status, not strict human-answer analytics.",
        "parameters": [
          {
            "name": "group_by",
            "in": "query",
            "description": "Optional grouping by stable service id, destination number, or status. Returns groups alongside unchanged totals and statuses. At most 1000 group/status pairs; narrow dates for larger results.",
            "schema": {
              "type": "string",
              "enum": [
                "service",
                "number",
                "status"
              ]
            }
          },
          {
            "$ref": "#/components/parameters/AccountFilter"
          },
          {
            "$ref": "#/components/parameters/ReportDirection"
          },
          {
            "$ref": "#/components/parameters/ReportStartDate"
          },
          {
            "$ref": "#/components/parameters/ReportEndDate"
          },
          {
            "$ref": "#/components/parameters/ReportTimezone"
          },
          {
            "$ref": "#/components/parameters/ReportCaller"
          },
          {
            "$ref": "#/components/parameters/ReportDestination"
          },
          {
            "$ref": "#/components/parameters/ReportMinDuration"
          },
          {
            "$ref": "#/components/parameters/ReportMaxDuration"
          }
        ]
      }
    },
    "/media/audio": {
      "get": {
        "operationId": "get_media_audio",
        "tags": [
          "Media"
        ],
        "summary": "List audio available to the account",
        "x-required-scopes": [
          "media:read"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AudioFile"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "description": "Requires capabilities.features.media_reads=true; otherwise authenticated requests return 403 feature_unavailable. Audio catalogue under media:read. The compatibility /audio route provides the same gated catalogue under services:read. processed indicates the portal processor completed, not that the retained S3 object still exists; download verifies object readiness. Reviewed companion recording/import uses the separately gated audio library upload routes and the portal processor. Unknown filters are rejected and offset must not exceed 10,000.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "$ref": "#/components/parameters/AccountFilter"
          }
        ]
      }
    },
    "/media/audio/{audio_id}/download": {
      "get": {
        "operationId": "get_media_audio_audio_id_download",
        "tags": [
          "Media"
        ],
        "summary": "Get a temporary audio download URL",
        "x-required-scopes": [
          "media:read"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/MediaDownload"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/MediaUnavailable"
          }
        },
        "description": "Requires capabilities.features.media_reads=true; otherwise authenticated requests return 403 feature_unavailable. Authorises an active in-tree audio file and checks its processed WAV exists using S3 metadata only. Unprocessed/archived objects return 409 media_not_ready; missing/empty objects return 404 media_not_found; storage/IAM failures return 503 media_unavailable. Returns a signed GET URL valid for at most five minutes. Use disposition=inline for playback. Load it directly without forwarding the API bearer token to S3.",
        "parameters": [
          {
            "$ref": "#/components/parameters/MediaDisposition"
          },
          {
            "name": "audio_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ]
      }
    },
    "/media/recordings": {
      "get": {
        "operationId": "get_media_recordings",
        "tags": [
          "Media"
        ],
        "summary": "List recording, voicemail and conference metadata",
        "x-required-scopes": [
          "media:read"
        ],
        "responses": {
          "200": {
            "description": "Recording metadata",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecordingPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "description": "Invalid stored recording metadata (media_bad_response)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "description": "Requires capabilities.features.media_reads=true; otherwise authenticated requests return 403 feature_unavailable. Metadata from the estate transcription/media catalogue, scoped to the token tree. Not an inventory of every S3 object. Inclusive metadata creation dates are calendar days in `timezone` (default UTC) and default to the last seven days including today, maximum 31 days; media processing may finish after the report's call-start date. Filter by exact call_id from reports and supply an explicit date window for historical playback. Zero or multiple media rows can match a call. Page must be at most 1000 and offset at most 10,000. Unknown query keys are rejected. Invalid stored dates return 502 media_bad_response.",
        "parameters": [
          {
            "$ref": "#/components/parameters/AccountFilter"
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page number; (page - 1) * per_page must also not exceed 10,000.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1000,
              "default": 1
            }
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "$ref": "#/components/parameters/ReportStartDate"
          },
          {
            "$ref": "#/components/parameters/ReportEndDate"
          },
          {
            "$ref": "#/components/parameters/ReportTimezone"
          },
          {
            "name": "call_id",
            "in": "query",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64,
              "pattern": "^[^\\x00-\\x1F\\x7F]+$"
            }
          },
          {
            "name": "media_type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "recording",
                "voicemail",
                "conference"
              ]
            }
          }
        ]
      }
    },
    "/media/recordings/{recording_id}": {
      "get": {
        "operationId": "get_media_recordings_recording_id",
        "tags": [
          "Media"
        ],
        "summary": "Get recording metadata and transcript",
        "x-required-scopes": [
          "media:read"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/RecordingDetail"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "description": "Invalid stored recording metadata (media_bad_response)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "recording_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "description": "Requires capabilities.features.media_reads=true; otherwise authenticated requests return 403 feature_unavailable. Returns metadata plus transcript and summary when available. Stored media URLs and unscoped storage paths are not returned. Invalid stored dates return 502 media_bad_response."
      }
    },
    "/media/recordings/{recording_id}/download": {
      "get": {
        "operationId": "get_media_recordings_recording_id_download",
        "tags": [
          "Media"
        ],
        "summary": "Get a temporary recording download URL",
        "x-required-scopes": [
          "media:read"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/MediaDownload"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/MediaUnavailable"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/MediaDisposition"
          },
          {
            "name": "recording_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "description": "Requires capabilities.features.media_reads=true; otherwise authenticated requests return 403 feature_unavailable. Rechecks ownership, validates the configured estate bucket and checks the S3 object metadata before signing. Missing/empty media returns 404 media_not_found; archived media returns 409 media_not_ready; storage/IAM failures return 503 media_unavailable. The URL is valid for at most five minutes. Use disposition=inline for playback, request a new URL after expiry, and never forward the API bearer token to S3. Objects can still disappear after this check."
      }
    },
    "/me": {
      "get": {
        "operationId": "get_me",
        "tags": [
          "Discovery"
        ],
        "summary": "Get the authenticated API identity",
        "description": "Returns the verified token owner and account plus granted scopes. An estate-scoped service token may have user:null. Secrets and token hashes are not returned.",
        "x-required-scopes": [],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ApiIdentity"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/capabilities": {
      "get": {
        "operationId": "get_capabilities",
        "tags": [
          "Discovery"
        ],
        "summary": "Discover the estate and enabled API features",
        "description": "Reports effective estate/caller gates and configuration readiness, not a live backend health probe. Conference control additionally requires an explicit conferences:write grant, a permitted current owner, configured call-state connection, executor credential and an executor host allowlist. Partner provisioning approval is independent of conference access; a true conference flag does not prove executor reachability, membership or live acceptance. data.read_only describes the caller's effective release access; false does not independently grant provisioning or any other write workflow. The global estate read-only guard is enabled by default and, when active, rejects every unsafe authenticated method with 403 api_read_only and advertises write features false. media_reads is independently disabled by default and gates both /media/* and /audio, including metadata. Download flags additionally require their configured bucket; no flag proves private media storage or object readiness. A true feature flag still requires the appropriate token scope. Check /services/capabilities for estate service-type entitlements. Unsupported invitation and upload workflows are explicitly false.",
        "x-required-scopes": [],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/EstateCapabilities"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/services/ivr": {
      "post": {
        "operationId": "create_companion_ivr",
        "x-required-scopes": [
          "services:write"
        ],
        "tags": [
          "Services"
        ],
        "summary": "Create an unassigned IVR keypad service",
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/CompanionIvrDocument"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompanionIvrMutation"
              },
              "example": {
                "account_id": 1,
                "name": "Reception keypad",
                "menu": {
                  "greeting_audio_id": "1",
                  "max_repeats": 3,
                  "routes": [
                    {
                      "digit": "1",
                      "name": "Repeat",
                      "action": "repeat"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/services/{service_id}/ivr": {
      "get": {
        "operationId": "get_companion_ivr",
        "x-required-scopes": [
          "services:read"
        ],
        "tags": [
          "Services"
        ],
        "summary": "Read an IVR keypad menu without exposing private routing parameters",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/CompanionIvrDocument"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          }
        },
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "account_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ]
      },
      "patch": {
        "operationId": "update_companion_ivr",
        "x-required-scopes": [
          "services:write"
        ],
        "tags": [
          "Services"
        ],
        "summary": "Review and incrementally update an IVR tree",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/CompanionIvrDocument"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "428": {
            "description": "A current config_hash or If-Match is required."
          }
        },
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "Quoted current config_hash; may instead supply base_config_hash."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompanionIvrMutation"
              }
            }
          }
        }
      }
    },
    "/services/{service_id}/flow-overview": {
      "get": {
        "operationId": "get_companion_flow_overview",
        "x-required-scopes": [
          "services:read"
        ],
        "tags": [
          "Services"
        ],
        "summary": "Explore a service flow by following branches",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/CompanionFlowOverview"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          }
        },
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "account_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "description": "Read-only navigation for API graphs and portal node lists. Parameters, credentials, headers and URLs are never included. The result is not a publishable graph."
      }
    },
    "/agents/management": {
      "get": {
        "tags": [
          "AI agents"
        ],
        "operationId": "managedAgents",
        "summary": "List account-owned AI agents including drafts",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-scopes": [
          "agents:read"
        ],
        "parameters": [
          {
            "name": "account_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ManagedAgentPage"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/agents/{agent_id}/management": {
      "get": {
        "tags": [
          "AI agents"
        ],
        "operationId": "managedAgent",
        "summary": "Read safe AI settings, curated models and flow navigation",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-scopes": [
          "agents:read"
        ],
        "parameters": [
          {
            "name": "agent_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,100}$"
            }
          },
          {
            "name": "account_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ManagedAgentDocument"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "AI agents"
        ],
        "operationId": "updateManagedAgent",
        "summary": "Review and update existing AI voice and language-model settings",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-scopes": [
          "agents:write"
        ],
        "parameters": [
          {
            "name": "agent_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,100}$"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ManagedAgentDocument"
                    }
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "account_id",
                  "revision",
                  "settings"
                ],
                "properties": {
                  "account_id": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "revision": {
                    "type": "string",
                    "pattern": "^[a-f0-9]{64}$"
                  },
                  "settings": {
                    "$ref": "#/components/schemas/AgentSettings"
                  }
                }
              },
              "example": {
                "account_id": 2,
                "revision": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
                "settings": {
                  "turn_timeout": 10
                }
              }
            }
          }
        },
        "description": "Requires current portal agents permission, a live account hierarchy, agent_writes estate feature and a companion principal. Only submitted controls change; prompts, tools, privacy, graph and automation remain untouched. Server-only provider credentials. A stale revision returns 412; an uncertain publish keeps its idempotent operation pending."
      }
    },
    "/agents/{agent_id}/configuration": {
      "get": {
        "tags": [
          "AI agents"
        ],
        "operationId": "agentConfiguration",
        "summary": "Read editable AI identity, greeting, voice and language fields",
        "description": "Requires a companion principal with current portal agents permission and an agent owned by the selected account in its permitted hierarchy. Returns field values, labels, bounds and current voice/language choices; provider credentials and raw provider configuration are never returned. A supported published CallPlatform flow exposes fields even when the principal cannot write; editable is the write permission indicator. Unsupported saved flows return supported=false, editable=false, a reason and empty fields. Draft agents cannot use this endpoint. Handover node references open the separate flow editor. Language-model and voice-tuning controls remain on the management endpoint.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-scopes": [
          "agents:read"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ManagedAgentId"
          },
          {
            "$ref": "#/components/parameters/ManagedAgentAccount"
          }
        ],
        "responses": {
          "200": {
            "description": "Configuration field document; inspect supported and editable before editing.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AgentConfigurationDocument"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/AgentEditorInvalid"
          },
          "503": {
            "$ref": "#/components/responses/AgentEditorUnavailable"
          }
        }
      },
      "patch": {
        "tags": [
          "AI agents"
        ],
        "operationId": "updateAgentConfiguration",
        "summary": "Publish changed AI identity, greeting, voice and language fields",
        "description": "Requires the agent_writes estate feature, a writable companion principal and current portal agent-management permission. Send only changed field keys from the reviewed configuration document, its revision and exact account_id. Omitted fields retain their saved values; text is literal, including @, +, percent signs and template variables. The portal compiler preserves unedited graph data and unrelated provider/automation settings. Voice choices and speech-model language compatibility are checked again at publication. Custom greeting variations that cannot be identified safely require editing in the portal. A successful response is the refreshed document with a new revision. Publication spans the provider, automation registry and portal; it is not an atomic transaction across those systems. A 503 may follow an applied provider update, and keeps the durable operation pending. Reuse the same Idempotency-Key and identical body to check the reviewed operation; do not retry it under a fresh key. Inspect the current agent and portal restore history before deciding on recovery. No automatic provider retry or compensation is performed.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-scopes": [
          "agents:write"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ManagedAgentId"
          },
          {
            "$ref": "#/components/parameters/AgentEditorIdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AgentConfigurationPatch"
              },
              "example": {
                "account_id": 2,
                "revision": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
                "fields": {
                  "greeting": "Hello, you have reached Example Support. How can I help?",
                  "business_name": "Example Support"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Confirmed publication, or no change; refreshed configuration document.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AgentConfigurationDocument"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/AgentEditorPending"
          },
          "412": {
            "$ref": "#/components/responses/AgentEditorConflict"
          },
          "422": {
            "$ref": "#/components/responses/AgentEditorInvalid"
          },
          "503": {
            "$ref": "#/components/responses/AgentEditorUnavailable"
          }
        }
      }
    },
    "/agents/{agent_id}/flow": {
      "get": {
        "tags": [
          "AI agents"
        ],
        "operationId": "editableAgentFlow",
        "summary": "Read AI steps, editable fields and stable path identities",
        "description": "Requires the same account ownership and current portal agents permission as configuration. Supported published CallPlatform flows expose stable node IDs and named ports with target IDs. Fields and insertion templates define the controls the client may offer. Advanced nodes and unrecognised ports are retained with editable=false; do not infer permission from their kind. Unsupported graphs remain read-only with a reason and safe navigation metadata. The response is a projection, not a replacement graph or provider payload. Draft agents are unsupported.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-scopes": [
          "agents:read"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ManagedAgentId"
          },
          {
            "$ref": "#/components/parameters/ManagedAgentAccount"
          }
        ],
        "responses": {
          "200": {
            "description": "Flow projection and insertion catalogue; inspect supported, editable and per-port permissions.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AgentEditableFlowDocument"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/AgentEditorInvalid"
          },
          "503": {
            "$ref": "#/components/responses/AgentEditorUnavailable"
          }
        }
      },
      "patch": {
        "tags": [
          "AI agents"
        ],
        "operationId": "updateEditableAgentFlow",
        "summary": "Publish incremental AI step edits, path changes and insertions",
        "description": "Requires the agent_writes estate feature and current companion agent-management permission. Send the reviewed flow revision, exact account_id and 1–25 operations in execution order. update_node changes only submitted fields; reconnect changes one known port; insert_node creates a client-named step after an editable port. Node deletion, arbitrary node kinds and raw graph replacement are not supported. Unknown node data, connection metadata and protected handover rules remain stored. Decision routes are a full list keyed by stable route IDs: removing a route removes its outgoing edge. Handover rules are incremental by their original index; omission never deletes a rule. Inserting a step routes the selected incoming path to it and connects each of its outgoing ports to the prior target, when present. Reconnect later in the same request to choose other targets. Every new decision or transfer fallback port must be connected before saving. The server compiles and validates the resulting flow before publishing. Publication is not atomic across the provider, automation registry and portal. An uncertain 503 can follow a partial publish and leaves the operation pending; never submit a fresh key to repeat it. Reuse the original key and body, inspect current state and use portal restore history for recovery. A 200 confirms the reviewed changes and returns the refreshed flow document.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-scopes": [
          "agents:write"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ManagedAgentId"
          },
          {
            "$ref": "#/components/parameters/AgentEditorIdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AgentFlowPatch"
              },
              "example": {
                "account_id": 2,
                "revision": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
                "operations": [
                  {
                    "op": "update_node",
                    "node_id": "instruction_1",
                    "fields": {
                      "instruction": "Ask the caller for their preferred appointment day."
                    }
                  },
                  {
                    "op": "reconnect",
                    "node_id": "decision_1",
                    "port": "yes",
                    "target_id": "instruction_1"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Confirmed publication, or no change; refreshed editable flow document.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AgentEditableFlowDocument"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/AgentEditorPending"
          },
          "412": {
            "$ref": "#/components/responses/AgentEditorConflict"
          },
          "422": {
            "$ref": "#/components/responses/AgentEditorInvalid"
          },
          "503": {
            "$ref": "#/components/responses/AgentEditorUnavailable"
          }
        }
      }
    },
    "/agents/{agent_id}/insights": {
      "get": {
        "tags": [
          "AI agents"
        ],
        "operationId": "managedAgentInsights",
        "summary": "List filtered AI conversations and aggregates of the returned page",
        "description": "Reads stored provider analysis without generating evaluations or summaries. Omit both dates for the last seven UTC calendar days, including today; otherwise supply both inclusive dates, at most 90 days. Filters are applied at the provider and checked again on returned rows. Repeat the same dates and filters when using the opaque cursor; clear the cursor after any filter change. Each response contains at most 25 conversations. Summary and trends describe only its returned page; complete_range is true only for an initial, untruncated page with no more results. Provider records can change while paginating; this is not a fixed report snapshot.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-scopes": [
          "agents:read"
        ],
        "parameters": [
          {
            "name": "agent_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,100}$"
            }
          },
          {
            "name": "account_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 1000
            }
          },
          {
            "name": "date_from",
            "in": "query",
            "description": "Inclusive UTC start date; requires date_to, at most 90 inclusive days.",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2026-09-01"
            }
          },
          {
            "name": "date_to",
            "in": "query",
            "description": "Inclusive UTC end date; requires date_from.",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2026-09-07"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Provider processing state; independent of evaluation outcome.",
            "schema": {
              "type": "string",
              "enum": [
                "initiated",
                "in-progress",
                "processing",
                "done",
                "failed"
              ]
            }
          },
          {
            "name": "outcome",
            "in": "query",
            "description": "Stored success evaluation; error means evaluation failed to run, not a failed call.",
            "schema": {
              "type": "string",
              "enum": [
                "success",
                "failure",
                "unknown",
                "error"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AgentInsightPage"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/agents/{agent_id}/conversations/{conversation_id}": {
      "get": {
        "tags": [
          "AI agents"
        ],
        "operationId": "managedAgentConversation",
        "summary": "Read a conversation summary and spoken transcript",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-scopes": [
          "agents:read"
        ],
        "parameters": [
          {
            "name": "agent_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,100}$"
            }
          },
          {
            "name": "account_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "conversation_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,100}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AgentConversation"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/media/audio/library": {
      "get": {
        "tags": [
          "Media"
        ],
        "operationId": "audioLibrary",
        "summary": "List own and direct-parent shared audio",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-scopes": [
          "media:read"
        ],
        "parameters": [
          {
            "in": "query",
            "name": "account_id",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "in": "query",
            "name": "page",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 400
            }
          },
          {
            "in": "query",
            "name": "search",
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          },
          {
            "in": "query",
            "name": "category_id",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AudioLibraryPage"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/media/audio/categories": {
      "get": {
        "tags": [
          "Media"
        ],
        "operationId": "audioCategories",
        "summary": "List the portal audio category catalogue",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-scopes": [
          "media:read"
        ],
        "parameters": [
          {
            "in": "query",
            "name": "account_id",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "name": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/media/audio/uploads": {
      "post": {
        "tags": [
          "Media"
        ],
        "operationId": "uploadAudio",
        "summary": "Upload a recorded or imported WAV or MP3 clip",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-scopes": [
          "media:write"
        ],
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AudioLibraryItem"
                    }
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AudioUploadRequest"
              }
            }
          }
        },
        "description": "WAV is validated as 16-bit PCM mono/stereo at supported 8–48 kHz rates. MP3 is probed as a single audio stream. Both are at most 5 MiB and 120 seconds. No external URL or user filename is accepted. Processing uses the same portal normalization/upload worker in a private directory, producing 16 kHz mono WAV in the estate media bucket. Poll the library for ready or failed status. Requires media_writes and configs.php permission."
      }
    },
    "/media/audio/{audio_id}": {
      "patch": {
        "tags": [
          "Media"
        ],
        "operationId": "updateAudioMetadata",
        "summary": "Update the name and category of owned audio",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-scopes": [
          "media:write"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "audio_id",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AudioLibraryItem"
                    }
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AudioMetadataRequest"
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Media"
        ],
        "operationId": "removeAudio",
        "summary": "Remove owned audio when no active service or agent uses it",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-scopes": [
          "media:write"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "audio_id",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "integer"
                        },
                        "removed": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "account_id",
                  "revision"
                ],
                "properties": {
                  "account_id": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "revision": {
                    "type": "string",
                    "pattern": "^[a-f0-9]{64}$"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/media/audio/{audio_id}/preview": {
      "get": {
        "tags": [
          "Media"
        ],
        "operationId": "previewAudio",
        "summary": "Play authorized ready audio with a short-lived signed URL",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-scopes": [
          "media:read"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "audio_id",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "in": "query",
            "name": "account_id",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "required": [
                        "url",
                        "expires_at",
                        "method",
                        "content_type",
                        "size_bytes",
                        "disposition"
                      ],
                      "properties": {
                        "url": {
                          "type": "string",
                          "format": "uri"
                        },
                        "expires_at": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "method": {
                          "type": "string",
                          "const": "GET"
                        },
                        "content_type": {
                          "type": "string",
                          "const": "audio/wav"
                        },
                        "size_bytes": {
                          "type": "integer",
                          "minimum": 1
                        },
                        "disposition": {
                          "type": "string",
                          "const": "inline"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/accounts/options": {
      "get": {
        "operationId": "get_account_setup_options",
        "tags": [
          "Accounts"
        ],
        "summary": "Get current account setup choices and published plans",
        "x-required-scopes": [
          "accounts:read"
        ],
        "parameters": [
          {
            "name": "account_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AccountOptions"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          }
        },
        "description": "Companion sessions only. Uses current portal country/timezone choices and the same published, customer-safe rate-plan catalogue. No supplier provenance or pricing credentials are returned."
      }
    },
    "/users/options": {
      "get": {
        "operationId": "get_user_setup_options",
        "tags": [
          "Users"
        ],
        "summary": "Get current assignable user roles and page permissions",
        "x-required-scopes": [
          "users:read"
        ],
        "parameters": [
          {
            "name": "account_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/UserOptions"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          }
        }
      }
    },
    "/services/timezones": {
      "get": {
        "operationId": "get_service_timezones",
        "tags": [
          "Services"
        ],
        "summary": "List searchable IANA time zones with their current UTC offsets",
        "x-required-scopes": [
          "services:read"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "offset": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "id",
                          "name",
                          "offset"
                        ]
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Partner API token (prefix `vvp_`)"
      }
    },
    "parameters": {
      "MediaDisposition": {
        "name": "disposition",
        "in": "query",
        "description": "Use inline for audio-player playback; attachment downloads the file.",
        "schema": {
          "type": "string",
          "enum": [
            "attachment",
            "inline"
          ],
          "default": "attachment"
        }
      },
      "IfMatch": {
        "name": "If-Match",
        "in": "header",
        "description": "Quoted SHA256 config_hash from the reviewed service GET. Required for service mutations unless the documented body hash is supplied. No wildcards.",
        "schema": {
          "type": "string",
          "pattern": "^\"[a-f0-9]{64}\"$"
        }
      },
      "AccountFilter": {
        "name": "account_id",
        "in": "query",
        "description": "Exact account in the verified token hierarchy; omitted means the whole hierarchy.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      },
      "ReportDirection": {
        "name": "direction",
        "in": "query",
        "schema": {
          "type": "string",
          "enum": [
            "inbound",
            "outbound"
          ],
          "default": "inbound"
        }
      },
      "ReportStartDate": {
        "name": "start_date",
        "in": "query",
        "schema": {
          "type": "string",
          "format": "date"
        },
        "description": "First calendar day in timezone, inclusive. Default: six days before end_date."
      },
      "ReportEndDate": {
        "name": "end_date",
        "in": "query",
        "schema": {
          "type": "string",
          "format": "date"
        },
        "description": "Last calendar day in timezone, inclusive. Default: today in timezone. At most 31 days."
      },
      "ReportTimezone": {
        "name": "timezone",
        "in": "query",
        "schema": {
          "type": "string",
          "maxLength": 64,
          "example": "Australia/Sydney"
        },
        "description": "IANA timezone (backward-compatible aliases accepted) whose calendar days start_date and end_date name, for example Europe/London. Default: UTC. Unknown zones and bare offsets return 422."
      },
      "ReportCaller": {
        "name": "caller",
        "in": "query",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 100
        },
        "description": "Literal substring; percent, underscore and backslash are not wildcards."
      },
      "ReportDestination": {
        "name": "destination",
        "in": "query",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 100
        },
        "description": "Literal substring of the inbound number or outbound destination."
      },
      "ReportMinDuration": {
        "name": "min_duration",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 0,
          "maximum": 604800,
          "default": 0
        }
      },
      "ReportMaxDuration": {
        "name": "max_duration",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 604800
        },
        "description": "Maximum seconds, at least min_duration; omitted means no upper duration filter."
      },
      "Page": {
        "name": "page",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        }
      },
      "PerPage": {
        "name": "per_page",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 25
        }
      },
      "NumberId": {
        "name": "number_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "integer"
        }
      },
      "ServiceId": {
        "name": "service_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "integer"
        }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "description": "UUID; identical retries with the same key return the original result. Use a new key for any changed request.",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "ConferenceIdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "description": "UUID; use a fresh key per intended action and preserve it for identical retries.",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "ManagedAgentId": {
        "name": "agent_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "pattern": "^[A-Za-z0-9_-]{1,100}$"
        }
      },
      "ManagedAgentAccount": {
        "name": "account_id",
        "in": "query",
        "required": true,
        "description": "Exact owning account, verified against the principal's current permitted hierarchy.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      },
      "AgentEditorIdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "description": "A UUID for this reviewed publication. Reuse this key and the identical body after an uncertain response. A completed operation replays its result; an ambiguous publish stays pending and is not automatically reissued. A different body under the same key is rejected.",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      }
    },
    "schemas": {
      "NumberOrderPricing": {
        "type": "object",
        "required": [
          "currency",
          "setup_pence",
          "monthly_pence",
          "due_now_pence",
          "payment_type"
        ],
        "properties": {
          "currency": {
            "type": "string",
            "example": "GBP"
          },
          "setup_pence": {
            "type": "integer",
            "minimum": 0
          },
          "monthly_pence": {
            "type": "integer",
            "minimum": 0
          },
          "due_now_pence": {
            "type": "integer",
            "minimum": 0
          },
          "payment_type": {
            "type": "string",
            "enum": [
              "prepay",
              "postpay"
            ]
          }
        }
      },
      "NumberOrderCandidate": {
        "type": "object",
        "required": [
          "source",
          "number",
          "quote",
          "pricing",
          "expires_at"
        ],
        "properties": {
          "source": {
            "type": "string",
            "enum": [
              "stock",
              "magrathea"
            ]
          },
          "number_id": {
            "type": [
              "integer",
              "null"
            ]
          },
          "number": {
            "type": "string",
            "example": "+441632960001"
          },
          "grade_id": {
            "type": "integer"
          },
          "grade_name": {
            "type": "string"
          },
          "quote": {
            "type": "string"
          },
          "pricing": {
            "$ref": "#/components/schemas/NumberOrderPricing"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "NumberOrder": {
        "type": "object",
        "required": [
          "order_id",
          "status",
          "source",
          "number",
          "pricing"
        ],
        "properties": {
          "order_id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "review",
              "completed",
              "rejected"
            ]
          },
          "source": {
            "type": "string",
            "enum": [
              "stock",
              "magrathea"
            ]
          },
          "number": {
            "type": "string"
          },
          "number_id": {
            "type": [
              "integer",
              "null"
            ]
          },
          "pricing": {
            "$ref": "#/components/schemas/NumberOrderPricing"
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "allocation_id": {
            "type": [
              "integer",
              "null"
            ]
          },
          "rental_id": {
            "type": [
              "integer",
              "null"
            ]
          },
          "charge_id": {
            "type": [
              "integer",
              "null"
            ]
          },
          "credit_ledger_id": {
            "type": [
              "integer",
              "null"
            ]
          }
        }
      },
      "AgentEditorDocument": {
        "type": "object",
        "required": [
          "id",
          "account_id",
          "name",
          "revision",
          "editable",
          "supported",
          "reason"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "account_id": {
            "type": "integer",
            "minimum": 1
          },
          "name": {
            "type": "string"
          },
          "revision": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$",
            "description": "Opaque revision of portal flow, provider state and the reviewed automation configuration. Use the value from the corresponding configuration or flow GET; it is not interchangeable with the older management revision. Re-read and review after a 412."
          },
          "editable": {
            "type": "boolean",
            "description": "Supported flow and current principal has agent-management write permission; estate write gates still apply."
          },
          "supported": {
            "type": "boolean",
            "description": "Saved published flow has the supported CallPlatform compiler and unambiguous node/port identities."
          },
          "reason": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "AgentConfigurationDocument": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AgentEditorDocument"
          },
          {
            "type": "object",
            "required": [
              "fields",
              "handover_nodes"
            ],
            "properties": {
              "fields": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/AgentEditorField"
                }
              },
              "handover_nodes": {
                "type": "array",
                "description": "References to human handover steps editable through the flow endpoint.",
                "items": {
                  "type": "object",
                  "required": [
                    "id",
                    "title"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "title": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        ]
      },
      "AgentEditableFlowDocument": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AgentEditorDocument"
          },
          {
            "type": "object",
            "required": [
              "nodes",
              "insertable"
            ],
            "properties": {
              "nodes": {
                "type": "array",
                "maxItems": 500,
                "items": {
                  "$ref": "#/components/schemas/AgentEditableNode"
                }
              },
              "insertable": {
                "type": "array",
                "description": "Server-authorised insertion kinds and initial field definitions; empty when not editable.",
                "items": {
                  "type": "object",
                  "required": [
                    "kind",
                    "label",
                    "fields"
                  ],
                  "properties": {
                    "kind": {
                      "type": "string",
                      "enum": [
                        "instruction",
                        "decision",
                        "transfer",
                        "end"
                      ]
                    },
                    "label": {
                      "type": "string"
                    },
                    "fields": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AgentEditorField"
                      }
                    }
                  }
                }
              }
            }
          }
        ]
      },
      "AgentEditorField": {
        "type": "object",
        "required": [
          "key",
          "label",
          "type",
          "value",
          "required"
        ],
        "description": "Render the server-provided control and bounds, retaining its exact key and literal value. required applies when a value is supplied or a new step is created; it does not require resending unchanged fields. Select and transfer-mode options are dynamic. A current legacy selection can remain unchanged even when it is no longer offered for a new selection.",
        "properties": {
          "key": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "text",
              "multiline",
              "select",
              "integer",
              "routes",
              "transfer_rules"
            ]
          },
          "value": {
            "description": "Current scalar value, decision-route list or projected phone-handover-rule list, according to type.",
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              },
              {
                "type": "array",
                "items": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/AgentDecisionRouteValue"
                    },
                    {
                      "$ref": "#/components/schemas/AgentTransferRuleValue"
                    }
                  ]
                }
              }
            ]
          },
          "required": {
            "type": "boolean"
          },
          "max_length": {
            "type": "integer",
            "minimum": 1,
            "description": "Maximum Unicode characters for text fields."
          },
          "minimum": {
            "type": "number"
          },
          "maximum": {
            "type": "number"
          },
          "max_items": {
            "type": "integer",
            "minimum": 1,
            "maximum": 20
          },
          "protected_rules": {
            "type": "integer",
            "minimum": 0,
            "description": "Number of advanced/non-phone handover rules retained on the server and omitted from value; cannot be overwritten or removed here."
          },
          "options": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "value",
                "label"
              ],
              "properties": {
                "value": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                }
              }
            }
          },
          "template": {
            "allOf": [
              {
                "$ref": "#/components/schemas/AgentTransferRuleValue"
              }
            ],
            "description": "Initial phone-handover rule with index=null, empty phone number and a permitted transfer mode. Complete the international number before submitting; this draft is not itself valid."
          }
        }
      },
      "AgentDecisionRouteValue": {
        "type": "object",
        "required": [
          "id",
          "label",
          "condition"
        ],
        "description": "Current or template route; saved legacy values may need correction to meet write bounds.",
        "properties": {
          "id": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "condition": {
            "type": "string"
          }
        }
      },
      "AgentTransferRuleValue": {
        "type": "object",
        "required": [
          "index",
          "label",
          "condition",
          "phone_number",
          "transfer_mode",
          "permission_prompt",
          "hold_message",
          "enabled"
        ],
        "description": "Projected editable phone rule or insertion template; complete draft values before saving.",
        "properties": {
          "index": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "label": {
            "type": "string"
          },
          "condition": {
            "type": "string"
          },
          "phone_number": {
            "type": "string"
          },
          "transfer_mode": {
            "type": "string"
          },
          "permission_prompt": {
            "type": "string"
          },
          "hold_message": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean"
          }
        }
      },
      "AgentConfigurationPatch": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "account_id",
          "revision",
          "fields"
        ],
        "properties": {
          "account_id": {
            "type": "integer",
            "minimum": 1
          },
          "revision": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$"
          },
          "fields": {
            "$ref": "#/components/schemas/AgentConfigurationFields"
          }
        }
      },
      "AgentConfigurationFields": {
        "type": "object",
        "additionalProperties": false,
        "minProperties": 1,
        "maxProperties": 10,
        "description": "Only changed keys; controls absent from the current GET are not writable. Text rejects control characters and is never URL-decoded.",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "Must contain non-whitespace text."
          },
          "business_name": {
            "type": "string",
            "maxLength": 120
          },
          "greeting": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2000,
            "description": "Must contain non-whitespace text."
          },
          "instructions": {
            "type": "string",
            "maxLength": 12000
          },
          "business_brief": {
            "type": "string",
            "maxLength": 12000,
            "description": "Offered only when a recognised business-brief instruction step exists; updates that step in place."
          },
          "responsibilities": {
            "type": "string",
            "maxLength": 12000,
            "description": "Offered only when a recognised responsibilities instruction step exists; updates that step in place."
          },
          "tone": {
            "type": "string",
            "enum": [
              "",
              "warm",
              "professional",
              "concise",
              "friendly"
            ]
          },
          "voice_id": {
            "type": "string",
            "description": "Choose a value from the current account voice options."
          },
          "language": {
            "type": "string",
            "description": "Choose a returned language identity compatible with the current speech model."
          }
        }
      },
      "AgentEditableNode": {
        "type": "object",
        "required": [
          "id",
          "title",
          "kind",
          "enabled",
          "editable",
          "fields",
          "ports"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable saved identity; preserve it exactly."
          },
          "title": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "description": "Supported graphs use start, instruction, decision, transfer, end or advanced. Unsupported read-only graphs may retain a descriptive legacy kind. Use editable and fields as authority."
          },
          "enabled": {
            "type": "boolean",
            "description": "Current state; changing node enabled state is not supported."
          },
          "editable": {
            "type": "boolean"
          },
          "fields": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AgentEditorField"
            }
          },
          "ports": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "id",
                "label",
                "target_id",
                "editable"
              ],
              "properties": {
                "id": {
                  "type": "string",
                  "description": "Stable named output port or decision route ID."
                },
                "label": {
                  "type": "string"
                },
                "target_id": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Saved target node or null for an unwired path."
                },
                "editable": {
                  "type": "boolean",
                  "description": "False for unknown/protected paths."
                }
              }
            }
          },
          "paths": {
            "type": "array",
            "description": "Optional read-only navigation on unsupported legacy flows.",
            "items": {
              "type": "object",
              "properties": {
                "to": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "AgentDecisionRoute": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "condition"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{1,80}$",
            "description": "Stable unique path ID; main, always and failure are reserved and cannot be used."
          },
          "label": {
            "type": "string",
            "maxLength": 100
          },
          "condition": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2000,
            "description": "Must contain non-whitespace text."
          }
        }
      },
      "AgentTransferRule": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "index"
        ],
        "description": "A patch to one phone destination at its original non-negative index; index=null appends a new rule. Only submitted properties change and omitted rules survive. Existing advanced/non-phone rules are protected. New rules must supply a valid phone_number and use a currently offered transfer_mode (the server default is warm). Existing rule indices must be unique in a save. Disable an editable destination using enabled=false; omission does not delete it.",
        "properties": {
          "index": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "label": {
            "type": "string",
            "maxLength": 100
          },
          "condition": {
            "type": "string",
            "maxLength": 2000
          },
          "phone_number": {
            "type": "string",
            "pattern": "^\\+[1-9][0-9]{6,14}$"
          },
          "transfer_mode": {
            "type": "string",
            "enum": [
              "warm",
              "blind",
              "three_way"
            ]
          },
          "permission_prompt": {
            "type": "string",
            "maxLength": 2000
          },
          "hold_message": {
            "type": "string",
            "maxLength": 1000
          },
          "enabled": {
            "type": "boolean"
          }
        }
      },
      "AgentNodeFieldPatch": {
        "type": "object",
        "additionalProperties": false,
        "minProperties": 1,
        "description": "Changed fields only from this node's returned schema. title/instruction are available on editable instruction, decision, handover and end steps. routes is offered on decisions and instructions with existing routes; timeout/rules only on human handover. Start and advanced step fields cannot be changed here. A new step requires a non-blank title; a new handover also requires at least one completed rule. Non-text field types and all bounds are checked strictly.",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "instruction": {
            "type": "string",
            "maxLength": 12000
          },
          "response_timeout_secs": {
            "type": "integer",
            "minimum": 5,
            "maximum": 60
          },
          "routes": {
            "type": "array",
            "minItems": 1,
            "maxItems": 20,
            "description": "Complete desired route list; preserves unknown metadata for retained route IDs, removes omitted route edges.",
            "items": {
              "$ref": "#/components/schemas/AgentDecisionRoute"
            }
          },
          "rules": {
            "type": "array",
            "maxItems": 20,
            "description": "Incremental edits/appends; the total saved rule count including protected rules cannot exceed 20.",
            "items": {
              "$ref": "#/components/schemas/AgentTransferRule"
            }
          }
        }
      },
      "AgentFlowPatch": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "account_id",
          "revision",
          "operations"
        ],
        "properties": {
          "account_id": {
            "type": "integer",
            "minimum": 1
          },
          "revision": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$"
          },
          "operations": {
            "type": "array",
            "minItems": 1,
            "maxItems": 25,
            "items": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/AgentUpdateNodeOperation"
                },
                {
                  "$ref": "#/components/schemas/AgentReconnectOperation"
                },
                {
                  "$ref": "#/components/schemas/AgentInsertNodeOperation"
                }
              ]
            }
          }
        }
      },
      "AgentUpdateNodeOperation": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "op",
          "node_id",
          "fields"
        ],
        "properties": {
          "op": {
            "type": "string",
            "const": "update_node"
          },
          "node_id": {
            "type": "string"
          },
          "fields": {
            "$ref": "#/components/schemas/AgentNodeFieldPatch"
          }
        }
      },
      "AgentReconnectOperation": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "op",
          "node_id",
          "port",
          "target_id"
        ],
        "properties": {
          "op": {
            "type": "string",
            "const": "reconnect"
          },
          "node_id": {
            "type": "string"
          },
          "port": {
            "type": "string",
            "description": "An editable output port on node_id",
            "including a newly added decision route.": null
          },
          "target_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Existing node (possibly inserted earlier in this request), or null to disconnect. Self-targets are rejected."
          }
        }
      },
      "AgentInsertNodeOperation": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "op",
          "node_id",
          "kind",
          "fields",
          "after"
        ],
        "properties": {
          "op": {
            "type": "string",
            "const": "insert_node"
          },
          "node_id": {
            "type": "string",
            "pattern": "^mobile_[A-Za-z0-9_-]{8,70}$",
            "description": "Unique client-generated node ID; keep stable across retries."
          },
          "kind": {
            "type": "string",
            "enum": [
              "instruction",
              "decision",
              "transfer",
              "end"
            ],
            "description": "Must be offered in the current insertable catalogue."
          },
          "fields": {
            "$ref": "#/components/schemas/AgentNodeFieldPatch"
          },
          "after": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "node_id",
              "port"
            ],
            "properties": {
              "node_id": {
                "type": "string"
              },
              "port": {
                "type": "string",
                "description": "Existing editable output port to insert after."
              }
            }
          }
        }
      },
      "CompanionAccountCreated": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "minimum": 1
          },
          "name": {
            "type": "string"
          },
          "verified": {
            "type": "boolean"
          },
          "welcome_email": {
            "type": "string",
            "enum": [
              "sent",
              "failed",
              "not_requested"
            ]
          }
        },
        "required": [
          "id",
          "name",
          "verified",
          "welcome_email"
        ]
      },
      "CompanionAccountCreate": {
        "type": "object",
        "required": [
          "name",
          "contact_name",
          "email",
          "parent_account_id",
          "country_id",
          "timezone_id",
          "payment_type_id"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 128,
            "description": "Company name"
          },
          "contact_name": {
            "type": "string",
            "maxLength": 128
          },
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 128
          },
          "phone": {
            "type": "string",
            "maxLength": 22
          },
          "address1": {
            "type": "string",
            "maxLength": 128
          },
          "address2": {
            "type": "string",
            "maxLength": 128
          },
          "address3": {
            "type": "string",
            "maxLength": 45
          },
          "postcode": {
            "type": "string",
            "maxLength": 45
          },
          "country_id": {
            "type": "integer",
            "description": "Choose from the account options country list."
          },
          "timezone_id": {
            "type": "integer",
            "description": "Choose from the account options timezone list."
          },
          "payment_type_id": {
            "type": "integer",
            "enum": [
              1,
              2
            ],
            "description": "1 = postpaid, 2 = prepaid. Review the parent default returned by account options."
          },
          "parent_account_id": {
            "type": "integer",
            "description": "Explicit in-tree parent to create under."
          },
          "company_id": {
            "type": "string",
            "maxLength": 45,
            "description": "Company registration number."
          },
          "is_reseller": {
            "type": "boolean"
          },
          "retention_days": {
            "type": "integer",
            "minimum": 1,
            "maximum": 3650
          },
          "send_welcome": {
            "type": "boolean",
            "default": true,
            "description": "Requires email; sends an account welcome email, not a portal user invitation. False skips the email and marks the new account verified."
          },
          "rate_source": {
            "type": "string",
            "enum": [
              "managed_plan",
              "parent_rates"
            ],
            "default": "managed_plan"
          },
          "rate_plan_version_id": {
            "type": "integer",
            "minimum": 1
          },
          "rate_plan_bundle_ids": {
            "type": "array",
            "items": {
              "type": "integer",
              "minimum": 1
            },
            "minItems": 1,
            "maxItems": 100,
            "uniqueItems": true
          },
          "parent_rate_markup_percent": {
            "type": "string",
            "pattern": "^\\d{1,4}(?:\\.\\d{1,2})?$",
            "default": "10.00",
            "description": "Parent-rate uplift from 0 to 1000 percent, at most two decimal places."
          }
        },
        "additionalProperties": false,
        "description": "Companion account creation uses the canonical portal provisioning transaction. Choose a current published managed plan and nonempty destination bundle set, or explicitly copy the selected parent effective rate card with a reviewed uplift. Currency follows the parent. Prepay creates its wallet and prepay settings. No arbitrary client-supplied prices are accepted.",
        "anyOf": [
          {
            "required": [
              "rate_plan_version_id",
              "rate_plan_bundle_ids"
            ],
            "properties": {
              "rate_source": {
                "enum": [
                  "managed_plan"
                ]
              }
            }
          },
          {
            "required": [
              "rate_source"
            ],
            "properties": {
              "rate_source": {
                "const": "parent_rates"
              }
            }
          }
        ]
      },
      "AccountOptions": {
        "type": "object",
        "properties": {
          "account_name": {
            "type": "string"
          },
          "can_create": {
            "type": "boolean"
          },
          "countries": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "integer",
                  "minimum": 1
                },
                "name": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "code": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "dial_code": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "name",
                "code",
                "dial_code"
              ]
            }
          },
          "timezones": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PeopleChoice"
            }
          },
          "payment_types": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PeopleChoice"
            }
          },
          "defaults": {
            "type": "object",
            "properties": {
              "country_id": {
                "type": "integer",
                "minimum": 1
              },
              "timezone_id": {
                "type": "integer",
                "minimum": 1
              },
              "payment_type_id": {
                "type": "integer",
                "enum": [
                  1,
                  2
                ]
              },
              "retention_days": {
                "type": "integer",
                "minimum": 1,
                "maximum": 3650
              },
              "send_welcome": {
                "type": "boolean"
              }
            }
          },
          "plans": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AccountPlan"
            }
          },
          "parent_rates_available": {
            "type": "boolean"
          },
          "welcome_email_available": {
            "type": "boolean"
          }
        },
        "required": [
          "account_name",
          "can_create",
          "countries",
          "timezones",
          "payment_types",
          "defaults",
          "plans",
          "parent_rates_available",
          "welcome_email_available"
        ]
      },
      "AccountPlan": {
        "type": "object",
        "properties": {
          "version_id": {
            "type": "integer",
            "minimum": 1
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "mechanism": {
            "type": "string",
            "enum": [
              "rated",
              "allowlist"
            ]
          },
          "currency_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "currency_symbol": {
            "type": [
              "string",
              "null"
            ]
          },
          "bundles": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AccountPlanBundle"
            }
          }
        },
        "required": [
          "version_id",
          "name",
          "mechanism",
          "bundles"
        ]
      },
      "AccountPlanBundle": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "minimum": 1
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "direction": {
            "type": "string",
            "enum": [
              "inbound",
              "outbound",
              "both"
            ]
          },
          "default_enabled": {
            "type": "integer",
            "enum": [
              0,
              1
            ]
          },
          "risk_level": {
            "type": "string",
            "enum": [
              "standard",
              "review",
              "restricted"
            ]
          }
        },
        "required": [
          "id",
          "name",
          "default_enabled",
          "risk_level"
        ]
      },
      "UserOptions": {
        "type": "object",
        "properties": {
          "account_name": {
            "type": "string"
          },
          "dial_code": {
            "type": [
              "string",
              "null"
            ]
          },
          "roles": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "user",
                "agent",
                "bot",
                "admin",
                "super_admin"
              ]
            }
          },
          "permissions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PeoplePermission"
            }
          },
          "default_permissions": {
            "type": "array",
            "items": {
              "type": "integer",
              "minimum": 1
            },
            "uniqueItems": true,
            "maxItems": 250
          },
          "invitation_available": {
            "type": "boolean"
          }
        },
        "required": [
          "account_name",
          "roles",
          "permissions",
          "default_permissions",
          "invitation_available"
        ]
      },
      "PeoplePermission": {
        "$ref": "#/components/schemas/PeopleChoice"
      },
      "PeopleChoice": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "minimum": 1
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name"
        ]
      },
      "AudioMetadataRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "account_id",
          "name",
          "revision"
        ],
        "properties": {
          "account_id": {
            "type": "integer",
            "minimum": 1
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "category_id": {
            "type": "integer",
            "minimum": 1,
            "default": 1
          },
          "revision": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$"
          }
        }
      },
      "AudioUploadRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "account_id",
          "name",
          "audio_base64"
        ],
        "properties": {
          "account_id": {
            "type": "integer",
            "minimum": 1
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "category_id": {
            "type": "integer",
            "minimum": 1,
            "default": 1
          },
          "audio_base64": {
            "type": "string",
            "contentEncoding": "base64",
            "maxLength": 6990508
          }
        }
      },
      "AudioLibraryPage": {
        "type": "object",
        "required": [
          "items",
          "page",
          "has_more"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AudioLibraryItem"
            }
          },
          "page": {
            "type": "integer"
          },
          "has_more": {
            "type": "boolean"
          }
        }
      },
      "AudioLibraryItem": {
        "type": "object",
        "required": [
          "id",
          "account_id",
          "name",
          "category_id",
          "category_name",
          "status",
          "owned",
          "shared",
          "revision",
          "can_preview"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "account_id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "category_id": {
            "type": "integer"
          },
          "category_name": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "processing",
              "ready",
              "failed"
            ]
          },
          "owned": {
            "type": "boolean"
          },
          "shared": {
            "type": "boolean"
          },
          "revision": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$"
          },
          "can_preview": {
            "type": "boolean"
          }
        }
      },
      "AgentInsightPage": {
        "type": "object",
        "required": [
          "items",
          "has_more",
          "cursor",
          "filters",
          "summary",
          "trends"
        ],
        "properties": {
          "items": {
            "type": "array",
            "maxItems": 25,
            "items": {
              "$ref": "#/components/schemas/AgentConversation"
            }
          },
          "has_more": {
            "type": "boolean"
          },
          "cursor": {
            "type": [
              "string",
              "null"
            ]
          },
          "filters": {
            "type": "object",
            "required": [
              "date_from",
              "date_to",
              "status",
              "outcome"
            ],
            "properties": {
              "date_from": {
                "type": "string",
                "format": "date"
              },
              "date_to": {
                "type": "string",
                "format": "date"
              },
              "status": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "initiated",
                  "in-progress",
                  "processing",
                  "done",
                  "failed",
                  null
                ]
              },
              "outcome": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "success",
                  "failure",
                  "unknown",
                  "error",
                  null
                ]
              }
            }
          },
          "summary": {
            "$ref": "#/components/schemas/AgentInsightSummary"
          },
          "trends": {
            "type": "array",
            "description": "UTC daily aggregates of returned items only; absent days are not asserted to be zero.",
            "maxItems": 25,
            "items": {
              "type": "object",
              "required": [
                "date",
                "conversations",
                "successes",
                "failures",
                "duration_seconds"
              ],
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "conversations": {
                  "type": "integer",
                  "minimum": 0
                },
                "successes": {
                  "type": "integer",
                  "minimum": 0
                },
                "failures": {
                  "type": "integer",
                  "minimum": 0
                },
                "duration_seconds": {
                  "type": "integer",
                  "minimum": 0,
                  "description": "Sum of known durations only."
                }
              }
            }
          }
        }
      },
      "AgentInsightSummary": {
        "type": "object",
        "description": "All counts and duration sums refer only to items in this response. Do not extrapolate these to all conversations. Missing durations are excluded; average duration divides total_duration_seconds by known_duration_count. Processing state and evaluation outcome are separate dimensions. If showing success rate, divide success_count by success_count + failure_count and state that unknown and error outcomes are excluded. No percentages are estimated.",
        "required": [
          "scope",
          "sample_size",
          "sample_limit",
          "truncated",
          "complete_range",
          "total_duration_seconds",
          "known_duration_count",
          "success_count",
          "failure_count",
          "unknown_count",
          "error_count",
          "completed_count",
          "failed_count",
          "processing_count"
        ],
        "properties": {
          "scope": {
            "type": "string",
            "const": "page"
          },
          "sample_size": {
            "type": "integer",
            "minimum": 0,
            "maximum": 25
          },
          "sample_limit": {
            "type": "integer",
            "const": 25
          },
          "truncated": {
            "type": "boolean",
            "description": "True for later pages, more results, or omitted invalid, duplicate, or mismatched provider rows."
          },
          "complete_range": {
            "type": "boolean",
            "description": "True only for the first page, no more results, and no skipped rows; describes this retrieval, not a frozen report."
          },
          "total_duration_seconds": {
            "type": "integer",
            "minimum": 0
          },
          "known_duration_count": {
            "type": "integer",
            "minimum": 0
          },
          "success_count": {
            "type": "integer",
            "minimum": 0
          },
          "failure_count": {
            "type": "integer",
            "minimum": 0
          },
          "unknown_count": {
            "type": "integer",
            "minimum": 0
          },
          "error_count": {
            "type": "integer",
            "minimum": 0
          },
          "completed_count": {
            "type": "integer",
            "minimum": 0,
            "description": "Conversations with processing status done, regardless of evaluation outcome."
          },
          "failed_count": {
            "type": "integer",
            "minimum": 0,
            "description": "Conversations with processing status failed."
          },
          "processing_count": {
            "type": "integer",
            "minimum": 0,
            "description": "Conversations initiated, in progress, or processing."
          }
        }
      },
      "AgentConversation": {
        "type": "object",
        "required": [
          "id",
          "started_at",
          "duration_seconds",
          "status",
          "outcome",
          "title",
          "summary",
          "language",
          "message_count"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "started_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "UTC start time; null when unavailable. Filtered list rows require a known date."
          },
          "duration_seconds": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Null when provider duration is unavailable; zero is a known zero duration."
          },
          "status": {
            "type": "string",
            "enum": [
              "done",
              "failed",
              "processing",
              "initiated",
              "in-progress",
              "unknown"
            ]
          },
          "outcome": {
            "type": "string",
            "enum": [
              "success",
              "failure",
              "unknown",
              "error"
            ]
          },
          "title": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 300
          },
          "summary": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 20000,
            "description": "Existing provider summary, at most 2000 characters in lists or 20000 in detail. No new AI work is triggered."
          },
          "language": {
            "type": [
              "string",
              "null"
            ]
          },
          "message_count": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Provider message count when available; does not imply every turn is included in the spoken transcript."
          },
          "evaluations": {
            "type": "array",
            "maxItems": 50,
            "description": "Detail only. Stored results for criterion IDs in the currently authorized agent configuration; retired or unknown criteria are omitted.",
            "items": {
              "type": "object",
              "required": [
                "id",
                "label",
                "result",
                "rationale"
              ],
              "properties": {
                "id": {
                  "type": "string",
                  "maxLength": 100
                },
                "label": {
                  "type": "string",
                  "maxLength": 200
                },
                "result": {
                  "type": "string",
                  "enum": [
                    "success",
                    "failure",
                    "unknown",
                    "error"
                  ]
                },
                "rationale": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "maxLength": 2000
                }
              }
            }
          },
          "transcript_truncated": {
            "type": "boolean",
            "description": "Detail only. True if the 2000-turn, 10000-character-per-turn or 300000-total-character limit was reached."
          },
          "transcript": {
            "type": "array",
            "maxItems": 2000,
            "description": "Detail only. Spoken caller and agent text, excluding tool calls, hidden reasoning and system messages.",
            "items": {
              "type": "object",
              "required": [
                "speaker",
                "message",
                "seconds",
                "interrupted",
                "source_medium"
              ],
              "properties": {
                "speaker": {
                  "type": "string",
                  "enum": [
                    "Caller",
                    "Agent"
                  ]
                },
                "message": {
                  "type": "string",
                  "maxLength": 10000
                },
                "seconds": {
                  "type": [
                    "number",
                    "null"
                  ],
                  "minimum": 0,
                  "description": "Elapsed call time; null when unavailable."
                },
                "interrupted": {
                  "type": "boolean"
                },
                "source_medium": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "enum": [
                    "audio",
                    "text",
                    null
                  ]
                }
              }
            }
          }
        }
      },
      "ManagedAgentDocument": {
        "type": "object",
        "required": [
          "id",
          "account_id",
          "name",
          "revision",
          "editable",
          "settings",
          "models",
          "flow",
          "voice_tuning"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "account_id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "revision": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$"
          },
          "editable": {
            "type": "boolean"
          },
          "voice_tuning": {
            "type": "boolean"
          },
          "settings": {
            "$ref": "#/components/schemas/AgentSettings"
          },
          "models": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "provider": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                },
                "capabilities": {
                  "type": "object",
                  "properties": {
                    "temperature": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "flow": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "kind": {
                  "type": "string"
                },
                "enabled": {
                  "type": "boolean"
                },
                "paths": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "to": {
                        "type": "string"
                      },
                      "label": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "ManagedAgentPage": {
        "type": "object",
        "required": [
          "items",
          "page",
          "has_more"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "status": {
                  "type": "string"
                },
                "available": {
                  "type": "boolean"
                }
              }
            }
          },
          "page": {
            "type": "integer"
          },
          "has_more": {
            "type": "boolean"
          }
        }
      },
      "AgentSettings": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "llm": {
            "type": "string",
            "description": "Select from returned models; existing retired models may be retained only."
          },
          "temperature": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "tts_stability": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "tts_similarity": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "tts_speed": {
            "type": "number",
            "minimum": 0.7,
            "maximum": 1.2
          },
          "turn_eagerness": {
            "type": "string",
            "enum": [
              "patient",
              "normal",
              "eager"
            ]
          },
          "turn_timeout": {
            "type": "number",
            "minimum": 1,
            "maximum": 30
          },
          "max_duration": {
            "type": "integer",
            "minimum": 60,
            "maximum": 7200
          }
        }
      },
      "CompanionFlowOverview": {
        "type": "object",
        "required": [
          "id",
          "account_id",
          "name",
          "config_hash",
          "editable",
          "entry",
          "nodes"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "minimum": 1
          },
          "account_id": {
            "type": "integer",
            "minimum": 1
          },
          "name": {
            "type": "string"
          },
          "config_hash": {
            "type": "string"
          },
          "editable": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "entry": {
            "type": "string"
          },
          "nodes": {
            "type": "array",
            "maxItems": 1000,
            "items": {
              "type": "object",
              "required": [
                "id",
                "label",
                "kind",
                "edges"
              ],
              "properties": {
                "id": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "kind": {
                  "type": "string"
                },
                "edges": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "label",
                      "to"
                    ],
                    "properties": {
                      "label": {
                        "type": "string"
                      },
                      "to": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "CompanionIvrMutation": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "account_id",
          "name",
          "menu"
        ],
        "properties": {
          "account_id": {
            "type": "integer",
            "minimum": 1
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "base_config_hash": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$"
          },
          "menu": {
            "$ref": "#/components/schemas/CompanionIvrMenuInput"
          }
        }
      },
      "CompanionIvrDocument": {
        "type": "object",
        "required": [
          "id",
          "account_id",
          "name",
          "service_type",
          "config_hash",
          "menu"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "minimum": 1
          },
          "account_id": {
            "type": "integer",
            "minimum": 1
          },
          "name": {
            "type": "string"
          },
          "service_type": {
            "type": "integer",
            "enum": [
              11
            ]
          },
          "config_hash": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$"
          },
          "timezone": {
            "type": "string",
            "description": "Owning account IANA time zone for new routing schedules."
          },
          "routing_catalog": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EditorModule"
            }
          },
          "menu": {
            "$ref": "#/components/schemas/CompanionIvrMenu"
          }
        }
      },
      "CompanionIvrRoute": {
        "type": "object",
        "required": [
          "id",
          "digit",
          "name",
          "action",
          "has_actions"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "minimum": 1
          },
          "digit": {
            "type": "string",
            "pattern": "^(?:[0-9*#]|t)$"
          },
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "action": {
            "type": "string",
            "description": "linked_service, play_audio, hangup, repeat, submenu, flexible. Existing voicemail/future outcomes may only be retained. Flexible routing uses the branch module catalog and incremental routing changes."
          },
          "target_id": {
            "type": "string",
            "pattern": "^[1-9][0-9]*$"
          },
          "post_action": {
            "type": "string",
            "enum": [
              "return",
              "hangup"
            ]
          },
          "submenu": {
            "$ref": "#/components/schemas/CompanionIvrMenu"
          },
          "routing": {
            "$ref": "#/components/schemas/CompanionIvrRouting"
          },
          "has_actions": {
            "type": "boolean"
          }
        }
      },
      "CompanionIvrMenu": {
        "type": "object",
        "required": [
          "id",
          "greeting_audio_id",
          "timeout_audio_id",
          "max_repeats",
          "routes"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "minimum": 1
          },
          "greeting_audio_id": {
            "type": "string",
            "pattern": "^[1-9][0-9]*$"
          },
          "timeout_audio_id": {
            "type": "string",
            "pattern": "^[0-9]+$"
          },
          "max_repeats": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10
          },
          "routes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CompanionIvrRoute"
            }
          },
          "has_hours": {
            "type": "boolean"
          }
        }
      },
      "CompanionIvrRouteInput": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "digit",
          "name",
          "action"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "minimum": 1
          },
          "digit": {
            "type": "string",
            "pattern": "^(?:[0-9*#]|t)$"
          },
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "action": {
            "type": "string",
            "description": "linked_service, play_audio, hangup, repeat, submenu, flexible. Existing voicemail/future outcomes may only be retained. Flexible routing uses the branch module catalog and incremental routing changes."
          },
          "target_id": {
            "type": "string",
            "pattern": "^[1-9][0-9]*$"
          },
          "post_action": {
            "type": "string",
            "enum": [
              "return",
              "hangup"
            ]
          },
          "submenu": {
            "$ref": "#/components/schemas/CompanionIvrMenuInput"
          },
          "routing": {
            "$ref": "#/components/schemas/CompanionIvrRoutingInput"
          },
          "replace_actions": {
            "type": "boolean",
            "description": "Required true to explicitly replace a key that already contains routing actions or a submenu."
          }
        }
      },
      "CompanionIvrMenuInput": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "greeting_audio_id",
          "max_repeats",
          "routes"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "minimum": 1
          },
          "greeting_audio_id": {
            "type": "string",
            "pattern": "^[1-9][0-9]*$"
          },
          "timeout_audio_id": {
            "type": "string",
            "pattern": "^[0-9]+$"
          },
          "max_repeats": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10
          },
          "routes": {
            "type": "array",
            "minItems": 1,
            "maxItems": 13,
            "items": {
              "$ref": "#/components/schemas/CompanionIvrRouteInput"
            }
          },
          "removed_route_ids": {
            "type": "array",
            "maxItems": 13,
            "uniqueItems": true,
            "items": {
              "type": "integer",
              "minimum": 1
            }
          }
        },
        "description": "Incremental menu document. Existing menu and route IDs must be retained. Deletion requires explicit removed_route_ids. Nested menus have at most five levels. Opaque legacy fields and global opening hours are retained on the server."
      },
      "EditorRevision": {
        "type": "string",
        "pattern": "^[a-f0-9]{64}$",
        "description": "Opaque current configuration revision; never construct it on the client."
      },
      "EditorResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name"
        ]
      },
      "EditorField": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "text",
              "multiline",
              "integer",
              "boolean",
              "choice",
              "resource",
              "resources",
              "target",
              "schedule",
              "timezone",
              "emails",
              "dtmf",
              "phone",
              "date",
              "time",
              "headers",
              "secret"
            ]
          },
          "required": {
            "type": "boolean"
          },
          "default": {},
          "min": {
            "type": "integer"
          },
          "max": {
            "type": "integer"
          },
          "choices": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "resource": {
            "type": "string"
          },
          "redirect": {
            "type": "boolean"
          },
          "custom_voicemail": {
            "type": "boolean"
          },
          "portal_only_value": {
            "type": "string",
            "description": "Delivery choice that requires no external delivery credentials (IVR recording and voicemail)."
          }
        },
        "required": [
          "key",
          "label",
          "type"
        ]
      },
      "EditorModule": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "section": {
            "type": "string"
          },
          "multiple": {
            "type": "boolean"
          },
          "fields": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EditorField"
            }
          }
        },
        "required": [
          "kind",
          "label",
          "section",
          "multiple",
          "fields"
        ]
      },
      "CompanionIvrRouting": {
        "type": "object",
        "required": [
          "editable",
          "strategy",
          "options"
        ],
        "description": "Public controls for native JSON action rows belonging to this keypad option. Unsupported modules stay opaque. Option IDs are opaque integers scoped to this key and config_hash; reload after publishing, since target IDs may change after reordering. Credentials and unknown parameters are never returned.",
        "properties": {
          "editable": {
            "type": "boolean"
          },
          "strategy": {
            "type": "string",
            "enum": [
              "simultaneous",
              "sequential",
              "round_robin",
              "weighted",
              "unsupported"
            ]
          },
          "options": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "id",
                "kind",
                "label",
                "editable",
                "values",
                "configured_secrets"
              ],
              "properties": {
                "id": {
                  "type": "integer",
                  "minimum": 1
                },
                "kind": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "editable": {
                  "type": "boolean"
                },
                "values": {
                  "$ref": "#/components/schemas/EditorValues"
                },
                "configured_secrets": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      },
      "CompanionIvrRoutingInput": {
        "type": "object",
        "additionalProperties": false,
        "description": "Incremental module changes applied atomically with the IVR menu under its existing revision and idempotency preconditions. Required when creating a flexible branch. Omit routing to preserve an existing branch byte for byte. Existing positive option IDs must belong to this key; negative client_id values identify new destinations in destination_order. Keep at least one routing module, which may be voicemail alone. Unknown modules and unsubmitted parameters survive. Use only routing_catalog fields: IVR recording/voicemail delivery type 4 means Portal only. Replacing an existing action subtree still requires replace_actions=true.",
        "properties": {
          "changes": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/EditorChange"
            }
          },
          "strategy": {
            "type": "string",
            "enum": [
              "simultaneous",
              "sequential",
              "round_robin",
              "weighted"
            ]
          },
          "destination_order": {
            "type": "array",
            "maxItems": 500,
            "uniqueItems": true,
            "items": {
              "type": "integer"
            }
          }
        }
      },
      "ServiceEditorCatalog": {
        "type": "object",
        "properties": {
          "timezone": {
            "type": "string"
          },
          "ivr_routing_catalog": {
            "type": "array",
            "description": "Available native IVR branch modules for new keypad services; empty without IVR permission or entitlement.",
            "items": {
              "$ref": "#/components/schemas/EditorModule"
            }
          },
          "service_types": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "integer",
                  "enum": [
                    1,
                    7,
                    11
                  ]
                },
                "name": {
                  "type": "string"
                },
                "catalog": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EditorModule"
                  }
                }
              },
              "required": [
                "id",
                "name",
                "catalog"
              ]
            }
          }
        },
        "required": [
          "timezone",
          "service_types"
        ]
      },
      "EditorValues": {
        "type": "object",
        "description": "Incremental values keyed by the returned module fields. Targets are {type,value}: number (E.164), sip, owned device, agent, address_book, service, audio, ddi; redirect controls also accept voicemail/reject; closed-hours alone accepts custom_voicemail. Schedules are arrays of {day:0..6 (Sunday=0),start:HH:mm,end:HH:mm}, no overlaps. Resource IDs use the exact-account selector. Secret fields are write-only; omit to preserve existing credentials. Null clears an optional field. Arbitrary storage parameters are rejected.",
        "additionalProperties": true
      },
      "EditorChange": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "minimum": 1
          },
          "client_id": {
            "type": "integer",
            "maximum": -1
          },
          "kind": {
            "type": "string"
          },
          "remove": {
            "type": "boolean"
          },
          "values": {
            "$ref": "#/components/schemas/EditorValues"
          }
        },
        "required": [
          "kind"
        ]
      },
      "ServiceEditorDocument": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "account_id": {
            "type": "integer"
          },
          "timezone": {
            "type": "string",
            "description": "Owning account's IANA time zone, used for new schedule controls."
          },
          "account_name": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "service_type": {
            "type": "integer",
            "enum": [
              1,
              7
            ]
          },
          "config_hash": {
            "$ref": "#/components/schemas/EditorRevision"
          },
          "editable": {
            "type": "boolean"
          },
          "strategy": {
            "type": "string",
            "enum": [
              "simultaneous",
              "sequential",
              "round_robin",
              "weighted",
              "unsupported"
            ]
          },
          "options": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "integer"
                },
                "kind": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "editable": {
                  "type": "boolean"
                },
                "values": {
                  "$ref": "#/components/schemas/EditorValues"
                },
                "configured_secrets": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              },
              "required": [
                "id",
                "kind",
                "label",
                "editable",
                "values",
                "configured_secrets"
              ]
            }
          },
          "catalog": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EditorModule"
            }
          }
        },
        "required": [
          "id",
          "account_id",
          "account_name",
          "name",
          "service_type",
          "config_hash",
          "editable",
          "strategy",
          "options",
          "catalog"
        ]
      },
      "AccountManagement": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "contact_name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "dial_code": {
            "type": "string"
          },
          "is_reseller": {
            "type": "boolean"
          },
          "can_delete": {
            "type": "boolean"
          },
          "revision": {
            "$ref": "#/components/schemas/EditorRevision"
          },
          "assets": {
            "type": "object",
            "properties": {
              "numbers": {
                "type": "integer"
              },
              "services": {
                "type": "integer"
              },
              "users": {
                "type": "integer"
              },
              "accounts": {
                "type": "integer"
              },
              "devices": {
                "type": "integer"
              },
              "call_packages": {
                "type": "integer"
              },
              "credit_balances": {
                "type": "integer"
              }
            }
          },
          "verified": {
            "type": "boolean"
          },
          "payment_type": {
            "type": "string",
            "enum": [
              "Prepay",
              "Postpay"
            ]
          },
          "country": {
            "type": [
              "string",
              "null"
            ]
          },
          "timezone": {
            "type": [
              "string",
              "null"
            ]
          },
          "retention_days": {
            "type": "integer"
          }
        },
        "required": [
          "id",
          "name",
          "can_delete",
          "revision",
          "assets"
        ]
      },
      "ServiceEditorPatch": {
        "type": "object",
        "properties": {
          "account_id": {
            "type": "integer",
            "minimum": 1
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "changes": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/EditorChange"
            }
          },
          "strategy": {
            "type": "string",
            "enum": [
              "simultaneous",
              "sequential",
              "round_robin",
              "weighted"
            ]
          },
          "destination_order": {
            "type": "array",
            "maxItems": 500,
            "items": {
              "type": "integer"
            }
          },
          "base_config_hash": {
            "$ref": "#/components/schemas/EditorRevision"
          }
        },
        "required": [
          "account_id"
        ],
        "additionalProperties": false
      },
      "ServiceEditorCreate": {
        "type": "object",
        "properties": {
          "account_id": {
            "type": "integer",
            "minimum": 1
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "changes": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/EditorChange"
            }
          },
          "strategy": {
            "type": "string",
            "enum": [
              "simultaneous",
              "sequential",
              "round_robin",
              "weighted"
            ]
          },
          "destination_order": {
            "type": "array",
            "maxItems": 500,
            "items": {
              "type": "integer"
            }
          },
          "base_config_hash": {
            "$ref": "#/components/schemas/EditorRevision"
          },
          "service_type": {
            "type": "integer",
            "enum": [
              1,
              7
            ]
          }
        },
        "required": [
          "account_id",
          "name",
          "service_type",
          "changes"
        ],
        "additionalProperties": false
      },
      "RoutingListEntryCreate": {
        "oneOf": [
          {
            "type": "object",
            "required": [
              "number"
            ],
            "additionalProperties": false,
            "properties": {
              "number": {
                "type": "string",
                "maxLength": 32
              }
            }
          },
          {
            "type": "object",
            "required": [
              "area"
            ],
            "additionalProperties": false,
            "properties": {
              "area": {
                "type": "string",
                "maxLength": 32
              }
            }
          },
          {
            "type": "object",
            "required": [
              "ip"
            ],
            "additionalProperties": false,
            "properties": {
              "ip": {
                "type": "string",
                "maxLength": 32
              }
            }
          },
          {
            "type": "object",
            "required": [
              "start_date",
              "end_date"
            ],
            "additionalProperties": false,
            "properties": {
              "name": {
                "type": "string",
                "maxLength": 128
              },
              "start_date": {
                "type": "string",
                "format": "date-time"
              },
              "end_date": {
                "type": "string",
                "format": "date-time"
              }
            }
          }
        ]
      },
      "ConfigHash": {
        "type": "string",
        "pattern": "^[a-f0-9]{64}$",
        "description": "SHA256 of full live service state, shared with the portal. Not a hash of only the public summary."
      },
      "ApiIdentity": {
        "type": "object",
        "required": [
          "account",
          "user",
          "token"
        ],
        "properties": {
          "account": {
            "type": "object",
            "required": [
              "id",
              "name"
            ],
            "properties": {
              "id": {
                "type": "integer"
              },
              "name": {
                "type": "string"
              },
              "dial_code": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Account country dial code, e.g. +44. Presentation only."
              }
            }
          },
          "user": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "type": "object",
                "required": [
                  "id",
                  "name",
                  "role",
                  "read_only"
                ],
                "properties": {
                  "id": {
                    "type": "integer"
                  },
                  "name": {
                    "type": "string"
                  },
                  "avatar_url": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "uri",
                    "description": "Saved portal HTTPS profile photo. Never send API credentials to this URL."
                  },
                  "role": {
                    "type": "string",
                    "enum": [
                      "admin",
                      "super_admin",
                      "user",
                      "agent"
                    ]
                  },
                  "read_only": {
                    "type": "boolean",
                    "description": "The token owner's portal view-only setting, not the estate-wide release guard. See GET /capabilities data.read_only."
                  }
                }
              }
            ]
          },
          "token": {
            "type": "object",
            "required": [
              "id",
              "name",
              "scopes",
              "expires_at"
            ],
            "properties": {
              "id": {
                "type": "integer"
              },
              "name": {
                "type": "string"
              },
              "scopes": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "expires_at": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              }
            }
          }
        }
      },
      "EstateCapabilities": {
        "type": "object",
        "required": [
          "api_version",
          "release",
          "read_only",
          "estate",
          "features",
          "links"
        ],
        "properties": {
          "api_version": {
            "type": "string",
            "const": "v1"
          },
          "release": {
            "type": "string"
          },
          "read_only": {
            "type": "boolean",
            "default": true,
            "description": "Effective release access for this caller. False may reflect conference integration access alone and does not grant provisioning. Individual features, token scopes and owner restrictions still apply. The default-on global estate read-only guard blocks every unsafe method with 403 api_read_only, even with write-scoped tokens."
          },
          "estate": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            }
          },
          "features": {
            "type": "object",
            "required": [
              "account_writes",
              "user_writes",
              "number_writes",
              "number_allocation",
              "number_release",
              "service_writes",
              "conference_control",
              "reports",
              "media_reads",
              "audio_downloads",
              "recording_downloads",
              "user_invitations",
              "media_uploads",
              "media_writes",
              "agent_management",
              "agent_writes",
              "caller_blocking"
            ],
            "properties": {
              "caller_blocking": {
                "type": "boolean",
                "description": "CallPlatform app sessions only. Adding one caller number to an existing acl block list (POST /lists/acl/{id}/entries). Follows service_writes; false while read_only is true and for integration tokens. Changes live routing."
              },
              "user_writes": {
                "type": "boolean",
                "description": "User creation, reviewed identity/permission editing and removal; false while read-only. Current administrator role ordering and page permissions still apply."
              },
              "account_writes": {
                "type": "boolean",
                "description": "Effective estate account-write switch; false while read_only is true. Token scopes still apply."
              },
              "number_writes": {
                "type": "boolean",
                "description": "Effective scheduled number cancellation switch; false while read_only is true. Does not enable checkout or immediate release."
              },
              "number_allocation": {
                "type": "boolean",
                "const": false
              },
              "number_release": {
                "type": "boolean",
                "const": false
              },
              "service_writes": {
                "type": "boolean",
                "description": "Effective estate service/routing-write switch; false while read_only is true."
              },
              "conference_control": {
                "type": "boolean",
                "description": "Effective conference gate for this estate and caller; requires conferences:write, current owner permissions and configured call-state, executor credential and host allowlist. False while read_only is true, including POST list requests. Independent of partner provisioning approval. Does not probe runtime health or prove live acceptance."
              },
              "reports": {
                "type": "boolean"
              },
              "active_calls_overview": {
                "type": "boolean",
                "default": false,
                "description": "Effective estate overview gate with reports:read and current companion Live Stats permission. False or absent retains the exact-account snapshot fallback."
              },
              "active_calls_descendants": {
                "type": "boolean",
                "default": false,
                "description": "Overview is enabled and this bound administrator has effective accounts:read, reports:read and current Live Stats permission. Every selected child account is independently authorised server-side."
              },
              "active_calls": {
                "type": "boolean",
                "description": "Live Stats permission allows read-only SBC connection snapshots."
              },
              "media_reads": {
                "type": "boolean",
                "default": false,
                "description": "Independent estate media gate. False blocks all /media/* and /audio requests with 403 feature_unavailable, including metadata and transcripts. True is configuration, not proof of private storage or media readiness."
              },
              "audio_downloads": {
                "type": "boolean",
                "description": "True only when media_reads is enabled and an audio bucket is configured; individual downloads still verify ownership and object readiness."
              },
              "recording_downloads": {
                "type": "boolean",
                "description": "True only when media_reads is enabled and a recording bucket is configured; individual downloads still verify ownership and object readiness."
              },
              "user_invitations": {
                "type": "boolean",
                "description": "Current companion user invitation availability through the portal mailer."
              },
              "media_uploads": {
                "type": "boolean",
                "description": "Current companion audio recording/import availability."
              },
              "media_writes": {
                "type": "boolean",
                "description": "Companion audio library mutations. False while the estate is read-only; current media:write and portal permission still apply."
              },
              "agent_management": {
                "type": "boolean",
                "description": "Account-owned AI settings and insight reads through the portal provider bridge."
              },
              "agent_writes": {
                "type": "boolean",
                "description": "Reviewed existing AI agent settings changes; false while read-only."
              }
            }
          },
          "links": {
            "type": "object",
            "properties": {
              "documentation": {
                "type": "string"
              },
              "openapi": {
                "type": "string"
              }
            }
          }
        }
      },
      "MediaDownload": {
        "type": "object",
        "required": [
          "url",
          "expires_at",
          "method",
          "content_type",
          "size_bytes",
          "disposition"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Sensitive short-lived URL. Do not log, share or cache it."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "method": {
            "type": "string",
            "const": "GET"
          },
          "content_type": {
            "type": "string",
            "enum": [
              "audio/wav",
              "audio/mpeg",
              "audio/ogg",
              "audio/mp4",
              "audio/flac"
            ]
          },
          "size_bytes": {
            "type": "integer",
            "minimum": 1
          },
          "disposition": {
            "type": "string",
            "enum": [
              "attachment",
              "inline"
            ]
          }
        }
      },
      "RecordingMetadata": {
        "type": "object",
        "required": [
          "id",
          "call_id",
          "account_id",
          "service_id",
          "number_id",
          "caller",
          "destination",
          "created_at",
          "media_type",
          "has_recording"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "call_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "account_id": {
            "type": "integer"
          },
          "service_id": {
            "type": "integer"
          },
          "number_id": {
            "type": "integer"
          },
          "caller": {
            "type": [
              "string",
              "null"
            ]
          },
          "destination": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "media_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "has_recording": {
            "type": "boolean",
            "description": "A recording locator is stored. The download operation still checks current object existence/readiness and can return 404 after retention."
          }
        }
      },
      "RecordingDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/RecordingMetadata"
          },
          {
            "type": "object",
            "properties": {
              "transcript": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "summary": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "transcript",
              "summary"
            ]
          }
        ]
      },
      "RecordingPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/RecordingMetadata"
            }
          },
          "meta": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "minimum": 1,
                "maximum": 1000
              },
              "per_page": {
                "type": "integer",
                "minimum": 1,
                "maximum": 100
              },
              "has_more": {
                "type": "boolean"
              },
              "timezone": {
                "type": "string",
                "description": "IANA timezone of the start_date/end_date calendar days (the request's, else UTC)."
              },
              "start_date": {
                "type": "string",
                "format": "date"
              },
              "end_date": {
                "type": "string",
                "format": "date"
              }
            },
            "required": [
              "page",
              "per_page",
              "has_more",
              "timezone",
              "start_date",
              "end_date"
            ]
          }
        },
        "required": [
          "data",
          "meta"
        ]
      },
      "User": {
        "type": "object",
        "required": [
          "id",
          "account_id",
          "email",
          "firstname",
          "lastname",
          "role",
          "enabled",
          "verified",
          "created_at"
        ],
        "properties": {
          "revision": {
            "$ref": "#/components/schemas/EditorRevision"
          },
          "id": {
            "type": "integer",
            "minimum": 0
          },
          "account_id": {
            "type": "integer",
            "minimum": 0
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "firstname": {
            "type": "string"
          },
          "lastname": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "enum": [
              "super_admin",
              "admin",
              "user",
              "agent",
              "bot"
            ]
          },
          "enabled": {
            "type": "boolean"
          },
          "verified": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "description": "Portal creation timestamp (YYYY-MM-DD HH:mm:ss).",
            "examples": [
              "2026-09-06 10:00:00"
            ]
          },
          "phone": {
            "type": [
              "string",
              "null"
            ]
          },
          "can_edit": {
            "type": "boolean"
          },
          "permissions": {
            "type": "array",
            "items": {
              "type": "integer",
              "minimum": 1
            },
            "uniqueItems": true,
            "maxItems": 250
          },
          "account_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Present on the user detail response."
          },
          "invitation_email": {
            "type": "string",
            "enum": [
              "sent",
              "failed",
              "not_requested"
            ],
            "description": "Present after user creation. No verification token is returned."
          }
        }
      },
      "UserCreate": {
        "type": "object",
        "required": [
          "email"
        ],
        "properties": {
          "account_id": {
            "type": "integer",
            "minimum": 1
          },
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 64
          },
          "firstname": {
            "type": "string",
            "maxLength": 45
          },
          "lastname": {
            "type": "string",
            "maxLength": 45
          },
          "phone": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 45
          },
          "role": {
            "type": "string",
            "enum": [
              "user",
              "agent",
              "bot",
              "admin",
              "super_admin"
            ],
            "description": "Integration tokens: user, agent or bot. Companion administrators: roles at or below their current portal role."
          },
          "password": {
            "type": "string",
            "minLength": 12,
            "maxLength": 72,
            "writeOnly": true,
            "description": "12–72 characters and at most 72 UTF-8 bytes; NUL bytes are not accepted."
          },
          "send_invite": {
            "type": "boolean",
            "default": false,
            "description": "Companion-only invitation. Requires estate user writes and configured portal bridge. A random password is stored and verified remains false until the recipient follows the 24-hour activation email and chooses a password."
          },
          "permissions": {
            "type": "array",
            "items": {
              "type": "integer",
              "minimum": 1
            },
            "uniqueItems": true,
            "maxItems": 250,
            "description": "Companion administrator only. Replacement page-permission IDs must all be currently grantable by the actor. Omit to use the portal baseline intersected with the companion actor's grantable permissions; integration tokens retain the portal baseline."
          },
          "enabled": {
            "type": "boolean",
            "default": true
          }
        },
        "anyOf": [
          {
            "required": [
              "password"
            ]
          },
          {
            "required": [
              "send_invite"
            ],
            "properties": {
              "send_invite": {
                "const": true
              }
            }
          }
        ]
      },
      "UserUpdate": {
        "type": "object",
        "properties": {
          "firstname": {
            "type": "string",
            "maxLength": 45
          },
          "lastname": {
            "type": "string",
            "maxLength": 45
          },
          "phone": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 45
          },
          "role": {
            "type": "string",
            "enum": [
              "user",
              "agent",
              "bot",
              "admin",
              "super_admin"
            ],
            "description": "Integration tokens: user, agent or bot. Companion administrators: roles at or below their current portal role."
          },
          "password": {
            "type": "string",
            "minLength": 12,
            "maxLength": 72,
            "writeOnly": true,
            "description": "12–72 characters and at most 72 UTF-8 bytes; NUL bytes are not accepted."
          },
          "enabled": {
            "type": "boolean"
          },
          "account_id": {
            "type": "integer",
            "minimum": 1,
            "description": "Required for companion sessions; must be the user current account."
          },
          "revision": {
            "$ref": "#/components/schemas/EditorRevision"
          },
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 64
          },
          "permissions": {
            "type": "array",
            "items": {
              "type": "integer",
              "minimum": 1
            },
            "uniqueItems": true,
            "maxItems": 250,
            "description": "Companion administrator only. Replacement page-permission IDs must all be currently grantable by the actor. Omit to preserve the user's current permissions."
          }
        },
        "minProperties": 1,
        "description": "Companion edits require account_id and revision. Fields omitted remain unchanged. Administrator role/permission rules are rechecked on the locked target; integration administrator-role restrictions remain unchanged."
      },
      "NumberCancellationRequest": {
        "type": "object",
        "required": [
          "account_id"
        ],
        "properties": {
          "account_id": {
            "type": "integer",
            "minimum": 1
          },
          "mode": {
            "type": "string",
            "enum": [
              "scheduled"
            ],
            "default": "scheduled"
          },
          "reason": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 255
          }
        }
      },
      "NumberCancellation": {
        "type": "object",
        "required": [
          "number_id",
          "status",
          "effective_date"
        ],
        "properties": {
          "number_id": {
            "type": "integer",
            "minimum": 0
          },
          "status": {
            "type": "string",
            "enum": [
              "cancellation_requested",
              "already_requested"
            ]
          },
          "effective_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "New requests have a date. A legacy pending request may have no stored date; resolve that inconsistency in the portal."
          }
        }
      },
      "ResourceNameUpdate": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 64
          }
        }
      },
      "RoutingListEntryWrite": {
        "anyOf": [
          {
            "type": "object",
            "properties": {
              "number": {
                "type": "string",
                "maxLength": 32
              }
            }
          },
          {
            "type": "object",
            "properties": {
              "area": {
                "type": "string",
                "maxLength": 32
              }
            }
          },
          {
            "type": "object",
            "properties": {
              "ip": {
                "type": "string",
                "maxLength": 32
              }
            }
          },
          {
            "type": "object",
            "properties": {
              "name": {
                "type": "string",
                "maxLength": 128
              },
              "start_date": {
                "type": "string",
                "format": "date-time"
              },
              "end_date": {
                "type": "string",
                "format": "date-time"
              }
            }
          }
        ],
        "description": "Use fields for the path type. On create acl/abr/ip require their single field; dex requires both dates. On PATCH provide at least one field."
      },
      "RoutingListEntry": {
        "allOf": [
          {
            "$ref": "#/components/schemas/RoutingListEntryWrite"
          },
          {
            "type": "object",
            "required": [
              "id"
            ],
            "properties": {
              "id": {
                "type": "integer",
                "minimum": 0
              }
            }
          }
        ]
      },
      "AddressBookEntryWrite": {
        "type": "object",
        "properties": {
          "target": {
            "type": "string",
            "maxLength": 255
          },
          "description": {
            "type": "string",
            "maxLength": 255
          },
          "schedule": {
            "type": "string",
            "maxLength": 512,
            "description": "Portal schedule string. Default is every day 00:00–23:59 enabled; e.g. 0,00:00,23:59,1;...;6,00:00,23:59,1"
          }
        },
        "description": "target required on POST, optional on PATCH."
      },
      "AddressBookEntry": {
        "type": "object",
        "required": [
          "id",
          "target",
          "target_type",
          "description",
          "schedule"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "minimum": 0
          },
          "target": {
            "type": "string"
          },
          "target_type": {
            "type": "string",
            "enum": [
              "sip",
              "number"
            ]
          },
          "description": {
            "type": "string"
          },
          "schedule": {
            "type": "string"
          }
        }
      },
      "CallReportRow": {
        "type": "object",
        "required": [
          "id",
          "call_id",
          "parent_call_id",
          "direction",
          "started_at",
          "caller",
          "destination",
          "duration_seconds",
          "status",
          "sip_code",
          "service_name"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[0-9]+$",
            "description": "CDR UInt64 represented as string to preserve precision in clients."
          },
          "call_id": {
            "type": "string",
            "description": "This leg's received SIP Call-ID. Distinct from the CDR id and recording id."
          },
          "parent_call_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Verified inbound parent SIP Call-ID for an outbound leg, matched within the same account by X-CID to SIP Call-ID or FreeSWITCH UUID. If X-CID is absent, an exact shared SIP Call-ID may match. Null for inbound, missing or ambiguous parents, or an older reporting gateway. Parent lookup includes seven days before the report start date."
          },
          "direction": {
            "type": "string",
            "enum": [
              "inbound",
              "outbound"
            ]
          },
          "started_at": {
            "type": "string",
            "format": "date-time",
            "description": "UTC"
          },
          "caller": {
            "type": "string"
          },
          "destination": {
            "type": "string"
          },
          "duration_seconds": {
            "type": "integer",
            "minimum": 0
          },
          "status": {
            "type": "string",
            "description": "Status label from the estate portal call log."
          },
          "sip_code": {
            "type": "integer",
            "minimum": 0
          },
          "service_name": {
            "type": "string"
          },
          "media": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/CallMediaAvailability"
              }
            ],
            "description": "With an explicit account filter, enabled media and media:read, identifies available media on this leg or its verified parent. A leg's own available media takes precedence. The id can be used directly with /media/recordings/{recording_id}/download. Otherwise null."
          }
        },
        "additionalProperties": false
      },
      "ReportMeta": {
        "type": "object",
        "required": [
          "direction",
          "start_date",
          "end_date",
          "timezone"
        ],
        "properties": {
          "direction": {
            "type": "string",
            "enum": [
              "inbound",
              "outbound"
            ]
          },
          "start_date": {
            "type": "string",
            "format": "date"
          },
          "end_date": {
            "type": "string",
            "format": "date"
          },
          "timezone": {
            "type": "string",
            "description": "IANA timezone of the start_date/end_date calendar days (the request's, else UTC)."
          }
        }
      },
      "CallReportPage": {
        "type": "object",
        "required": [
          "data",
          "meta"
        ],
        "properties": {
          "data": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/CallReportRow"
            }
          },
          "meta": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ReportMeta"
              },
              {
                "type": "object",
                "required": [
                  "page",
                  "per_page",
                  "has_more"
                ],
                "properties": {
                  "page": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "per_page": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100
                  },
                  "has_more": {
                    "type": "boolean"
                  }
                }
              }
            ]
          }
        }
      },
      "CallReportSummary": {
        "type": "object",
        "required": [
          "data",
          "meta"
        ],
        "properties": {
          "data": {
            "type": "object",
            "required": [
              "total_calls",
              "total_duration_seconds",
              "statuses"
            ],
            "properties": {
              "total_calls": {
                "type": "integer",
                "minimum": 0
              },
              "total_duration_seconds": {
                "type": "integer",
                "minimum": 0
              },
              "groups": {
                "type": "array",
                "description": "Present only when group_by was explicitly requested.",
                "items": {
                  "type": "object",
                  "required": [
                    "key",
                    "label",
                    "calls",
                    "duration_seconds"
                  ],
                  "properties": {
                    "key": {
                      "type": "string"
                    },
                    "label": {
                      "type": "string"
                    },
                    "calls": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "duration_seconds": {
                      "type": "integer",
                      "minimum": 0
                    }
                  }
                }
              },
              "statuses": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "status",
                    "calls",
                    "duration_seconds"
                  ],
                  "properties": {
                    "status": {
                      "type": "string"
                    },
                    "calls": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "duration_seconds": {
                      "type": "integer",
                      "minimum": 0
                    }
                  }
                }
              }
            }
          },
          "meta": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ReportMeta"
              },
              {
                "type": "object",
                "properties": {
                  "group_by": {
                    "type": "string",
                    "enum": [
                      "service",
                      "number",
                      "status"
                    ]
                  }
                }
              }
            ]
          }
        }
      },
      "Account": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "dial_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "Country dial code for local display and input"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AccountCreate": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100,
            "description": "Company name"
          },
          "contact_name": {
            "type": "string",
            "maxLength": 100
          },
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 255
          },
          "phone": {
            "type": "string",
            "maxLength": 50
          },
          "address1": {
            "type": "string",
            "maxLength": 255
          },
          "address2": {
            "type": "string",
            "maxLength": 255
          },
          "address3": {
            "type": "string",
            "maxLength": 255
          },
          "postcode": {
            "type": "string",
            "maxLength": 32
          },
          "country_id": {
            "type": "integer",
            "description": "Defaults to the parent's country"
          },
          "timezone_id": {
            "type": "integer",
            "description": "Defaults to the parent's timezone"
          },
          "payment_type_id": {
            "type": "integer",
            "enum": [
              1,
              2
            ],
            "description": "1 = postpaid, 2 = prepaid. Defaults to the parent."
          },
          "parent_account_id": {
            "type": "integer",
            "description": "In-tree parent to create under (defaults to your own account)"
          },
          "company_id": {
            "type": "string",
            "maxLength": 45,
            "description": "Company registration number."
          },
          "is_reseller": {
            "type": "boolean"
          },
          "retention_days": {
            "type": "integer",
            "minimum": 1,
            "maximum": 3650
          },
          "send_welcome": {
            "type": "boolean",
            "description": "Requires email; sends an account welcome email",
            "not a portal user invitation.": null
          }
        }
      },
      "AccountUpdate": {
        "type": "object",
        "description": "At least one field must be supplied.",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "contact_name": {
            "type": "string",
            "maxLength": 100
          },
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 255
          },
          "phone": {
            "type": "string",
            "maxLength": 50
          },
          "address1": {
            "type": "string",
            "maxLength": 255
          },
          "address2": {
            "type": "string",
            "maxLength": 255
          },
          "address3": {
            "type": "string",
            "maxLength": 255
          },
          "postcode": {
            "type": "string",
            "maxLength": 32
          },
          "country_id": {
            "type": "integer"
          },
          "timezone_id": {
            "type": "integer"
          },
          "payment_type_id": {
            "type": "integer",
            "enum": [
              1,
              2
            ]
          }
        }
      },
      "AvailableNumber": {
        "type": "object",
        "required": [
          "id",
          "number",
          "country",
          "grade",
          "monthly_cost",
          "currency",
          "pricing_status"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "number": {
            "type": "string",
            "description": "E.164 format, e.g. +442031234567"
          },
          "country": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO 3166-1 alpha-2; null for missing legacy lookup."
          },
          "grade": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "platinum",
              "gold",
              "silver",
              "bronze",
              null
            ]
          },
          "monthly_cost": {
            "type": "null",
            "description": "No monthly quote is calculated by this discovery endpoint. Use portal checkout."
          },
          "pricing_status": {
            "type": "string",
            "const": "quote_required"
          },
          "currency": {
            "type": [
              "string",
              "null"
            ],
            "description": "Actual account currency; null if not configured."
          }
        }
      },
      "Number": {
        "type": "object",
        "required": [
          "id",
          "allocation_id",
          "number",
          "country",
          "grade",
          "account_id",
          "description",
          "status_id",
          "presentation",
          "test_mode",
          "service_id",
          "service_status",
          "monthly_cost",
          "rental_status",
          "currency",
          "allocated_at",
          "cancellation"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "allocation_id": {
            "type": "integer"
          },
          "number": {
            "type": "string",
            "description": "E.164 format"
          },
          "country": {
            "type": [
              "string",
              "null"
            ]
          },
          "grade": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "platinum",
              "gold",
              "silver",
              "bronze",
              null
            ]
          },
          "account_id": {
            "type": "integer"
          },
          "description": {
            "type": "string"
          },
          "status_id": {
            "type": "integer",
            "description": "Inventory status from the estate."
          },
          "presentation": {
            "type": "boolean"
          },
          "test_mode": {
            "type": "boolean"
          },
          "service_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Inbound service this number is attached to, if any"
          },
          "service_status": {
            "type": "string",
            "enum": [
              "unassigned",
              "assigned",
              "conflict"
            ]
          },
          "monthly_cost": {
            "type": [
              "string",
              "null"
            ],
            "description": "Actual single-quantity recurring rental snapshot; null when missing or ambiguous. Never a grade/setup price."
          },
          "rental_status": {
            "type": "string",
            "enum": [
              "active",
              "missing",
              "ambiguous"
            ]
          },
          "currency": {
            "type": [
              "string",
              "null"
            ],
            "description": "Actual account currency; no guessed GBP fallback."
          },
          "allocated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "cancellation": {
            "type": "object",
            "required": [
              "status",
              "requested_at",
              "effective_date"
            ],
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "none",
                  "scheduled",
                  "processed"
                ]
              },
              "requested_at": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "effective_date": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date"
              }
            }
          }
        }
      },
      "AudioFile": {
        "type": "object",
        "required": [
          "id",
          "name",
          "kind",
          "format",
          "processed",
          "account_id",
          "created_at"
        ],
        "description": "An audio file you can reference by `id` (as `audio_id`) when building services.",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Use this value as `audio_id` in a service configuration."
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Friendly name shown in the portal."
          },
          "kind": {
            "type": "string",
            "enum": [
              "upload",
              "text_to_speech"
            ],
            "description": "`upload` = an uploaded recording; `text_to_speech` = generated from text."
          },
          "format": {
            "type": "string",
            "description": "Original catalogue MIME type; the processed playback file is WAV."
          },
          "processed": {
            "type": "boolean",
            "description": "Portal processing completed. The download endpoint separately verifies the retained object is available."
          },
          "account_id": {
            "type": "integer",
            "description": "The account that owns the file."
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "Agent": {
        "type": "object",
        "description": "An AI agent you can attach as a destination (use `id` as `ai_agent_id`).",
        "properties": {
          "id": {
            "type": "string",
            "description": "The agent id — pass as `ai_agent_id`."
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": [
              "string",
              "null"
            ],
            "description": "The agent's lifecycle status."
          },
          "account_id": {
            "type": "integer"
          }
        }
      },
      "RoutingList": {
        "type": "object",
        "description": "A routing list referenced by `list_id`.",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Use as `list_id` / `area_list_id` in a service configuration."
          },
          "name": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "acl",
              "abr",
              "dex",
              "ip"
            ],
            "description": "acl = number allow/block, abr = area/prefix, dex = date, ip = IP list."
          },
          "account_id": {
            "type": "integer"
          },
          "mode": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "deny",
              "allow",
              "anon",
              null
            ],
            "description": "acl lists only: deny (Black List), allow (White List) or anon (Anonymous Block List). Reported where the estate enables caller blocking; otherwise null, as for other list kinds and acl types."
          }
        }
      },
      "AddressBookContact": {
        "type": "object",
        "description": "An address-book contact referenced by `address_book_id`.",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Use as `address_book_id` in a service configuration."
          },
          "name": {
            "type": "string"
          },
          "account_id": {
            "type": "integer"
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "ListCreate": {
        "type": "object",
        "required": [
          "account_id",
          "type",
          "name"
        ],
        "description": "Create a routing list (optionally with entries).",
        "properties": {
          "account_id": {
            "type": "integer",
            "description": "The account that will own the list."
          },
          "type": {
            "type": "string",
            "enum": [
              "acl",
              "abr",
              "dex",
              "ip"
            ],
            "description": "List kind."
          },
          "name": {
            "type": "string",
            "maxLength": 64
          },
          "mode": {
            "type": "string",
            "enum": [
              "deny",
              "allow",
              "anon"
            ],
            "default": "deny",
            "description": "Caller-list behaviour, as the portal's list types: deny = Black List (matching callers take the service's list action), allow = White List (only matching callers pass), anon = Anonymous Block List."
          },
          "entries": {
            "type": "array",
            "maxItems": 500,
            "description": "Type-specific objects only; unknown fields and duplicate unique values are rejected.",
            "items": {
              "$ref": "#/components/schemas/RoutingListEntryCreate"
            }
          }
        }
      },
      "AddressBookCreate": {
        "type": "object",
        "required": [
          "account_id",
          "name"
        ],
        "description": "Create an address-book contact (optionally with destinations).",
        "properties": {
          "account_id": {
            "type": "integer"
          },
          "name": {
            "type": "string",
            "maxLength": 64
          },
          "destinations": {
            "type": "array",
            "description": "Optional destinations. `target_type` is derived from `target` (SIP if it contains `@`, else a phone number).",
            "items": {
              "type": "object",
              "required": [
                "target"
              ],
              "properties": {
                "target": {
                  "type": "string",
                  "maxLength": 255,
                  "description": "Phone number (E.164) or SIP URI (user@host)."
                },
                "description": {
                  "type": "string",
                  "maxLength": 255
                }
              }
            }
          }
        }
      },
      "InboundServiceCreate": {
        "type": "object",
        "required": [
          "account_id",
          "name",
          "route"
        ],
        "description": "The full inbound service configuration to create.",
        "properties": {
          "account_id": {
            "type": "integer",
            "description": "The account that will own the service. Must be your own account or one of your sub-accounts."
          },
          "name": {
            "type": "string",
            "maxLength": 100,
            "description": "A friendly name for the service, shown in your portal."
          },
          "service_type": {
            "type": "integer",
            "default": 1,
            "description": "The kind of service to create, as listed by `GET /v1/services/capabilities`.\nDefaults to standard inbound flexible routing (`1`). The chosen type\nmust be enabled for the target account. Audio Conference (`2`), IVR\n(`11`), Flow Builder (`13`) and Advanced ABR (`14`) use their own\nrequest shapes — see the other request schemas.\n"
          },
          "route": {
            "$ref": "#/components/schemas/Route"
          },
          "time_of_day": {
            "$ref": "#/components/schemas/TimeOfDay"
          },
          "anonymous_cli": {
            "$ref": "#/components/schemas/AnonymousCli"
          },
          "firewall": {
            "$ref": "#/components/schemas/Firewall"
          },
          "acl": {
            "$ref": "#/components/schemas/Acl"
          },
          "area_routing": {
            "$ref": "#/components/schemas/AreaRouting"
          },
          "date_routing": {
            "$ref": "#/components/schemas/DateRouting"
          },
          "ip_routing": {
            "$ref": "#/components/schemas/IpRouting"
          },
          "recording": {
            "$ref": "#/components/schemas/Recording"
          },
          "fax": {
            "$ref": "#/components/schemas/Fax"
          },
          "caller_id": {
            "$ref": "#/components/schemas/CallerId"
          },
          "conference": {
            "$ref": "#/components/schemas/Conference"
          },
          "cli_masking": {
            "$ref": "#/components/schemas/CliMasking"
          },
          "preconnection_audio": {
            "$ref": "#/components/schemas/PreconnectionAudio"
          },
          "whisper": {
            "$ref": "#/components/schemas/Whisper"
          },
          "post_call": {
            "$ref": "#/components/schemas/PostCall"
          },
          "queue": {
            "$ref": "#/components/schemas/Queue"
          },
          "audio_player": {
            "$ref": "#/components/schemas/AudioPlayer"
          },
          "mid_call_transfer": {
            "$ref": "#/components/schemas/MidCallTransfer"
          },
          "missed_call_alert": {
            "$ref": "#/components/schemas/MissedCallAlert"
          },
          "custom_sip_headers": {
            "$ref": "#/components/schemas/CustomSipHeaders"
          },
          "header_rewrites": {
            "$ref": "#/components/schemas/HeaderRewrites"
          },
          "voicemail": {
            "$ref": "#/components/schemas/Voicemail"
          },
          "failover": {
            "$ref": "#/components/schemas/Target"
          }
        }
      },
      "ConferenceServiceCreate": {
        "type": "object",
        "required": [
          "account_id",
          "name",
          "service_type",
          "conference"
        ],
        "description": "An Audio Conference service (service_type 2). Callers dial in and join a\nconference bridge — the bridge itself is the destination, so no `route`\nis used. Guests and the moderator authenticate with PINs, the bridge can\ndial out to bring participants in, and the conference can be recorded\n(with an optional AI summary of the recording). Attach dial-in numbers\nafterwards with `POST /v1/services/{id}/numbers`.\n",
        "example": {
          "account_id": 2,
          "name": "Team Bridge",
          "service_type": 2,
          "conference": {
            "guest_pins": "246810",
            "moderator_pin": "13579",
            "max_participants": 20,
            "record": {
              "enabled": true,
              "delivery": {
                "type": "email",
                "to": "minutes@acme.com",
                "from": "noreply@acme.com"
              }
            },
            "dial_out": {
              "type": "sip",
              "target": "sip:reception@pbx.acme.com",
              "cli": "+441632960001"
            },
            "webhook_url": "https://hooks.acme.com/conference/joined"
          }
        },
        "properties": {
          "account_id": {
            "type": "integer",
            "description": "The account that will own the service. Must be your own account or one of your sub-accounts."
          },
          "name": {
            "type": "string",
            "maxLength": 100,
            "description": "A friendly name for the service, shown in your portal."
          },
          "service_type": {
            "type": "integer",
            "enum": [
              2
            ],
            "description": "Always `2` for an Audio Conference service. The type must be enabled for the target account."
          },
          "conference": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Conference"
              }
            ],
            "description": "The conference room configuration — PINs, capacity, welcome audio, dial-out and recording."
          }
        }
      },
      "IvrServiceCreate": {
        "type": "object",
        "required": [
          "account_id",
          "name",
          "service_type",
          "ivr"
        ],
        "description": "An IVR menu service (service_type 11). Callers hear a greeting and press a\nDTMF digit to be routed. Attach numbers afterwards with\n`POST /v1/services/{id}/numbers`.\n",
        "properties": {
          "account_id": {
            "type": "integer",
            "description": "The account that will own the service (yours or a sub-account)."
          },
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "service_type": {
            "type": "integer",
            "enum": [
              11
            ]
          },
          "ivr": {
            "$ref": "#/components/schemas/IvrMenu"
          },
          "postcall": {
            "type": "object",
            "description": "Optional post-call notifications (SMS/email) sent after the call."
          }
        }
      },
      "IvrMenu": {
        "type": "object",
        "example": {
          "greeting_audio_id": "8",
          "menu": [
            {
              "digit": "1",
              "name": "Sales",
              "action": "linked_service",
              "linked_service_id": 101
            },
            {
              "digit": "2",
              "name": "Support",
              "action": "voicemail"
            }
          ]
        },
        "required": [
          "menu"
        ],
        "description": "An IVR menu (used at the top level and for nested sub-menus).",
        "properties": {
          "greeting_audio_id": {
            "type": "string",
            "default": "0",
            "description": "Account audio id played when the menu starts (\"0\" = none)."
          },
          "timeout_audio_id": {
            "type": "string",
            "default": "0",
            "description": "Account audio id played on no input (\"0\" = none)."
          },
          "max_repeats": {
            "type": "integer",
            "default": 3,
            "description": "How many times the menu repeats on no/invalid input."
          },
          "menu": {
            "type": "array",
            "minItems": 1,
            "description": "One entry per DTMF key.",
            "items": {
              "$ref": "#/components/schemas/IvrMenuOption"
            }
          }
        }
      },
      "IvrMenuOption": {
        "type": "object",
        "example": {
          "digit": "1",
          "name": "Sales",
          "action": "linked_service",
          "linked_service_id": 101
        },
        "required": [
          "digit",
          "action"
        ],
        "description": "A single DTMF choice. Which extra fields apply depends on `action`.",
        "properties": {
          "digit": {
            "type": "string",
            "maxLength": 1,
            "description": "The key the caller presses (0-9, * or #)."
          },
          "name": {
            "type": "string",
            "description": "Friendly label for the choice."
          },
          "action": {
            "type": "string",
            "enum": [
              "hangup",
              "voicemail",
              "repeat",
              "play_audio",
              "linked_service",
              "submenu",
              "flexible"
            ],
            "description": "What happens on this key. `hangup`/`voicemail`/`repeat` are\nself-contained; `play_audio` uses `audio_id`/`post_action`;\n`linked_service` uses `linked_service_id`; `submenu` uses `submenu`;\n`flexible` uses `actions`.\n"
          },
          "audio_id": {
            "type": "string",
            "description": "Account audio to play. Used when action=play_audio."
          },
          "post_action": {
            "type": "string",
            "description": "What to do after the audio (e.g. return to menu). Used when action=play_audio."
          },
          "linked_service_id": {
            "type": "integer",
            "description": "Hand the call to another of your services. Used when action=linked_service."
          },
          "submenu": {
            "allOf": [
              {
                "$ref": "#/components/schemas/IvrMenu"
              }
            ],
            "description": "A nested menu. Used when action=submenu."
          },
          "actions": {
            "type": "array",
            "description": "One or more behaviours to run. Used when action=flexible.",
            "items": {
              "$ref": "#/components/schemas/FlexibleAction"
            }
          }
        }
      },
      "AbrServiceCreate": {
        "type": "object",
        "required": [
          "account_id",
          "name",
          "service_type",
          "abr"
        ],
        "description": "Advanced ABR (service_type 14). Routes callers by the area / dialling\nprefix of their number, with an optional default for non-matches.\n",
        "properties": {
          "account_id": {
            "type": "integer"
          },
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "service_type": {
            "type": "integer",
            "enum": [
              14
            ]
          },
          "abr": {
            "type": "object",
            "required": [
              "rules"
            ],
            "properties": {
              "rules": {
                "type": "array",
                "minItems": 1,
                "description": "Match rules, evaluated in order.",
                "items": {
                  "$ref": "#/components/schemas/AbrRule"
                }
              },
              "default": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/AbrOutcome"
                  }
                ],
                "description": "Where to send callers that match no rule (linked or flexible only)."
              }
            }
          },
          "postcall": {
            "type": "object",
            "description": "Optional post-call notifications."
          }
        }
      },
      "AbrRule": {
        "type": "object",
        "example": {
          "rule_type": "direct",
          "match_value": "44161",
          "name": "Manchester",
          "rule_mode": "linked",
          "linked_service_id": 101
        },
        "required": [
          "rule_type"
        ],
        "description": "A match rule plus its outcome. `rule_mode` selects which outcome fields apply.",
        "properties": {
          "rule_type": {
            "type": "string",
            "enum": [
              "list",
              "direct"
            ],
            "description": "`list` matches a saved area list (`area_list_id`); `direct` matches a literal prefix (`match_value`)."
          },
          "routing_type": {
            "type": "string",
            "default": "cli_prefix",
            "description": "What to match on (e.g. cli_prefix)."
          },
          "name": {
            "type": "string"
          },
          "area_list_id": {
            "type": "integer",
            "description": "Account area list id. Required when rule_type=list."
          },
          "match_value": {
            "type": "string",
            "description": "Literal prefix to match. Required when rule_type=direct."
          },
          "match_descriptions": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          },
          "rule_mode": {
            "type": "string",
            "enum": [
              "linked",
              "flexible",
              "ivr"
            ],
            "default": "linked",
            "description": "Outcome: `linked` -> linked_service_id; `flexible` -> actions[]; `ivr` -> ivr menu."
          },
          "linked_service_id": {
            "type": "integer",
            "description": "Used when rule_mode=linked."
          },
          "actions": {
            "type": "array",
            "description": "Used when rule_mode=flexible.",
            "items": {
              "$ref": "#/components/schemas/FlexibleAction"
            }
          },
          "ivr": {
            "type": "object",
            "description": "Used when rule_mode=ivr — an IVR menu triggered for matched callers.",
            "properties": {
              "greeting_audio_id": {
                "type": "string",
                "default": "0"
              },
              "menu": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "digit"
                  ],
                  "properties": {
                    "digit": {
                      "type": "string",
                      "maxLength": 1
                    },
                    "action": {
                      "type": "string",
                      "description": "DTMF action label (e.g. hangup)."
                    },
                    "actions": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/FlexibleAction"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "AbrOutcome": {
        "type": "object",
        "example": {
          "rule_mode": "linked",
          "linked_service_id": 101
        },
        "description": "A linked or flexible outcome (used by the default route).",
        "properties": {
          "linked_service_id": {
            "type": "integer",
            "description": "Linked outcome."
          },
          "rule_mode": {
            "type": "string",
            "enum": [
              "linked",
              "flexible"
            ]
          },
          "actions": {
            "type": "array",
            "description": "Flexible outcome.",
            "items": {
              "$ref": "#/components/schemas/FlexibleAction"
            }
          }
        }
      },
      "FlowServiceCreate": {
        "type": "object",
        "required": [
          "account_id",
          "name",
          "service_type",
          "flow"
        ],
        "description": "Flow Builder (service_type 13). A directed graph of nodes; the platform\ncompiles it into the running call flow.\n",
        "properties": {
          "account_id": {
            "type": "integer"
          },
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "service_type": {
            "type": "integer",
            "enum": [
              13
            ]
          },
          "flow": {
            "type": "object",
            "required": [
              "entry",
              "nodes"
            ],
            "description": "The complete graph must encode to at most 256 KiB (262144 bytes)\nin stored JSON, including JSON escaping.\n",
            "properties": {
              "entry": {
                "type": "string",
                "description": "The id of the first node."
              },
              "nodes": {
                "type": "array",
                "minItems": 1,
                "items": {
                  "$ref": "#/components/schemas/FlowNode"
                }
              }
            }
          }
        }
      },
      "FlowNode": {
        "type": "object",
        "example": {
          "id": "n1",
          "type": "time_of_day",
          "params": {
            "timezone": "Europe/London",
            "schedule": "1,09:00,17:00"
          },
          "next": {
            "out": "n2",
            "alt": "n3"
          }
        },
        "required": [
          "id",
          "type"
        ],
        "description": "A node in the flow graph.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique within the flow; referenced by other nodes' edges."
          },
          "type": {
            "type": "string",
            "description": "Node type. Supported: terminate, hangup, play_audio, custom_sip_headers,\nlinked_service, time_of_day, apply_list_rules, ip_routing, whisper,\nfailover, http_request, split_test, send_email, send_sms, voicemail,\nrecord_call, caller_id, receive_fax, mid_call_transfer, queue,\nfirewall, conference, area_routing, date_routing.\n"
          },
          "params": {
            "type": "object",
            "description": "Node-specific parameters (the same shape as the matching inbound section / action)."
          },
          "next": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Outgoing edges keyed by port -> the id of the next node. Most nodes use\n`out`; two-way nodes also use `alt`; terminate uses `alt`; IVR uses\nper-digit keys plus `fail`.\n"
          }
        }
      },
      "FlexibleAction": {
        "type": "object",
        "example": {
          "type": "play_audio",
          "params": {
            "audio_id": 8
          }
        },
        "required": [
          "type",
          "params"
        ],
        "description": "A single behaviour attached to an IVR digit (action=flexible) or an ABR\nrule (rule_mode=flexible).\n",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "terminate",
              "time_of_day",
              "play_audio",
              "whisper",
              "apply_list_rules",
              "caller_id",
              "voicemail",
              "recording"
            ],
            "description": "The behaviour to run."
          },
          "params": {
            "type": "object",
            "description": "Parameters for the behaviour. The shape matches the matching feature:\n`terminate` takes a route-like { strategy, targets[] }; `voicemail`/\n`recording` take { greeting_audio_id?, delivery, email_to/email_from |\nserver_host/user/password/path | bucket, summary_enabled?, summary_type? }\n(recording also takes recording_mode); the rest take their single-field\nshapes (e.g. play_audio { audio_id }, apply_list_rules { list_id }).\n"
          }
        }
      },
      "Route": {
        "type": "object",
        "example": {
          "strategy": "simultaneous",
          "targets": [
            {
              "type": "number",
              "number": "+441632960001",
              "ring_time": 30
            }
          ]
        },
        "required": [
          "targets"
        ],
        "description": "Where incoming calls are sent and in what order.",
        "properties": {
          "strategy": {
            "type": "string",
            "enum": [
              "simultaneous",
              "sequential",
              "round_robin",
              "weighted"
            ],
            "default": "simultaneous",
            "description": "How the targets are dialled.\n- `simultaneous`: ring every target at once; first to answer wins.\n- `sequential`: try each target in order, moving on when one does not answer within its `ring_time`.\n- `round_robin`: rotate which target is tried first across successive calls, to spread load.\n- `weighted`: distribute calls across targets in proportion to each target's `weight`.\n"
          },
          "targets": {
            "type": "array",
            "minItems": 1,
            "description": "One or more destinations to dial, in priority order.",
            "items": {
              "$ref": "#/components/schemas/RouteTarget"
            }
          }
        }
      },
      "RouteTarget": {
        "type": "object",
        "example": {
          "type": "number",
          "number": "+441632960001",
          "ring_time": 30
        },
        "required": [
          "type"
        ],
        "description": "A single destination within a route. `type` selects the kind of\ndestination and which value field applies.\n",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "number",
              "address_book",
              "sip",
              "ddi",
              "ai_agent"
            ],
            "description": "The kind of destination.\n- `number`: an external phone number (set `number`).\n- `address_book`: a saved contact in your account (set `address_book_id`).\n- `sip`: a SIP endpoint you operate (set `sip_uri`).\n- `ddi`: route back to the dialled number itself.\n- `ai_agent`: one of your AI voice agents (set `ai_agent_id`).\n"
          },
          "number": {
            "type": "string",
            "pattern": "^\\+[1-9]\\d{1,14}$",
            "description": "Destination phone number in E.164 format, e.g. `+441632960001`. Required when `type` is `number`.",
            "example": "+441632960001"
          },
          "sip_uri": {
            "type": "string",
            "pattern": "^sips?:[^@\\s&=]+@[^@\\s&=]+$",
            "maxLength": 255,
            "description": "SIP address in the form `sip:user@host`. Required when `type` is `sip`. Must not contain spaces, `&` or `=`.",
            "example": "sip:agent@acme.com"
          },
          "address_book_id": {
            "type": "integer",
            "description": "Id of a saved contact in this account. Required when `type` is `address_book`."
          },
          "ai_agent_id": {
            "type": "string",
            "description": "Id of one of your AI voice agents. Required when `type` is `ai_agent`. Requires the AI agents feature to be enabled for the account."
          },
          "ring_time": {
            "type": "integer",
            "minimum": 5,
            "maximum": 120,
            "default": 30,
            "description": "How long (in seconds) to ring this target before giving up. Most relevant for `sequential` routing."
          },
          "weight": {
            "type": "integer",
            "minimum": 1,
            "description": "Relative share of calls this target receives. Used only when `route.strategy` is `weighted`; ignored otherwise."
          }
        }
      },
      "Target": {
        "type": "object",
        "example": {
          "type": "number",
          "number": "+441632960001"
        },
        "required": [
          "type"
        ],
        "description": "A single redirect destination, used for failover and for the various\n\"what to do instead\" branches (out-of-hours, blocked caller, list match,\nand so on). `type` selects which value field applies.\n",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "number",
              "address_book",
              "sip",
              "voicemail",
              "sip_code",
              "linked_service",
              "audio",
              "ai_agent"
            ],
            "description": "The kind of redirect destination.\n- `number`: an external phone number (set `number`).\n- `address_book`: a saved contact (set `address_book_id`).\n- `sip`: a SIP endpoint (set `sip_uri`).\n- `voicemail`: send the caller to voicemail.\n- `sip_code`: reject the call with a SIP response code (set `sip_code`).\n- `linked_service`: hand the call to another of your services (set `linked_service_id`).\n- `audio`: play an audio file then end the call (set `audio_id`).\n- `ai_agent`: connect to an AI voice agent (set `ai_agent_id`).\n"
          },
          "number": {
            "type": "string",
            "pattern": "^\\+[1-9]\\d{1,14}$",
            "description": "Destination phone number in E.164 format, e.g. `+441632960001`. Required when `type` is `number`.",
            "example": "+441632960001"
          },
          "sip_uri": {
            "type": "string",
            "pattern": "^sips?:[^@\\s&=]+@[^@\\s&=]+$",
            "maxLength": 255,
            "description": "SIP address in the form `sip:user@host`. Required when `type` is `sip`."
          },
          "sip_code": {
            "type": "string",
            "pattern": "^[1-6]\\d{2}$",
            "description": "SIP rejection code to return to the caller, e.g. `486` (Busy), `603` (Decline). Required when `type` is `sip_code`.",
            "example": "603"
          },
          "address_book_id": {
            "type": "integer",
            "description": "Id of a saved contact. Required when `type` is `address_book`."
          },
          "linked_service_id": {
            "type": "integer",
            "description": "Id of another service in this account to hand the call to. Required when `type` is `linked_service`."
          },
          "audio_id": {
            "type": "integer",
            "description": "Id of an audio file in this account to play. Required when `type` is `audio`."
          },
          "ai_agent_id": {
            "type": "string",
            "description": "Id of an AI voice agent. Required when `type` is `ai_agent`."
          }
        }
      },
      "TimeOfDay": {
        "type": "object",
        "required": [
          "schedule",
          "closed_route"
        ],
        "description": "Open-hours gate. Calls outside the defined hours are sent to `closed_route` instead of the normal route.",
        "properties": {
          "timezone": {
            "type": "string",
            "default": "UTC",
            "description": "IANA time zone the schedule is interpreted in, e.g. `Europe/London`.",
            "example": "Europe/London"
          },
          "schedule": {
            "type": "string",
            "pattern": "^[0-6],([01]\\d|2[0-3]):[0-5]\\d,([01]\\d|2[0-3]):[0-5]\\d(;[0-6],([01]\\d|2[0-3]):[0-5]\\d,([01]\\d|2[0-3]):[0-5]\\d)*$",
            "description": "Open-hours rules. One or more `day,HH:MM,HH:MM` rules joined with `;`,\nwhere the day is `0`=Sunday through `6`=Saturday and the two times are\nthe open and close times (24-hour clock). Example: open 9am–5pm Monday\nand Tuesday is `1,09:00,17:00;2,09:00,17:00`.\n",
            "example": "1,09:00,17:00;2,09:00,17:00"
          },
          "closed_route": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Target"
              }
            ],
            "description": "Where to send calls received outside the open hours."
          }
        }
      },
      "AnonymousCli": {
        "type": "object",
        "required": [
          "list_id",
          "divert"
        ],
        "description": "Handles callers who withhold their number (anonymous / no caller ID).",
        "properties": {
          "list_id": {
            "type": "integer",
            "description": "Id of the account access list anonymous callers are checked against."
          },
          "block_code": {
            "type": "string",
            "pattern": "^[0-9*#A-D]$",
            "default": "*",
            "description": "DTMF key an anonymous caller can press to be let through. Defaults to `*`."
          },
          "divert": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Target"
              }
            ],
            "description": "Where to send a blocked anonymous caller."
          }
        }
      },
      "Firewall": {
        "type": "object",
        "example": {
          "mode": "service",
          "call_limit": 5,
          "timeframe": 60,
          "timeframe_unit": "seconds",
          "divert": {
            "type": "voicemail"
          }
        },
        "required": [
          "mode"
        ],
        "description": "Rate-limits or blocks abusive callers, either using a saved firewall profile or rules defined inline.",
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "account",
              "service"
            ],
            "default": "service",
            "description": "- `account`: apply a saved account-level firewall profile (set `firewall_id`).\n- `service`: define limits inline for this service only (set `call_limit`, `timeframe`, `divert`).\n"
          },
          "firewall_id": {
            "type": "integer",
            "description": "Id of a saved account firewall profile. Required when `mode` is `account`."
          },
          "call_limit": {
            "type": "integer",
            "minimum": 0,
            "description": "Maximum number of calls allowed from a caller within `timeframe`. Used when `mode` is `service`."
          },
          "timeframe": {
            "type": "integer",
            "minimum": 0,
            "description": "Length of the rate-limit window. Used when `mode` is `service`. Combined with `timeframe_unit`."
          },
          "timeframe_unit": {
            "type": "string",
            "enum": [
              "seconds",
              "minutes",
              "hours"
            ],
            "default": "seconds",
            "description": "Unit for `timeframe`."
          },
          "divert": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Target"
              }
            ],
            "description": "Where to send a caller who exceeds the limit. Used when `mode` is `service`."
          },
          "add_to_list": {
            "type": "object",
            "description": "Optionally add an offending caller to an access list automatically.",
            "required": [
              "enabled"
            ],
            "properties": {
              "enabled": {
                "type": "boolean",
                "default": false,
                "description": "Whether to add limit-breaching callers to a list."
              },
              "list_id": {
                "type": "integer",
                "description": "Id of the account access list to add them to. Required when `enabled` is true."
              }
            }
          }
        }
      },
      "Acl": {
        "type": "object",
        "required": [
          "list_id",
          "divert"
        ],
        "description": "Applies an access list (allow/block list) to incoming callers.",
        "properties": {
          "list_id": {
            "type": "integer",
            "description": "Id of the account access list to apply."
          },
          "divert": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Target"
              }
            ],
            "description": "Where to send a caller who matches the block rule."
          }
        }
      },
      "AreaRouting": {
        "type": "object",
        "example": {
          "rules": [
            {
              "list_id": 5,
              "route": {
                "type": "linked_service",
                "linked_service_id": 101
              }
            }
          ]
        },
        "required": [
          "rules"
        ],
        "description": "Routes callers differently based on the area / dialling prefix of their number, using one or more rules.",
        "properties": {
          "rules": {
            "type": "array",
            "minItems": 1,
            "description": "The area-based routing rules, evaluated in order.",
            "items": {
              "type": "object",
              "required": [
                "list_id",
                "route"
              ],
              "properties": {
                "list_id": {
                  "type": "integer",
                  "description": "Id of the account area list this rule matches against."
                },
                "route": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Target"
                    }
                  ],
                  "description": "Where to send callers that match this rule."
                }
              }
            }
          }
        }
      },
      "DateRouting": {
        "type": "object",
        "example": {
          "rules": [
            {
              "mode": "custom",
              "date": "2026-12-25",
              "start": "00:00",
              "end": "23:59",
              "divert": {
                "type": "voicemail"
              }
            }
          ]
        },
        "required": [
          "rules"
        ],
        "description": "Routes callers differently on specific dates (for example public holidays), using one or more rules. Each rule matches either a saved date list or a single custom date window.",
        "properties": {
          "rules": {
            "type": "array",
            "minItems": 1,
            "description": "The date-based routing rules, evaluated in order.",
            "items": {
              "type": "object",
              "required": [
                "mode",
                "divert"
              ],
              "properties": {
                "mode": {
                  "type": "string",
                  "enum": [
                    "list",
                    "custom"
                  ],
                  "description": "- `list`: match against a saved account date list (set `list_id`).\n- `custom`: match one specific date and time window (set `date`, `start`, `end`).\n"
                },
                "list_id": {
                  "type": "integer",
                  "description": "Id of the account date list. Required when `mode` is `list`."
                },
                "date": {
                  "type": "string",
                  "format": "date",
                  "description": "The date to match, `YYYY-MM-DD`. Required when `mode` is `custom`.",
                  "example": "2026-12-25"
                },
                "start": {
                  "type": "string",
                  "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$",
                  "description": "Start of the time window on that date, `HH:MM` (24-hour). Used when `mode` is `custom`.",
                  "example": "00:00"
                },
                "end": {
                  "type": "string",
                  "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$",
                  "description": "End of the time window on that date, `HH:MM` (24-hour). Used when `mode` is `custom`.",
                  "example": "23:59"
                },
                "divert": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Target"
                    }
                  ],
                  "description": "Where to send callers on the matching date."
                }
              }
            }
          }
        }
      },
      "IpRouting": {
        "type": "object",
        "required": [
          "list_id",
          "redirect"
        ],
        "description": "Routes callers based on a match against an account IP list.",
        "properties": {
          "list_id": {
            "type": "integer",
            "description": "Id of the account IP list to check against."
          },
          "redirect": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Target"
              }
            ],
            "description": "Where to send a caller that matches the list."
          }
        }
      },
      "Recording": {
        "type": "object",
        "required": [
          "delivery"
        ],
        "description": "Records the call and delivers the recording.",
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "auto",
              "auto_pausable",
              "manual"
            ],
            "default": "auto",
            "description": "- `auto`: record the whole call automatically.\n- `auto_pausable`: record automatically, but let the agent pause/resume with DTMF keys.\n- `manual`: do not record until the agent starts it with a DTMF key.\n"
          },
          "dtmf": {
            "type": "object",
            "description": "DTMF key codes that control recording. Which keys apply depends on `mode`.",
            "properties": {
              "pause": {
                "type": "string",
                "pattern": "^\\*\\d$",
                "default": "*7",
                "description": "Key to pause recording (`auto_pausable` mode)."
              },
              "resume": {
                "type": "string",
                "pattern": "^\\*\\d$",
                "default": "*8",
                "description": "Key to resume recording (`auto_pausable` mode)."
              },
              "start": {
                "type": "string",
                "pattern": "^\\*\\d$",
                "default": "*1",
                "description": "Key to start recording (`manual` mode)."
              },
              "stop": {
                "type": "string",
                "pattern": "^\\*\\d$",
                "default": "*0",
                "description": "Key to stop recording (`manual` mode)."
              }
            }
          },
          "summary": {
            "$ref": "#/components/schemas/AiSummary"
          },
          "delivery": {
            "$ref": "#/components/schemas/RecordingDelivery"
          }
        }
      },
      "Fax": {
        "type": "object",
        "example": {
          "type": "email",
          "to_addr": "fax@acme.com",
          "from_addr": "noreply@acme.com",
          "document_format": "pdf"
        },
        "required": [
          "type",
          "to_addr",
          "from_addr"
        ],
        "description": "Receives the call as a fax and emails the completed TIFF or PDF document.",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "email"
            ],
            "description": "Fax delivery method. Email is the supported method."
          },
          "to_addr": {
            "type": "string",
            "description": "One to ten comma-separated recipient email addresses."
          },
          "from_addr": {
            "type": "string",
            "format": "email",
            "description": "Reply address shown for the fax delivery email. The verified platform address remains the delivery sender."
          },
          "document_format": {
            "type": "string",
            "enum": [
              "tiff",
              "pdf"
            ],
            "default": "tiff",
            "description": "Attachment format. Existing services without this field continue to use TIFF."
          }
        }
      },
      "CallerId": {
        "type": "object",
        "example": {
          "mode": "custom",
          "custom_number": "+441632960000"
        },
        "required": [
          "mode"
        ],
        "description": "Controls what caller ID is presented to the answering party.",
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "passthrough",
              "dialled",
              "both",
              "custom"
            ],
            "description": "- `passthrough`: present the original caller's number (standard).\n- `dialled`: present the number that was dialled instead.\n- `both`: present both the dialled number and the caller.\n- `custom`: present a fixed custom number (set `custom_number`).\n"
          },
          "replace_pai": {
            "type": "boolean",
            "default": false,
            "description": "Also rewrite the network identity header so the chosen number is used end-to-end."
          },
          "custom_number": {
            "type": "string",
            "pattern": "^\\+[1-9]\\d{1,14}$",
            "description": "The caller ID to present in E.164 format. Required when `mode` is `custom`.",
            "example": "+441632960000"
          }
        }
      },
      "Conference": {
        "type": "object",
        "example": {
          "max_participants": 10,
          "moderator_pin": "1234",
          "outbound": {
            "enabled": true,
            "type": "csv",
            "dial": [
              "+441632960002"
            ]
          }
        },
        "description": "Drops the caller into a conference room, optionally dialling out to participants and recording.",
        "properties": {
          "guest_pins": {
            "type": "string",
            "description": "PIN(s) guests must enter to join."
          },
          "moderator_pin": {
            "type": "string",
            "description": "PIN that identifies the conference moderator."
          },
          "max_participants": {
            "type": "integer",
            "minimum": 1,
            "description": "Maximum number of people allowed in the conference."
          },
          "audio_id": {
            "type": "integer",
            "minimum": 0,
            "description": "Id of an account audio file to play to participants (for example a welcome announcement). `0` for none."
          },
          "outbound": {
            "type": "object",
            "description": "Optionally dial out to bring participants into the conference.",
            "properties": {
              "enabled": {
                "type": "boolean",
                "default": false,
                "description": "Whether to dial out to participants."
              },
              "type": {
                "type": "string",
                "enum": [
                  "csv",
                  "address_book",
                  "acl"
                ],
                "default": "csv",
                "description": "Source of the participants to dial.\n- `csv`: a supplied list of numbers (set `dial`).\n- `address_book`: a saved contact (set `address_book_id`).\n- `acl`: an account access list of numbers (set `acl_id`).\n"
              },
              "dial": {
                "type": "array",
                "items": {
                  "type": "string",
                  "pattern": "^\\+[1-9]\\d{1,14}$"
                },
                "description": "Numbers to dial out to, each in E.164 format. Used when `type` is `csv`."
              },
              "address_book_id": {
                "type": "integer",
                "description": "Id of the contact to dial. Used when `type` is `address_book`."
              },
              "acl_id": {
                "type": "integer",
                "description": "Id of the access list of numbers to dial. Used when `type` is `acl`."
              },
              "cli": {
                "type": "string",
                "description": "Which caller ID to present on the outbound legs, or `custom` to use `custom_cli`."
              },
              "custom_cli": {
                "type": "string",
                "pattern": "^\\+[1-9]\\d{1,14}$",
                "description": "Custom caller ID in E.164 format. Used when `cli` is `custom`."
              }
            }
          },
          "record": {
            "type": "object",
            "description": "Optionally record the conference.",
            "properties": {
              "enabled": {
                "type": "boolean",
                "default": false,
                "description": "Whether to record the conference."
              },
              "summary": {
                "$ref": "#/components/schemas/AiSummary"
              },
              "delivery": {
                "$ref": "#/components/schemas/RecordingDelivery"
              }
            }
          },
          "webhook_url": {
            "type": "string",
            "format": "uri",
            "maxLength": 2048,
            "description": "Existing conference service webhook setting, passed to the estate\nplatform. Must be HTTPS; private, local, reserved and link-local\naddresses are rejected. The API does not expose conference event\nsubscriptions, delivery guarantees or a public event payload contract.\nObtain live action anchors through an independently verified integration.\n"
          },
          "dial_out": {
            "type": "object",
            "description": "Automatically dial a single participant when a caller joins — a phone\nnumber OR a SIP URI. Distinct from `outbound` above, which dials a list\nof attendees when the moderator joins.\n",
            "required": [
              "type",
              "target"
            ],
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "number",
                  "sip"
                ],
                "description": "`number` to dial a phone number; `sip` to dial a SIP URI."
              },
              "target": {
                "type": "string",
                "maxLength": 255,
                "description": "The E.164 number (when `type` is `number`) or the SIP URI (when `type` is `sip`)."
              },
              "cli": {
                "type": "string",
                "maxLength": 32,
                "description": "Optional caller ID (E.164) to present on the dial-out leg."
              }
            }
          }
        }
      },
      "CliMasking": {
        "type": "object",
        "description": "Maps inbound caller IDs to a presented outbound caller ID (number masking).",
        "properties": {
          "inbound_cli": {
            "type": "string",
            "description": "Comma-separated list of inbound caller IDs (E.164) to match. Provide this OR `inbound_clis`."
          },
          "inbound_clis": {
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^\\+[1-9]\\d{1,14}$"
            },
            "description": "List of inbound caller IDs (E.164) to match. Provide this OR `inbound_cli`."
          },
          "outbound_cli": {
            "type": "string",
            "pattern": "^\\+[1-9]\\d{1,14}$",
            "description": "The caller ID (E.164) to present outbound for matching calls."
          },
          "dual_purpose": {
            "type": "boolean",
            "default": false,
            "description": "Enable the dual-purpose masking variant (mask in both directions)."
          }
        }
      },
      "PreconnectionAudio": {
        "type": "object",
        "required": [
          "audio_id"
        ],
        "description": "Plays an audio message to the caller before the call is connected.",
        "properties": {
          "audio_id": {
            "type": "integer",
            "minimum": 0,
            "description": "Id of the account audio file to play before connecting. `0` disables."
          }
        }
      },
      "Whisper": {
        "type": "object",
        "required": [
          "audio_id"
        ],
        "description": "Plays a short message only to the answering agent (the caller keeps hearing ringing), optionally requiring the agent to accept the call.",
        "properties": {
          "audio_id": {
            "type": "integer",
            "minimum": 0,
            "description": "Id of the account audio file played to the agent. `0` for none."
          },
          "confirm_code": {
            "type": "string",
            "pattern": "^[0-9*#A-DX]$",
            "default": "X",
            "description": "DTMF key the agent must press to accept the call. The default `X` means auto-accept (no key required)."
          }
        }
      },
      "PostCall": {
        "type": "object",
        "description": "Sends a notification after the call ends, by SMS and/or email.",
        "properties": {
          "sms": {
            "type": "object",
            "description": "SMS notification settings.",
            "properties": {
              "enabled": {
                "type": "boolean",
                "default": false,
                "description": "Whether to send an SMS notification."
              },
              "sender": {
                "type": "string",
                "description": "Sender id — an alphanumeric sender name or an allowed caller ID (E.164). Used when `enabled` is true."
              },
              "to": {
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "pattern": "^\\+[1-9]\\d{1,14}$"
                    }
                  }
                ],
                "description": "Recipient number(s) in E.164 format, as a comma-separated string or an array."
              },
              "text": {
                "type": "string",
                "description": "Message body. Do not include the caller's phone number here — it is added by the platform."
              }
            }
          },
          "email": {
            "type": "object",
            "description": "Email notification settings.",
            "properties": {
              "enabled": {
                "type": "boolean",
                "default": false,
                "description": "Whether to send an email notification."
              },
              "to": {
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "email"
                    }
                  }
                ],
                "description": "Recipient email address(es), as a comma-separated string or an array."
              },
              "from": {
                "type": "string",
                "format": "email",
                "description": "Sender email address."
              },
              "subject": {
                "type": "string",
                "description": "Email subject line."
              },
              "body": {
                "type": "string",
                "description": "Email body."
              }
            }
          }
        }
      },
      "Queue": {
        "type": "object",
        "example": {
          "moh_audio_id": 8,
          "max_wait_seconds": 300,
          "overflow": {
            "type": "voicemail"
          }
        },
        "description": "Holds callers in a queue with music/announcements until an agent is free, with overflow and breakout handling.",
        "properties": {
          "welcome_audio_id": {
            "type": "integer",
            "minimum": 0,
            "default": 0,
            "description": "Id of the account audio file played when the caller enters the queue. `0` for none."
          },
          "moh_audio_id": {
            "type": "integer",
            "minimum": 0,
            "default": 0,
            "description": "Id of the account audio file used for music-on-hold. `0` for none."
          },
          "comfort_audio_id": {
            "type": "integer",
            "minimum": 0,
            "default": 0,
            "description": "Id of the account audio file played periodically as a comfort message. `0` for none."
          },
          "comfort_interval": {
            "type": "integer",
            "default": 60,
            "description": "Seconds between comfort messages."
          },
          "max_queue_size": {
            "type": "integer",
            "default": 100,
            "description": "Maximum number of callers allowed to wait in the queue."
          },
          "max_wait_seconds": {
            "type": "integer",
            "default": 7200,
            "description": "Maximum time (seconds) a caller may wait before being sent to overflow."
          },
          "concurrent_limit": {
            "type": "integer",
            "default": 200,
            "description": "Maximum number of concurrent calls the queue will handle."
          },
          "breakout": {
            "type": "object",
            "description": "Lets a waiting caller press a key to leave the queue and be redirected.",
            "properties": {
              "enabled": {
                "type": "boolean",
                "default": false,
                "description": "Whether breakout is offered."
              },
              "dtmf": {
                "type": "string",
                "pattern": "^[0-9*#A-D]$",
                "default": "*",
                "description": "DTMF key the caller presses to break out. Used when `enabled` is true."
              },
              "type": {
                "type": "string",
                "enum": [
                  "number",
                  "address_book",
                  "sip",
                  "voicemail",
                  "sip_code",
                  "linked_service",
                  "audio",
                  "ai_agent"
                ],
                "description": "Kind of destination for breakout. See `Target.type` for meanings."
              },
              "number": {
                "type": "string",
                "pattern": "^\\+[1-9]\\d{1,14}$",
                "description": "Breakout phone number (E.164), when type is number."
              },
              "sip_uri": {
                "type": "string",
                "description": "Breakout SIP address, when type is sip."
              },
              "sip_code": {
                "type": "string",
                "pattern": "^[1-6]\\d{2}$",
                "description": "SIP rejection code, when type is sip_code."
              },
              "address_book_id": {
                "type": "integer",
                "description": "Contact id, when type is address_book."
              },
              "linked_service_id": {
                "type": "integer",
                "description": "Service id, when type is linked_service."
              },
              "audio_id": {
                "type": "integer",
                "description": "Audio file id, when type is audio."
              },
              "ai_agent_id": {
                "type": "string",
                "description": "AI agent id, when type is ai_agent."
              }
            }
          },
          "overflow": {
            "type": "object",
            "required": [
              "type"
            ],
            "description": "Where callers go when the queue is full or they wait too long.",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "number",
                  "address_book",
                  "sip",
                  "voicemail",
                  "sip_code",
                  "linked_service",
                  "audio",
                  "ai_agent"
                ],
                "description": "Kind of overflow destination. See `Target.type` for meanings."
              },
              "number": {
                "type": "string",
                "pattern": "^\\+[1-9]\\d{1,14}$",
                "description": "Overflow phone number (E.164), when type is number."
              },
              "sip_uri": {
                "type": "string",
                "description": "Overflow SIP address, when type is sip."
              },
              "sip_code": {
                "type": "string",
                "pattern": "^[1-6]\\d{2}$",
                "description": "SIP rejection code, when type is sip_code."
              },
              "address_book_id": {
                "type": "integer",
                "description": "Contact id, when type is address_book."
              },
              "linked_service_id": {
                "type": "integer",
                "description": "Service id, when type is linked_service."
              },
              "audio_id": {
                "type": "integer",
                "description": "Audio file id, when type is audio."
              },
              "ai_agent_id": {
                "type": "string",
                "description": "AI agent id, when type is ai_agent."
              }
            }
          }
        }
      },
      "AudioPlayer": {
        "type": "object",
        "example": {
          "playlist": [
            8,
            9
          ],
          "exit": {
            "type": "hangup"
          }
        },
        "description": "Plays a playlist of audio tracks to the caller with interactive DTMF controls (pause, skip, etc.), then takes an exit action.",
        "properties": {
          "instructions_audio_id": {
            "type": "integer",
            "minimum": 0,
            "default": 0,
            "description": "Id of an account audio file describing the controls, played first. `0` for none."
          },
          "playlist": {
            "type": "array",
            "items": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Ordered list of account audio file ids to play. Zero entries are ignored."
          },
          "dtmf": {
            "type": "object",
            "description": "DTMF keys that control playback.",
            "properties": {
              "pause": {
                "type": "string",
                "pattern": "^[0-9*#A-D]$",
                "default": "2",
                "description": "Key to pause/resume playback."
              },
              "rewind": {
                "type": "string",
                "pattern": "^[0-9*#A-D]$",
                "default": "1",
                "description": "Key to rewind within the current track."
              },
              "fast_forward": {
                "type": "string",
                "pattern": "^[0-9*#A-D]$",
                "default": "3",
                "description": "Key to fast-forward within the current track."
              },
              "previous": {
                "type": "string",
                "pattern": "^[0-9*#A-D]$",
                "default": "4",
                "description": "Key to jump to the previous track."
              },
              "next": {
                "type": "string",
                "pattern": "^[0-9*#A-D]$",
                "default": "6",
                "description": "Key to jump to the next track."
              },
              "restart": {
                "type": "string",
                "pattern": "^[0-9*#A-D]$",
                "default": "0",
                "description": "Key to restart the playlist."
              },
              "exit": {
                "type": "string",
                "pattern": "^[0-9*#A-D]$",
                "default": "#",
                "description": "Key to stop playback and take the exit action."
              }
            }
          },
          "seek_amount": {
            "type": "integer",
            "default": 15,
            "description": "Seconds skipped per rewind/fast-forward press."
          },
          "resume_state": {
            "type": "integer",
            "enum": [
              0,
              1
            ],
            "default": 1,
            "description": "Whether to resume where the caller left off on a return visit (`1`) or always start over (`0`)."
          },
          "exit": {
            "type": "object",
            "required": [
              "type"
            ],
            "description": "What to do when the caller exits the player.",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "hangup",
                  "number",
                  "address_book",
                  "sip",
                  "linked_service",
                  "ai_agent",
                  "voicemail"
                ],
                "description": "The exit action.\n- `hangup`: end the call.\n- `number` / `sip` / `address_book` / `linked_service` / `ai_agent`: redirect (see `Target.type`).\n- `voicemail`: send to a custom voicemail (set `voicemail`).\n"
              },
              "number": {
                "type": "string",
                "pattern": "^\\+[1-9]\\d{1,14}$",
                "description": "Exit phone number (E.164), when type is number."
              },
              "sip_uri": {
                "type": "string",
                "description": "Exit SIP address, when type is sip."
              },
              "address_book_id": {
                "type": "integer",
                "description": "Contact id, when type is address_book."
              },
              "linked_service_id": {
                "type": "integer",
                "description": "Service id, when type is linked_service."
              },
              "ai_agent_id": {
                "type": "string",
                "description": "AI agent id, when type is ai_agent."
              },
              "voicemail": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Voicemail"
                  }
                ],
                "description": "Voicemail configuration used when `type` is `voicemail`."
              }
            }
          }
        }
      },
      "MidCallTransfer": {
        "type": "object",
        "required": [
          "transfer_code"
        ],
        "description": "Lets the answering agent transfer the live call to another party using DTMF keys.",
        "properties": {
          "transfer_code": {
            "type": "string",
            "pattern": "^\\*\\d$",
            "description": "DTMF sequence that begins a transfer — a star followed by one digit, e.g. `*1`.",
            "example": "*1"
          },
          "cancel_key": {
            "type": "string",
            "pattern": "^[0-9*#A-D]$",
            "default": "0",
            "description": "DTMF key to cancel an in-progress transfer."
          },
          "hangup_key": {
            "type": "string",
            "pattern": "^[0-9*#A-D]$",
            "default": "0",
            "description": "DTMF key to hang up the current leg during transfer."
          },
          "conf_key": {
            "type": "string",
            "pattern": "^[0-9*#A-D]$",
            "default": "0",
            "description": "DTMF key to turn the transfer into a three-way conference."
          }
        }
      },
      "MissedCallAlert": {
        "type": "object",
        "required": [
          "target"
        ],
        "description": "Emails an alert when a call is missed.",
        "properties": {
          "target": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string",
                  "format": "email"
                }
              }
            ],
            "description": "Recipient email address(es) for the alert, as a comma-separated string or an array."
          },
          "from": {
            "type": "string",
            "format": "email",
            "description": "Sender email address for the alert."
          }
        }
      },
      "CustomSipHeaders": {
        "type": "object",
        "required": [
          "headers"
        ],
        "description": "Adds custom SIP headers to the outbound call legs.",
        "properties": {
          "headers": {
            "type": "array",
            "maxItems": 10,
            "description": "Up to 10 header name/value pairs. Pairs missing a name or value are ignored.",
            "items": {
              "type": "object",
              "required": [
                "name",
                "value"
              ],
              "properties": {
                "name": {
                  "type": "string",
                  "description": "SIP header name."
                },
                "value": {
                  "type": "string",
                  "description": "SIP header value."
                }
              }
            }
          }
        }
      },
      "HeaderRewrites": {
        "type": "object",
        "description": "Rewrites standard SIP identity headers using a global regex rule (chosen by id). Omit a header or set it to `0` to leave it unchanged.",
        "properties": {
          "to": {
            "type": "integer",
            "description": "Rule id applied to the `To` header. `0` means no change."
          },
          "from": {
            "type": "integer",
            "description": "Rule id applied to the `From` header. `0` means no change."
          },
          "p_asserted_identity": {
            "type": "integer",
            "description": "Rule id applied to the `P-Asserted-Identity` header. `0` means no change."
          },
          "remote_party_id": {
            "type": "integer",
            "description": "Rule id applied to the `Remote-Party-ID` header. `0` means no change."
          }
        }
      },
      "Voicemail": {
        "type": "object",
        "example": {
          "greeting_audio_id": 8,
          "delivery": {
            "type": "email",
            "to": "support@acme.com",
            "from": "noreply@acme.com"
          }
        },
        "required": [
          "delivery"
        ],
        "description": "Sends the caller to voicemail and delivers the message.",
        "properties": {
          "greeting_audio_id": {
            "type": "integer",
            "minimum": 0,
            "default": 0,
            "description": "Id of an account audio file to use as the greeting. `0` or omitted uses the default greeting."
          },
          "summary": {
            "$ref": "#/components/schemas/AiSummary"
          },
          "delivery": {
            "type": "object",
            "required": [
              "type"
            ],
            "description": "How the voicemail message is delivered.",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "email",
                  "sftp",
                  "bucket"
                ],
                "description": "- `email`: email the recording (set `to`, `from`).\n- `sftp`: upload to an SFTP server (set `server_host`, `user`, `password`, `path`).\n- `bucket`: store in a storage bucket (set `bucket`).\n"
              },
              "to": {
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "email"
                    }
                  }
                ],
                "description": "Recipient email address(es), comma-separated string or array. Used when `type` is `email`."
              },
              "from": {
                "type": "string",
                "format": "email",
                "description": "Sender email address. Used when `type` is `email`."
              },
              "server_host": {
                "type": "string",
                "description": "SFTP server hostname. Used when `type` is `sftp`."
              },
              "user": {
                "type": "string",
                "description": "SFTP username. Used when `type` is `sftp`."
              },
              "password": {
                "type": "string",
                "format": "password",
                "writeOnly": true,
                "description": "SFTP password. Write-only — set it here, but it is never returned when reading the service back."
              },
              "path": {
                "type": "string",
                "description": "Destination path on the SFTP server. Used when `type` is `sftp`."
              },
              "bucket": {
                "type": "string",
                "description": "Storage bucket name. Used when `type` is `bucket`."
              }
            }
          }
        }
      },
      "AiSummary": {
        "type": "object",
        "description": "Optional AI-generated summary of the recorded audio.",
        "properties": {
          "enabled": {
            "type": "boolean",
            "default": false,
            "description": "Whether to generate an AI summary."
          },
          "type": {
            "type": "string",
            "description": "Id of an account AI-summary template to use. Required when `enabled` is true."
          }
        }
      },
      "RecordingDelivery": {
        "type": "object",
        "example": {
          "type": "email",
          "to": "recordings@acme.com",
          "from": "noreply@acme.com"
        },
        "required": [
          "type"
        ],
        "description": "How a recording is delivered.",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "email",
              "sftp",
              "bucket",
              "sftp_archive"
            ],
            "description": "- `email`: email the recording (set `to`, `from`).\n- `sftp` / `sftp_archive`: upload to an SFTP server (set `server_host`, `user`, `password`, `path`).\n- `bucket`: store in a storage bucket (set `bucket`).\n"
          },
          "to": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string",
                  "format": "email"
                }
              }
            ],
            "description": "Recipient email address(es), comma-separated string or array. Used when `type` is `email`."
          },
          "from": {
            "type": "string",
            "format": "email",
            "description": "Sender email address. Used when `type` is `email`."
          },
          "server_host": {
            "type": "string",
            "description": "SFTP server hostname. Used for `sftp`/`sftp_archive`."
          },
          "user": {
            "type": "string",
            "description": "SFTP username. Used for `sftp`/`sftp_archive`."
          },
          "password": {
            "type": "string",
            "format": "password",
            "writeOnly": true,
            "description": "SFTP password. Write-only — never returned when reading the service back."
          },
          "path": {
            "type": "string",
            "description": "Destination path on the SFTP server. Used for `sftp`/`sftp_archive`."
          },
          "bucket": {
            "type": "string",
            "description": "Storage bucket name. Used when `type` is `bucket`."
          }
        }
      },
      "ServiceWithConfiguration": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Service"
          },
          {
            "type": "object",
            "properties": {
              "configuration": {
                "$ref": "#/components/schemas/Configuration"
              }
            }
          }
        ]
      },
      "Configuration": {
        "type": "object",
        "description": "Read-only partial summary. It does not reconstruct every section or secret\nand must never be submitted as a replacement configuration.\n",
        "properties": {
          "route": {
            "type": "object",
            "description": "The reconstructed route.",
            "properties": {
              "strategy": {
                "type": "string",
                "enum": [
                  "simultaneous",
                  "sequential",
                  "round_robin",
                  "weighted"
                ],
                "description": "The dialling strategy."
              },
              "targets": {
                "type": "array",
                "description": "The route's targets, in order, in friendly form.",
                "items": {
                  "$ref": "#/components/schemas/RouteTarget"
                }
              }
            }
          },
          "time_of_day": {
            "allOf": [
              {
                "$ref": "#/components/schemas/TimeOfDay"
              }
            ],
            "description": "Present when the service has an open-hours gate."
          },
          "failover": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Target"
              }
            ],
            "description": "Present when the service has a failover destination."
          },
          "voicemail": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Voicemail"
              }
            ],
            "description": "Present when the service has voicemail (delivery secrets are never returned)."
          },
          "features": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Names of any other configured sections (for example `firewall`,\n`recording`, `queue`), reported by presence only.\n"
          }
        }
      },
      "Capabilities": {
        "type": "object",
        "description": "What the calling account may provision.",
        "properties": {
          "service_types": {
            "type": "array",
            "description": "Service types the account is entitled to create.",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "integer",
                  "description": "The service type id (pass as `service_type` when creating)."
                },
                "name": {
                  "type": "string",
                  "description": "Friendly name of the service type, e.g. `Flexible Routing`."
                },
                "provisionable_via_api": {
                  "type": "boolean",
                  "description": "Whether this service type can be created through this API."
                }
              }
            }
          },
          "features": {
            "type": "object",
            "description": "Feature flags resolved from the account's permissions.",
            "properties": {
              "ai_agents": {
                "type": "boolean",
                "description": "Whether AI voice agent targets may be used."
              }
            }
          }
        }
      },
      "Service": {
        "type": "object",
        "example": {
          "id": 765,
          "name": "Support Line",
          "account_id": 2,
          "route": {
            "strategy": "simultaneous",
            "targets": [
              {
                "type": "number",
                "number": "+441632960001",
                "ring_time": 30
              }
            ]
          },
          "numbers": [
            {
              "id": 1001,
              "number": "+442031230001"
            }
          ],
          "created_at": "2026-07-08T14:15:22Z"
        },
        "properties": {
          "editable_options": {
            "type": "array",
            "description": "Detail only. Existing safely editable linear routing options. Permission and revision checks still apply on save.",
            "items": {
              "$ref": "#/components/schemas/ServiceOptionControl"
            }
          },
          "service_type": {
            "type": "integer"
          },
          "supported_updates": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "name",
                "route",
                "flow"
              ]
            },
            "description": "Safely writable fields. Estate service_writes and token permissions still apply."
          },
          "config_hash": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ConfigHash"
              }
            ],
            "description": "Returned on GET detail and mutations, also as quoted ETag. Omitted from lists; GET before editing."
          },
          "flow": {
            "type": [
              "object",
              "null"
            ],
            "description": "API-shaped Flow graph, or null when invalid, in portal format, or containing protected credentials, headers or signed URLs. Null means unavailable for safe API read/write, never an empty live graph.",
            "properties": {
              "entry": {
                "type": "string"
              },
              "nodes": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/FlowNode"
                }
              }
            }
          },
          "configuration_read_only": {
            "type": "boolean",
            "description": "True for partial linear summaries and unsupported or protected Flow graphs; false for a safe, editable API-shaped Flow graph."
          },
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "account_id": {
            "type": "integer"
          },
          "route": {
            "type": [
              "object",
              "null"
            ],
            "description": "First simple SIP route when available. Use the read-only configuration summary for additional route details.",
            "properties": {
              "type": {
                "type": "string",
                "const": "sip"
              },
              "sip_uri": {
                "type": "string"
              }
            }
          },
          "numbers": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "integer"
                },
                "number": {
                  "type": "string"
                }
              }
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CallMediaAvailability": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "has_recording",
          "has_summary",
          "has_transcript"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "minimum": 1
          },
          "has_recording": {
            "type": "boolean"
          },
          "has_summary": {
            "type": "boolean"
          },
          "has_transcript": {
            "type": "boolean"
          }
        }
      },
      "ActiveConnectionCounts": {
        "type": "object",
        "required": [
          "ringing",
          "connected",
          "total"
        ],
        "properties": {
          "ringing": {
            "type": "integer",
            "minimum": 0
          },
          "connected": {
            "type": "integer",
            "minimum": 0
          },
          "total": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "ActiveCallOverview": {
        "type": "object",
        "required": [
          "data",
          "meta"
        ],
        "properties": {
          "data": {
            "type": "object",
            "required": [
              "accounts",
              "totals"
            ],
            "properties": {
              "accounts": {
                "type": "array",
                "maxItems": 100,
                "items": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ActiveConnectionCounts"
                    },
                    {
                      "type": "object",
                      "required": [
                        "account_id",
                        "account_name"
                      ],
                      "properties": {
                        "account_id": {
                          "type": "integer",
                          "minimum": 1
                        },
                        "account_name": {
                          "type": "string"
                        }
                      }
                    }
                  ]
                }
              },
              "totals": {
                "$ref": "#/components/schemas/ActiveConnectionCounts"
              }
            }
          },
          "meta": {
            "type": "object",
            "required": [
              "account_id",
              "include_children",
              "page",
              "per_page",
              "has_more",
              "matching_accounts",
              "scoped_accounts",
              "is_complete",
              "truncated",
              "truncation_reason",
              "source",
              "count_unit",
              "updated_at",
              "refresh_after_seconds"
            ],
            "properties": {
              "account_id": {
                "type": "integer",
                "minimum": 1
              },
              "include_children": {
                "type": "boolean"
              },
              "page": {
                "type": "integer",
                "minimum": 1,
                "maximum": 1000
              },
              "per_page": {
                "type": "integer",
                "minimum": 1,
                "maximum": 100
              },
              "has_more": {
                "type": "boolean"
              },
              "matching_accounts": {
                "type": "integer",
                "minimum": 0,
                "maximum": 1000
              },
              "scoped_accounts": {
                "type": "integer",
                "minimum": 1,
                "maximum": 1000
              },
              "is_complete": {
                "type": "boolean"
              },
              "truncated": {
                "type": "boolean"
              },
              "truncation_reason": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "account_limit",
                  "dialog_limit",
                  null
                ]
              },
              "source": {
                "type": "string",
                "const": "sbc_dialogs"
              },
              "count_unit": {
                "type": "string",
                "const": "dialog_connections"
              },
              "updated_at": {
                "type": "string",
                "format": "date-time"
              },
              "refresh_after_seconds": {
                "type": "integer",
                "const": 20
              }
            }
          }
        }
      },
      "ActiveCall": {
        "type": "object",
        "required": [
          "id",
          "caller",
          "destination",
          "started_at",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "caller": {
            "type": "string"
          },
          "destination": {
            "type": "string"
          },
          "started_at": {
            "type": "string",
            "format": "date-time"
          },
          "status": {
            "type": "string",
            "enum": [
              "Ringing",
              "Connected"
            ]
          }
        }
      },
      "HoursWindow": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "day",
          "start",
          "end"
        ],
        "properties": {
          "day": {
            "type": "integer",
            "minimum": 0,
            "maximum": 6,
            "description": "Sunday 0 to Saturday 6"
          },
          "start": {
            "type": "string",
            "pattern": "^(?:[01][0-9]|2[0-3]):[0-5][0-9]$"
          },
          "end": {
            "type": "string",
            "pattern": "^(?:[01][0-9]|2[0-3]):[0-5][0-9]$"
          }
        }
      },
      "ServiceOptionEdit": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "minimum": 1
          },
          "target": {
            "type": "string",
            "maxLength": 255,
            "description": "E.164 number or SIP address of the existing target type"
          },
          "ring_seconds": {
            "type": "integer",
            "minimum": 5,
            "maximum": 120
          },
          "strategy": {
            "type": "string",
            "enum": [
              "simultaneous",
              "sequential",
              "round_robin"
            ]
          },
          "windows": {
            "type": "array",
            "maxItems": 70,
            "items": {
              "$ref": "#/components/schemas/HoursWindow"
            }
          }
        }
      },
      "ServiceOptionControl": {
        "type": "object",
        "required": [
          "id",
          "kind",
          "label"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "kind": {
            "type": "string",
            "enum": [
              "destination",
              "failover",
              "business_hours"
            ]
          },
          "label": {
            "type": "string"
          },
          "destination_type": {
            "type": "string",
            "enum": [
              "number",
              "sip"
            ]
          },
          "target": {
            "type": "string"
          },
          "ring_seconds": {
            "type": "integer"
          },
          "strategy": {
            "type": "string",
            "enum": [
              "simultaneous",
              "sequential",
              "round_robin"
            ]
          },
          "timezone": {
            "type": "string",
            "description": "IANA service timezone; read-only"
          },
          "windows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HoursWindow"
            }
          }
        }
      },
      "PaginationMeta": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer"
          },
          "per_page": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "description": "Machine-readable code, e.g. number_unavailable, validation_failed"
              },
              "message": {
                "type": "string"
              },
              "details": {
                "type": "object",
                "additionalProperties": true,
                "description": "Field-level validation errors where applicable"
              }
            }
          }
        }
      },
      "ConflictError": {
        "type": "object",
        "description": "Error envelope for 412 configuration_conflict.",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "const": "configuration_conflict"
              },
              "message": {
                "type": "string"
              },
              "details": {
                "type": "object",
                "properties": {
                  "current_revision": {
                    "type": "string",
                    "pattern": "^[a-f0-9]{64}$",
                    "description": "Current revision (a service's config_hash, or the user/account revision)."
                  },
                  "service_id": {
                    "type": "integer",
                    "description": "Service writes only. The service whose revision is stale."
                  },
                  "changed_option_ids": {
                    "type": [
                      "array",
                      "null"
                    ],
                    "items": {
                      "type": "integer"
                    },
                    "description": "Service writes only. Ascending ids of options added, removed or edited since the request's base revision. Null when that revision is no longer in the service history; treat as unknown and reload. Number assignments are not options."
                  },
                  "service_changed": {
                    "type": [
                      "boolean",
                      "null"
                    ],
                    "description": "Service writes only. Whether the service's own fields (name, description, type, template) or its flow graph changed since the base revision; null when unknown."
                  }
                }
              }
            }
          }
        }
      },
      "ConferenceAction": {
        "type": "object",
        "required": [
          "action",
          "fs_uuid"
        ],
        "properties": {
          "action": {
            "type": "string",
            "enum": [
              "list",
              "mute",
              "unmute",
              "deaf",
              "undeaf",
              "kick",
              "hup",
              "kill",
              "dial"
            ],
            "description": "List room members, change speaking/hearing state, remove or hang up a participant, or dial a party into the room. Move, transfer, discovery and conference events are unsupported."
          },
          "fs_uuid": {
            "type": "string",
            "format": "uuid",
            "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$",
            "description": "Full live channel UUID. The server verifies its owning account, node and room membership."
          },
          "member": {
            "type": "string",
            "pattern": "^(?:[1-9][0-9]{0,9}|[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})$",
            "description": "Positive conference member ID or full channel UUID; required for mute/unmute/deaf/undeaf/kick/hup/kill. The server verifies current membership of the requested room before acting."
          },
          "number": {
            "type": "string",
            "maxLength": 255,
            "pattern": "^(?:\\+?[0-9]{1,20}|(?:sip:)?[A-Za-z0-9_.+-]{1,64}@[A-Za-z0-9](?:[A-Za-z0-9.-]*[A-Za-z0-9])?(?::[0-9]{1,5})?)$",
            "description": "Required for dial. 1–20 PSTN digits with optional leading plus, or a conservative sip:user@host/user@host address. SIP user is 1–64 letters, digits or _.+-, host must be a valid DNS hostname or dotted IPv4 address, optional port is 1–65535. No whitespace, command fragments, embedded credentials or URI parameters."
          },
          "cli": {
            "type": "string",
            "pattern": "^\\+?[0-9]{1,20}$",
            "description": "Optional dial presentation CLI, 1–20 digits with optional leading plus; defaults to ddi."
          },
          "ddi": {
            "type": "string",
            "pattern": "^\\+?[0-9]{1,20}$",
            "description": "Dial DDI, 1–20 digits with optional leading plus. Required if the room has no numeric DDI prefix; otherwise derived from that verified room."
          }
        },
        "allOf": [
          {
            "if": {
              "properties": {
                "action": {
                  "enum": [
                    "mute",
                    "unmute",
                    "deaf",
                    "undeaf",
                    "kick",
                    "hup",
                    "kill"
                  ]
                }
              },
              "required": [
                "action"
              ]
            },
            "then": {
              "required": [
                "member"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "action": {
                  "const": "dial"
                }
              },
              "required": [
                "action"
              ]
            },
            "then": {
              "required": [
                "number"
              ]
            }
          }
        ],
        "example": {
          "action": "mute",
          "fs_uuid": "12345678-1234-4234-8234-123456789abc",
          "member": "7"
        }
      }
    },
    "responses": {
      "CallControlUnavailable": {
        "description": "503 conference_unavailable. Required estate call-state, executor credential allowed executor hosts or verified routing context are unavailable or incomplete. No mutating action is dispatched. Operators must verify the estate runtime configuration; sandbox wiring must use isolated test call-state and executor resources.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "AgentEditorConflict": {
        "description": "412 precondition_failed. The portal, provider or reviewed automation state changed. Fetch the corresponding configuration/flow document and review the desired change again before using a new revision and operation key. This is not the service config_hash precondition.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "AgentEditorPending": {
        "description": "409 operation_pending or idempotency_key_in_progress means the reviewed request is still running or a prior publish could not be confirmed; inspect current state before another change. No second provider mutation is issued for that pending operation.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "AgentEditorInvalid": {
        "description": "422 validation_failed for unknown fields, invalid values/operations or a configuration that cannot be compiled safely; configuration_update_unsupported for a draft or unsupported saved flow. idempotency_key_conflict means the API key was reused with a different request body. Protected steps/rules and custom greeting variations must be edited in the portal.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "AgentEditorUnavailable": {
        "description": "503 companion_unavailable. The estate bridge/provider/registry is unavailable or publication could not be confirmed. A PATCH may have changed provider state before readback or persistence failed. There is no automatic retry or rollback across systems. A durable restore point is recorded before external changes and the operation remains pending on uncertain failure. Reuse the exact reviewed key/body; do not issue a new key to repeat an uncertain publication.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "UserPermissionsUnavailable": {
        "description": "User creation is unavailable because the estate could not assign the required portal permission baseline. The user and its permission grants are rolled back; no partial user is created.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "user_permissions_unavailable",
                "message": "User creation is unavailable because the portal permission baseline could not be assigned. Please contact your administrator."
              }
            }
          }
        }
      },
      "PreconditionRequired": {
        "description": "A reviewed service config_hash is required (428 precondition_required).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "PreconditionFailed": {
        "description": "The item changed after review (412 configuration_conflict). Re-read and review before submitting a new change with a new Idempotency-Key. `error.details.current_revision` is the current revision; service writes also report what changed since the request's base revision (see ConflictError) so a reviewed draft can be rebased when its edits do not overlap. Portal-backed users may omit details.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ConflictError"
            }
          }
        }
      },
      "ServiceHistoryUnavailable": {
        "description": "The estate cannot safely record a service version (503 service_history_unavailable).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "MediaUnavailable": {
        "description": "Media storage is not configured for this estate or is temporarily unavailable.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ReportingUnavailable": {
        "description": "Reporting is not configured for this estate or the backend is temporarily unavailable. No MySQL fallback is used.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ReportingBadResponse": {
        "description": "The reporting backend returned a malformed or oversized response. Raw backend errors are never returned.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing, invalid or inactive credentials; token-owner and estate-account state are checked on every request.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Access denied. `api_read_only` means the estate's default-on release\nguard rejected an unsafe authenticated method before scope checks,\nidempotency claims or business handlers; write-scoped tokens do not\nbypass it. `feature_unavailable` means the estate feature is disabled,\nincluding all /media/* and /audio reads when media_reads is false.\nOther causes include insufficient_scope or a service type not enabled\nfor the account. Read /capabilities for configuration, not permission\nto bypass the token's scopes or estate acceptance.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "readOnlyRelease": {
                "summary": "Unsafe method blocked by the estate read-only release guard",
                "value": {
                  "error": {
                    "code": "api_read_only",
                    "message": "This estate API is currently read-only."
                  }
                }
              },
              "mediaOrFeatureDisabled": {
                "summary": "Media reads or another estate feature are disabled",
                "value": {
                  "error": {
                    "code": "feature_unavailable",
                    "message": "This operation is not enabled for this estate. See /v1/capabilities."
                  }
                }
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found (or not within your account hierarchy)",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ValidationError": {
        "description": "Request failed validation",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limit exceeded; retry after the indicated delay",
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "integer"
            },
            "description": "Seconds to wait"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "DestructiveRateLimited": {
        "description": "Too many destructive operations (deletes/releases) in a short period.\nA safety limit caps how many resources can be removed per minute to\nprotect against runaway or accidental bulk deletion; pace the requests\nand retry after the indicated delay. Error code `destructive_rate_limited`.\n",
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "integer"
            },
            "description": "Seconds to wait"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Conflict": {
        "description": "The request conflicts with current state — e.g. a conference member or\nroom targeted by a call-control action is no longer active (`call_ended`).\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "BadGateway": {
        "description": "The upstream node could not be reached or errored while executing the\naction (`node_unreachable`) — e.g. the FreeSWITCH node's :5001 executor\nis down or blocked by a security group.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  },
  "x-source-sha256": "48c69286dd60d57d0204cdc1f2b56e86d904b063e7f2ea59ee9934383e4a2c49"
}
