{
  "openapi": "3.1.0",
  "info": {
    "title": "DialStack API",
    "version": "1.0.0",
    "description": "DialStack — Business Voice for Vertical SaaS\n\n## Authentication\nDialStack supports three authentication methods:\n\n### Platform API Keys (Backend)\nFor server-side integrations, use your secret API key (starts with `sk_live_`) in the Authorization header.\n\nExample: `Authorization: Bearer sk_live_YOUR_SECRET_KEY`\n\n### Session Tokens (Embedded Components)\nFor embedded voice components in your frontend, create a session using the Account Session API\nand use the client_secret JWT token in the Authorization header.\n\nExample: `Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...`\n\nSessions are account-scoped and expire after 1 hour.\n\n### User Tokens (Softphones & User-Facing Apps)\nFor client-side applications where end users interact directly (softphones, call history,\nvoicemail), authenticate users via `POST /v1/user_sessions` and use the returned user token.\n\nExample: `Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...`\n\nUser tokens are scoped to a single user within an account and grant access to the WebRTC\nsignalling channel and user-scoped REST endpoints such as emergency addresses. See the\n[Authentication guide](/guides/authentication#user-tokens) for setup details.\n\n## Account Context\nMost API endpoints require an account context. This is specified differently depending on the authentication method:\n\n### Platform API Keys\nInclude the `DialStack-Account` header with the account ID:\n```\nDialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41\n```\n\n### Session Tokens\nThe account is automatically derived from the JWT claims. No header is needed.\n\n## Pagination\nAll list API methods support URL-based cursor pagination. Results are returned in reverse chronological order.\n\n### Request Parameters\n- `limit` - Number of objects to return (1-100, default 10)\n- `page` - Opaque cursor token (only used when following pagination URLs)\n\n### Response Structure\nList responses include:\n- `object` - Always \"list\"\n- `url` - The endpoint URL\n- `next_page_url` - URL to fetch the next page (null if no more pages)\n- `previous_page_url` - URL to fetch the previous page (null if on first page)\n- `data` - Array of objects\n\n### Usage\nTo paginate, simply follow the URLs provided in `next_page_url` and `previous_page_url`.\nDo not construct pagination URLs manually - the cursor format is opaque and may change.\n\n## Expanding Responses\nSome endpoints support the `expand[]` parameter to include related resources inline.\nWithout expansion, the related data is omitted from the response.\n\nFor example, to include extensions when listing users:\n```\nGET /v1/users?expand[]=extensions\n```\n\nThe expanded field appears as a nested list object:\n```json\n{\n  \"id\": \"user_01h2xcejqtf2nbrexx3vqjhp42\",\n  \"name\": \"Dr. Alice Smith\",\n  \"extensions\": {\n    \"object\": \"list\",\n    \"data\": [\n      {\n        \"number\": \"105\",\n        \"target\": \"user_01h2xcejqtf2nbrexx3vqjhp42\",\n        \"status\": \"active\",\n        \"created_at\": \"2025-10-18T10:00:00Z\",\n        \"updated_at\": \"2025-10-18T10:00:00Z\"\n      }\n    ]\n  }\n}\n```\n\nExpandable fields are noted in endpoint descriptions.\n\n## Base URL\n- `https://api.dialstack.ai`\n\n## Voice Apps\nFor building programmable voice applications with webhooks and real-time audio streaming,\nsee the [Voice Apps Guide](/guides/voice-apps).\n\n## Routing Targets\nA **routing target** is a resource that can receive calls. The following resource\ntypes are valid routing targets:\n- **User** — rings all of the user's registered devices (desk phones, softphones)\n- **Voice App** — delivers the call via webhook notification for programmatic control or monitoring\n- **Dial Plan** — routes the call through a dial plan graph\n- **Ring Group** — rings all group members simultaneously\n- **Shared Voicemail** — sends the call directly to a shared voicemail box\n\n## Resource IDs\nAll resource IDs in the API are opaque strings of at most 255 characters.\nDo not parse or make assumptions about their format — treat them as identifiers\nto store and pass back to the API.\n",
    "contact": {
      "name": "DialStack API Support",
      "email": "info@dialstack.ai",
      "url": "https://docs.dialstack.ai/api"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://dialstack.ai/terms"
    }
  },
  "servers": [
    {
      "url": "https://api.dialstack.ai"
    }
  ],
  "security": [
    {
      "BearerAuth": []
    },
    {
      "SessionAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "sk_live_*",
        "description": "Platform secret API key (starts with sk_live_) for server-side integrations.\nInclude in Authorization header:\n`Authorization: Bearer sk_live_YOUR_SECRET_KEY`\n\nFor account-scoped operations, also include the `DialStack-Account` header.\n"
      },
      "SessionAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Account session JWT token for embedded components.\nCreate a session using POST /v1/account_sessions\nand use the client_secret JWT in the Authorization header:\n`Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...`\n\nSessions are account-scoped and expire after 1 hour.\nThe account context is automatically derived from the JWT claims.\n\nNote: Session tokens cannot be used to create new sessions.\n"
      },
      "UserAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "User token for softphones and user-facing applications.\nObtain a token via POST /v1/user_sessions and include it in the Authorization header:\n`Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...`\n\nUser tokens are scoped to a single user within an account.\nThey grant access to the WebRTC signalling channel and user-scoped\nREST endpoints (/v1/me/*). They cannot access platform-level endpoints.\n\nTokens expire after the TTL requested at mint time (default 24 hours).\nTo extend access, mint a new session via POST /v1/user_sessions.\n"
      }
    },
    "parameters": {
      "DialStackAccount": {
        "name": "DialStack-Account",
        "in": "header",
        "required": true,
        "description": "Account identifier for API key authentication.\nNot required when using session tokens (account is derived from JWT).\n",
        "schema": {
          "type": "string",
          "example": "acct_01h2xcejqtf2nbrexx3vqjhp41"
        }
      },
      "DialStackAccountOptional": {
        "name": "DialStack-Account",
        "in": "header",
        "required": false,
        "description": "Optional account identifier. When omitted, the operation applies to\nplatform-global resources; when supplied, it applies to that account's\nresources. Used by endpoints that are platform-global by default but can\nbe scoped to a single account (e.g. webhook endpoints).\n",
        "schema": {
          "type": "string",
          "example": "acct_01h2xcejqtf2nbrexx3vqjhp41"
        }
      },
      "AccountId": {
        "name": "account_id",
        "in": "path",
        "required": true,
        "description": "Account identifier",
        "schema": {
          "type": "string",
          "example": "acct_01h2xcejqtf2nbrexx3vqjhp41"
        }
      },
      "UserId": {
        "name": "user_id",
        "in": "path",
        "required": true,
        "description": "User identifier",
        "schema": {
          "type": "string",
          "example": "user_01h2xcejqtf2nbrexx3vqjhp42"
        }
      },
      "AdminUserId": {
        "name": "admin_user",
        "in": "path",
        "required": true,
        "description": "Admin portal user identifier",
        "schema": {
          "type": "string",
          "example": "admin_user_01h2xcejqtf2nbrexx3vqjhp43"
        }
      },
      "VoicemailId": {
        "name": "voicemail_id",
        "in": "path",
        "required": true,
        "description": "Voicemail identifier",
        "schema": {
          "type": "string",
          "example": "vm_01h2xcejqtf2nbrexx3vqjhp44"
        }
      },
      "VoiceAppId": {
        "name": "voice_app_id",
        "in": "path",
        "required": true,
        "description": "Voice app identifier",
        "schema": {
          "type": "string",
          "example": "va_01h2xcejqtf2nbrexx3vqjhp49"
        }
      },
      "AIAgentId": {
        "name": "ai_agent_id",
        "in": "path",
        "required": true,
        "description": "AI agent identifier",
        "schema": {
          "type": "string",
          "example": "aia_01h2xcejqtf2nbrexx3vqjhp60"
        }
      },
      "ScheduleId": {
        "name": "schedule_id",
        "in": "path",
        "required": true,
        "description": "Schedule identifier",
        "schema": {
          "type": "string",
          "example": "sched_01h2xcejqtf2nbrexx3vqjhp50"
        }
      },
      "RingGroupId": {
        "name": "ring_group_id",
        "in": "path",
        "required": true,
        "description": "Ring group identifier",
        "schema": {
          "type": "string",
          "example": "rg_01h2xcejqtf2nbrexx3vqjhp51"
        }
      },
      "RingGroupMemberId": {
        "name": "member_id",
        "in": "path",
        "required": true,
        "description": "Ring group member identifier",
        "schema": {
          "type": "string",
          "example": "rgm_01h2xcejqtf2nbrexx3vqjhp52"
        }
      },
      "QueueId": {
        "name": "queue_id",
        "in": "path",
        "required": true,
        "description": "Call queue identifier",
        "schema": {
          "type": "string",
          "example": "qu_01h2xcejqtf2nbrexx3vqjhp61"
        }
      },
      "QueueMemberId": {
        "name": "member_id",
        "in": "path",
        "required": true,
        "description": "Queue member identifier",
        "schema": {
          "type": "string",
          "example": "qum_01h2xcejqtf2nbrexx3vqjhp62"
        }
      },
      "SharedVoicemailBoxId": {
        "name": "shared_voicemail_box_id",
        "in": "path",
        "required": true,
        "description": "Shared voicemail box identifier",
        "schema": {
          "type": "string",
          "example": "svm_01h2xcejqtf2nbrexx3vqjhp60"
        }
      },
      "AudioClipId": {
        "name": "audio_clip_id",
        "in": "path",
        "required": true,
        "description": "Audio clip identifier",
        "schema": {
          "type": "string"
        }
      },
      "FaxId": {
        "name": "fax",
        "in": "path",
        "required": true,
        "description": "Fax identifier",
        "schema": {
          "type": "string",
          "example": "fax_01h2xcejqtf2nbrexx3vqjhp60"
        }
      },
      "ExtensionNumber": {
        "name": "number",
        "in": "path",
        "required": true,
        "description": "Extension number (dial code)",
        "schema": {
          "type": "string",
          "example": "105"
        }
      },
      "ExtensionTargetFilter": {
        "name": "target",
        "in": "query",
        "required": false,
        "description": "Filter extensions by routing target ID",
        "schema": {
          "type": "string",
          "maxLength": 255,
          "example": "user_01h2xcejqtf2nbrexx3vqjhp42"
        }
      },
      "CallId": {
        "name": "call_id",
        "in": "path",
        "required": true,
        "description": "Call log identifier",
        "schema": {
          "type": "string",
          "example": "call_01h2xcejqtf2nbrexx3vqjhp45"
        }
      },
      "ListenerId": {
        "name": "listener_id",
        "in": "path",
        "required": true,
        "description": "Listener identifier",
        "schema": {
          "type": "string",
          "example": "lstn_01h2xcejqtf2nbrexx3vqjhp50"
        }
      },
      "OrderId": {
        "name": "order_id",
        "in": "path",
        "required": true,
        "description": "Phone number order identifier",
        "schema": {
          "type": "string",
          "example": "nord_01h2xcejqtf2nbrexx3vqjhp47"
        }
      },
      "PortOrderId": {
        "name": "order_id",
        "in": "path",
        "required": true,
        "description": "Port order identifier",
        "schema": {
          "type": "string",
          "example": "por_01h2xcejqtf2nbrexx3vqjhp53"
        }
      },
      "PhoneNumberId": {
        "name": "phone_number_id",
        "in": "path",
        "required": true,
        "description": "Phone number identifier",
        "schema": {
          "type": "string",
          "example": "did_01h2xcejqtf2nbrexx3vqjhp46"
        }
      },
      "PhoneNumberStatus": {
        "name": "status",
        "in": "query",
        "required": false,
        "description": "Filter by phone number status",
        "schema": {
          "type": "string",
          "enum": [
            "active",
            "inactive",
            "pending",
            "released"
          ],
          "example": "active"
        }
      },
      "NumberOrderStatus": {
        "name": "status",
        "in": "query",
        "required": false,
        "description": "Filter by order status",
        "schema": {
          "type": "string",
          "enum": [
            "pending",
            "complete",
            "partial",
            "failed"
          ]
        }
      },
      "NumberOrderType": {
        "name": "order_type",
        "in": "query",
        "required": false,
        "description": "Filter by order type",
        "schema": {
          "type": "string",
          "enum": [
            "order",
            "disconnect"
          ]
        }
      },
      "LocationId": {
        "name": "location_id",
        "in": "path",
        "required": true,
        "description": "Location identifier",
        "schema": {
          "type": "string",
          "example": "loc_01h2xcejqtf2nbrexx3vqjhp50"
        }
      },
      "LocationStatus": {
        "name": "status",
        "in": "query",
        "required": false,
        "deprecated": true,
        "description": "Deprecated. The operational-status field was retired; the filter is\naccepted for backwards compatibility but no longer narrows results.\n",
        "schema": {
          "type": "string",
          "enum": [
            "active",
            "inactive"
          ],
          "example": "active"
        }
      },
      "DeviceLineId": {
        "name": "line_id",
        "in": "path",
        "required": true,
        "description": "Device line identifier",
        "schema": {
          "type": "string",
          "example": "dln_01h2xcejqtf2nbrexx3vqjhp55"
        }
      },
      "ButtonTemplateId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Button template identifier",
        "schema": {
          "type": "string",
          "example": "btpl_01h2xcejqtf2nbrexx3vqjhp70"
        }
      },
      "ButtonId": {
        "name": "button_id",
        "in": "path",
        "required": true,
        "description": "Template button identifier",
        "schema": {
          "type": "string",
          "example": "btn_01h2xcejqtf2nbrexx3vqjhp71"
        }
      },
      "ButtonOverrideId": {
        "name": "override_id",
        "in": "path",
        "required": true,
        "description": "Device button override identifier",
        "schema": {
          "type": "string",
          "example": "devbtn_01h2xcejqtf2nbrexx3vqjhp72"
        }
      },
      "DeviceTypeFilter": {
        "name": "type",
        "in": "query",
        "required": false,
        "description": "Filter devices by type",
        "schema": {
          "type": "string",
          "enum": [
            "deskphone",
            "dect_base",
            "dect_handset"
          ]
        }
      },
      "PortOrderStatus": {
        "name": "status",
        "in": "query",
        "required": false,
        "description": "Filter by port order status",
        "schema": {
          "type": "string",
          "enum": [
            "draft",
            "approved",
            "submitted",
            "exception",
            "foc",
            "complete",
            "cancelled"
          ]
        }
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "description": "Number of objects to return.\nDefaults to 10. Maximum is 100.\n",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 10,
          "example": 10
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Unauthorized",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Account does not belong to this platform",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "AccountNotFound": {
        "description": "Account not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "UserNotFound": {
        "description": "User not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "VoicemailNotFound": {
        "description": "Voicemail not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "CallNotFound": {
        "description": "Call log not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ListenerNotFound": {
        "description": "Listener not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "CallNotActive": {
        "description": "Call is not in a state that supports listeners (e.g., still ringing, already ended)",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TranscriptNotFound": {
        "description": "Transcript not found (no recording exists for this call)",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RecordingNotFound": {
        "description": "Recording not found (no recording exists for this call)",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "VoiceAppNotFound": {
        "description": "Voice app not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "AccountDeleted": {
        "description": "Account deleted successfully"
      },
      "UserDeleted": {
        "description": "User deleted successfully"
      },
      "VoicemailDeleted": {
        "description": "Voicemail deleted successfully"
      },
      "VoiceAppDeleted": {
        "description": "Voice app deleted successfully"
      },
      "AIAgentNotFound": {
        "description": "AI agent not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "AIAgentDeleted": {
        "description": "AI agent deleted successfully"
      },
      "ScheduleNotFound": {
        "description": "Schedule not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ScheduleDeleted": {
        "description": "Schedule deleted successfully"
      },
      "DialPlanNotFound": {
        "description": "Dial plan not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "DialPlanDeleted": {
        "description": "Dial plan deleted successfully"
      },
      "RoutingLoop": {
        "description": "Validation error — routing loop, AI-agent voice app referenced from a\n`notify`-mode `voice_app` node, or other dial-plan constraint violation.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "routing loop detected: rg_01h2x... → dp_01h2x... → rg_01h2x..."
            }
          }
        }
      },
      "ExtensionNotFound": {
        "description": "Extension not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ExtensionDeleted": {
        "description": "Extension deleted successfully"
      },
      "ExtensionConflict": {
        "description": "Extension number already exists in this account",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "DialPlanConflict": {
        "description": "Dial plan cannot be deleted because it is referenced by an extension",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RingGroupNotFound": {
        "description": "Ring group not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RingGroupMemberNotFound": {
        "description": "Ring group member not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RingGroupDeleted": {
        "description": "Ring group deleted successfully"
      },
      "RingGroupMemberDeleted": {
        "description": "Ring group member removed successfully"
      },
      "RingGroupConflict": {
        "description": "Ring group cannot be deleted because it is referenced by an extension",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "QueueNotFound": {
        "description": "Queue not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "QueueMemberNotFound": {
        "description": "Queue member not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "QueueDeleted": {
        "description": "Queue deleted successfully"
      },
      "QueueMemberDeleted": {
        "description": "Queue member removed successfully"
      },
      "QueueMemberConflict": {
        "description": "User is already a member of this queue",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "QueueValidationFailed": {
        "description": "Request body is well-formed but references state that prevents the change.\nExamples:\n- Timeout target not found in this account.\n- Adding the queue would form a routing loop through ring groups, dial plans,\n  or other queues.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "AudioClipNotFound": {
        "description": "Audio clip not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "AudioClipDeleted": {
        "description": "Audio clip deleted successfully"
      },
      "FaxNotFound": {
        "description": "Fax not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "FaxDeleted": {
        "description": "Fax deleted successfully"
      },
      "SharedVoicemailBoxNotFound": {
        "description": "Shared voicemail box not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "SharedVoicemailBoxDeleted": {
        "description": "Shared voicemail box deleted successfully"
      },
      "SharedVoicemailBoxConflict": {
        "description": "Shared voicemail box cannot be deleted because it is referenced by an extension",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "PhoneNumberNotFound": {
        "description": "Phone number not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NumberOrderNotFound": {
        "description": "Number order not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "LocationNotFound": {
        "description": "Location not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "PortOrderNotFound": {
        "description": "Port order not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "LocationDeleted": {
        "description": "Location deleted successfully"
      },
      "DeviceNotFound": {
        "description": "Device not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "DeviceLineNotFound": {
        "description": "Device line not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ButtonTemplateNotFound": {
        "description": "Button template not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ButtonOverrideNotFound": {
        "description": "Button override not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "DeviceDeleted": {
        "description": "Device deleted successfully"
      },
      "DeviceLineDeleted": {
        "description": "Device line deleted successfully"
      },
      "DocumentNotFound": {
        "description": "Document not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "HardwareOrderNotFound": {
        "description": "Hardware order not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Conflict": {
        "description": "Conflict with current state of the resource",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "InternalServerError": {
        "description": "Internal server error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "BadGateway": {
        "description": "Upstream provider error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "IceServersResponse": {
        "type": "object",
        "required": [
          "ice_servers",
          "expires_at"
        ],
        "properties": {
          "ice_servers": {
            "type": "array",
            "description": "List of ICE server configurations for WebRTC peer connections",
            "items": {
              "$ref": "#/components/schemas/IceServer"
            }
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the TURN credentials expire. Fetch new credentials before this time."
          }
        }
      },
      "IceServer": {
        "type": "object",
        "required": [
          "urls"
        ],
        "properties": {
          "urls": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "STUN or TURN server URL(s). Always an array, even for a single URL, matching `RTCIceServer.urls` in the W3C WebRTC spec.",
            "examples": [
              [
                "stun:stun.dialstack.ai:3478"
              ],
              [
                "turn:turn.dialstack.ai:443?transport=tcp"
              ]
            ]
          },
          "username": {
            "type": "string",
            "description": "TURN username (not present for STUN servers)"
          },
          "credential": {
            "type": "string",
            "description": "TURN credential (not present for STUN servers)"
          }
        }
      },
      "WebPushKeyResponse": {
        "type": "object",
        "required": [
          "vapid_public_key"
        ],
        "properties": {
          "vapid_public_key": {
            "type": "string",
            "description": "The public key the browser subscribes with, as base64url. Pass it to\n`pushManager.subscribe` as `applicationServerKey`.\n"
          }
        }
      },
      "CreatePushSubscriptionRequest": {
        "type": "object",
        "required": [
          "endpoint",
          "keys"
        ],
        "properties": {
          "endpoint": {
            "type": "string",
            "description": "The browser Web Push destination URL (the `endpoint` of a browser\n`PushSubscription`). This is where the wake notification is sent.\n"
          },
          "keys": {
            "type": "object",
            "required": [
              "p256dh",
              "auth"
            ],
            "description": "The subscription's encryption keys, used to encrypt the wake payload end-to-end to the browser.",
            "properties": {
              "p256dh": {
                "type": "string",
                "description": "The subscription's P-256 ECDH public key (base64url)."
              },
              "auth": {
                "type": "string",
                "description": "The subscription's authentication secret (base64url)."
              }
            }
          }
        }
      },
      "PushSubscription": {
        "type": "object",
        "required": [
          "id",
          "endpoint",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Push subscription identifier"
          },
          "endpoint": {
            "type": "string",
            "description": "The browser Web Push destination URL this subscription wakes."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the subscription was registered."
          }
        }
      },
      "UserProfile": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "User identifier"
          },
          "name": {
            "type": "string",
            "description": "User's display name"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "User's email address"
          },
          "account": {
            "type": "string",
            "description": "Account the user belongs to"
          },
          "extensions": {
            "type": "array",
            "description": "User's assigned extension dial codes",
            "items": {
              "type": "object",
              "properties": {
                "number": {
                  "type": "string",
                  "description": "Extension dial code"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "active",
                    "inactive"
                  ]
                }
              }
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PresenceStatus": {
        "type": "object",
        "required": [
          "status"
        ],
        "properties": {
          "user": {
            "type": "string",
            "description": "User identifier"
          },
          "status": {
            "type": "string",
            "enum": [
              "available",
              "on_call",
              "dnd",
              "away",
              "offline"
            ],
            "description": "Current presence status:\n- `available` — user is online and can receive calls\n- `on_call` — user is currently on an active call\n- `dnd` — user has enabled Do Not Disturb\n- `away` — user is away (idle timeout or manual)\n- `offline` — no active WebRTC or SIP registration\n"
          },
          "status_text": {
            "type": [
              "string",
              "null"
            ],
            "description": "Optional custom status message"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the presence status last changed"
          }
        }
      },
      "PresenceUpdateRequest": {
        "type": "object",
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "available",
              "dnd",
              "away"
            ],
            "description": "Desired presence status (cannot set `on_call` or `offline` manually)"
          },
          "status_text": {
            "type": [
              "string",
              "null"
            ],
            "description": "Optional custom status message (max 100 characters)"
          }
        }
      },
      "DirectoryEntry": {
        "type": "object",
        "description": "One member of the account directory, projected to only the fields a\ndirectory listing needs — never a full user object.\n",
        "required": [
          "user",
          "display_name"
        ],
        "properties": {
          "user": {
            "type": "string",
            "description": "Identifier of a colleague in the caller's account."
          },
          "display_name": {
            "type": "string",
            "description": "The member's display name, suitable for a contact-list label. Falls\nback to the user identifier when the member has no name set.\n"
          }
        }
      },
      "EmergencyAddress": {
        "type": "object",
        "description": "A registered emergency (E911) address resource.",
        "required": [
          "id",
          "address",
          "registered_ip",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the emergency address.",
            "examples": [
              "emerg_01h2xcejqtf2nbrexx3vqjhp42"
            ]
          },
          "address": {
            "$ref": "#/components/schemas/EmergencyAddressDetails"
          },
          "registered_ip": {
            "type": [
              "string",
              "null"
            ],
            "description": "The network this address is bound to, or null when it has not yet\nbeen registered from a softphone session. Set automatically when a\nsoftphone presents this address on connect; cleared with\n`DELETE /v1/me/emergency-addresses/{emergency_address_id}/registered_ip`.\n"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "EmergencyAddressDetails": {
        "type": "object",
        "description": "Normalized civic address fields.",
        "required": [
          "city",
          "state",
          "postal_code",
          "country"
        ],
        "properties": {
          "address_number": {
            "type": "string",
            "description": "House or building number.",
            "examples": [
              "123"
            ]
          },
          "street": {
            "type": "string",
            "examples": [
              "Main St"
            ]
          },
          "unit": {
            "type": "string",
            "description": "Suite, floor, apartment, or room number.",
            "examples": [
              "Suite 400"
            ]
          },
          "city": {
            "type": "string",
            "examples": [
              "San Francisco"
            ]
          },
          "state": {
            "type": "string",
            "description": "Two-letter state/province code.",
            "examples": [
              "CA"
            ]
          },
          "postal_code": {
            "type": "string",
            "examples": [
              "94105"
            ]
          },
          "country": {
            "type": "string",
            "description": "Two-letter country code (ISO 3166-1 alpha-2).",
            "examples": [
              "US"
            ]
          },
          "formatted_address": {
            "type": "string",
            "description": "Human-readable single-line address."
          },
          "latitude": {
            "type": "number"
          },
          "longitude": {
            "type": "number"
          }
        }
      },
      "EmergencyAddressRequest": {
        "type": "object",
        "description": "Civic address to register. Validated before it is stored.",
        "required": [
          "street",
          "city",
          "state",
          "postal_code"
        ],
        "properties": {
          "address_number": {
            "type": "string",
            "description": "House or building number."
          },
          "street": {
            "type": "string"
          },
          "unit": {
            "type": "string",
            "description": "Suite, floor, apartment, or room number."
          },
          "city": {
            "type": "string"
          },
          "state": {
            "type": "string",
            "description": "Two-letter state/province code."
          },
          "postal_code": {
            "type": "string"
          },
          "country": {
            "type": "string",
            "description": "Two-letter country code (ISO 3166-1 alpha-2). Defaults to US."
          }
        }
      },
      "HardwareCatalogItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Hardware catalog item ID"
          },
          "manufacturer": {
            "type": "string",
            "description": "Hardware manufacturer",
            "example": "SNOM"
          },
          "model": {
            "type": "string",
            "description": "Product model name",
            "example": "M500"
          },
          "sku": {
            "type": [
              "string",
              "null"
            ],
            "description": "Stock-keeping unit identifier"
          },
          "device_type": {
            "type": "string",
            "enum": [
              "deskphone",
              "dect_base",
              "dect_handset",
              "accessory"
            ],
            "description": "Type of item. `accessory` is a non-provisioned add-on (e.g. a power supply) that ships with an order but never becomes a device."
          },
          "active": {
            "type": "boolean",
            "description": "Whether the item is available for selection"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "HardwareOrder": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Hardware order ID"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "submitted",
              "approved",
              "rejected",
              "fulfilled",
              "cancelled"
            ],
            "description": "Order lifecycle status. Orders are created as `submitted`, become `approved` after review, and `fulfilled` once delivered. `rejected` (declined at review) and `cancelled` are terminal."
          },
          "rejection_reason": {
            "type": [
              "string",
              "null"
            ],
            "description": "Reason the order was declined at review. Only set when status is `rejected`."
          },
          "items": {
            "type": "array",
            "description": "Line items in the order",
            "items": {
              "$ref": "#/components/schemas/HardwareOrderItem"
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "HardwareOrderItem": {
        "type": "object",
        "description": "A single physical unit on a hardware order. Requests speak quantity; responses expose one item per unit — aggregate client-side for display.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Hardware order item ID"
          },
          "user": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pre-assignment intent — the user this unit is destined for. Null when unassigned."
          },
          "location": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pre-staging intent — the physical location this unit is destined for. Null when not set."
          },
          "base_item": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pre-pairing intent (handsets only) — the ordered base unit this handset will pair with. Auto-set when the order has exactly one base; null otherwise."
          },
          "device": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "$ref": "#/components/schemas/Device"
              },
              {
                "type": "null"
              }
            ],
            "readOnly": true,
            "description": "The device this unit materialized into at fulfillment. By default\nthis is the device's id; when `expand[]=items.device` is requested\nit is the full device object, which carries its own `type`\n(`deskphone`, `dect_base`, `dect_handset`) and identity\n(`mac_address` / `ipei`). Null until the unit is fulfilled.\n"
          },
          "fulfilled_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "readOnly": true,
            "description": "When this unit was fulfilled into a device. Null until fulfilled."
          },
          "hardware_catalog": {
            "$ref": "#/components/schemas/HardwareCatalogItem"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "HardwareOrderRequest": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "object",
              "required": [
                "hardware_catalog",
                "quantity"
              ],
              "properties": {
                "hardware_catalog": {
                  "type": "string",
                  "description": "ID of the hardware catalog item"
                },
                "quantity": {
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 100
                }
              }
            }
          }
        }
      },
      "AccountPricing": {
        "type": "object",
        "required": [
          "per_user_rate",
          "per_did_rate",
          "per_voiceai_location_rate"
        ],
        "properties": {
          "per_user_rate": {
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000,
            "description": "Agreed retail price per user seat, per month, in cents."
          },
          "per_did_rate": {
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000,
            "description": "Agreed retail price per phone number, per month, in cents."
          },
          "per_voiceai_location_rate": {
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000,
            "description": "Agreed retail price per VoiceAI-enabled location, per month, in cents."
          }
        }
      },
      "AccountPricingRequest": {
        "type": "object",
        "required": [
          "per_user_rate",
          "per_did_rate",
          "per_voiceai_location_rate"
        ],
        "properties": {
          "per_user_rate": {
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000,
            "description": "Agreed retail price per user seat, per month, in cents"
          },
          "per_did_rate": {
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000,
            "description": "Agreed retail price per phone number, per month, in cents"
          },
          "per_voiceai_location_rate": {
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000,
            "description": "Agreed retail price per VoiceAI-enabled location, per month, in cents"
          }
        }
      },
      "TosAcceptance": {
        "type": "object",
        "description": "A recorded acceptance of the subscription agreement. Captures the\nevidence of acceptance (timestamp, IP address, user agent) together with\na snapshot of the pricing agreed to, so consent is provable against the\nspecific price shown even if pricing later changes.\n",
        "properties": {
          "accepted_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the agreement was accepted."
          },
          "ip": {
            "type": "string",
            "description": "IP address of the client that recorded the acceptance — the account\nowner's browser for in-portal acceptance, or your integration's\nbackend when your platform accepts on the owner's behalf via API.\n"
          },
          "user_agent": {
            "type": "string",
            "description": "User agent of the client that recorded the acceptance — the account\nowner's browser for in-portal acceptance, or your integration's\nclient when your platform accepts on the owner's behalf via API.\n"
          },
          "pricing": {
            "$ref": "#/components/schemas/AccountPricing"
          }
        },
        "required": [
          "accepted_at",
          "ip",
          "pricing"
        ]
      },
      "Tos": {
        "type": "object",
        "description": "The account's subscription-agreement resource — the current agreement\ndocument plus the account's acceptance state. The agreed pricing is\nincluded only when requested via `expand[]=pricing`.\n",
        "required": [
          "version",
          "url",
          "content",
          "body",
          "acceptance"
        ],
        "properties": {
          "version": {
            "type": "string",
            "description": "Version identifier of the agreement currently in effect (date-based, `YYYY-MM-DD`; it is also the effective date). Echo it back in the acceptance request so the server can reject acceptance of stale text."
          },
          "url": {
            "type": "string",
            "description": "Canonical URL of the full agreement."
          },
          "content": {
            "type": "string",
            "description": "Short affirmation the customer ticks to accept (the clickwrap checkbox label, including the 911/E911 acknowledgement)."
          },
          "body": {
            "type": "string",
            "description": "Full agreement text (HTML) shown to the customer. Render this as the agreement body; `content` is the short affirmation that accompanies it."
          },
          "acceptance": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/TosAcceptance"
              },
              {
                "type": "null"
              }
            ],
            "description": "The current acceptance, or null if the account has not accepted."
          },
          "pricing": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/AccountPricing"
              },
              {
                "type": "null"
              }
            ],
            "description": "The account's agreed pricing. Included only when `expand[]=pricing` is requested; null when pricing has not been set."
          }
        }
      },
      "TosAcceptanceRequest": {
        "type": "object",
        "required": [
          "version"
        ],
        "properties": {
          "version": {
            "type": "string",
            "description": "The agreement version being accepted; must match the current version. The evidence of acceptance (timestamp, IP, user agent) and its provenance are derived server-side from the request and authenticated actor, not supplied here."
          }
        }
      },
      "EntityId": {
        "type": "string",
        "description": "Unique identifier",
        "example": "acct_01h2xcejqtf2nbrexx3vqjhp41"
      },
      "EntityName": {
        "type": [
          "string",
          "null"
        ],
        "minLength": 1,
        "maxLength": 255,
        "description": "Display name",
        "example": "Spineline"
      },
      "CreatedAt": {
        "type": "string",
        "format": "date-time",
        "description": "Timestamp when it was created",
        "example": "2025-10-17T14:30:00Z"
      },
      "UpdatedAt": {
        "type": "string",
        "format": "date-time",
        "description": "Timestamp when it was last updated",
        "example": "2025-10-17T14:30:00Z"
      },
      "ClientSecret": {
        "type": "string",
        "description": "JWT token for account-scoped authentication",
        "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50X2lkIjoiYWNjdF8wMWgyeGNlanF0ZjJuYnJleHgzdnFqaHA0MSIsImp0aSI6IjAxaDJ4Y2VqcXRmMm5icmV4eDN2cWpocDQ2IiwiZXhwIjoxNzI2NzU3MjAwfQ.1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0t1u2"
      },
      "SessionExpiresAt": {
        "type": "string",
        "format": "date-time",
        "description": "When the session expires",
        "example": "2025-11-13T15:00:00Z"
      },
      "ListObject": {
        "type": "string",
        "enum": [
          "list"
        ],
        "description": "String representing the object's type. Always \"list\" for list responses."
      },
      "ListUrl": {
        "type": "string",
        "description": "The URL for accessing this list.",
        "example": "/v1/accounts"
      },
      "NextPageUrl": {
        "type": [
          "string",
          "null"
        ],
        "description": "URL to fetch the next page of results. If `null`, there are no more pages.\nThe URL includes all necessary parameters including the pagination cursor.\n",
        "example": "/v1/accounts?page=eyJzdGFydGluZ19hZnRlciI6ImFjY3RfMDFoMnhjZWpxdGYybmJyZXh4M3ZxamhwNDEiLCJsaW1pdCI6MTB9"
      },
      "PreviousPageUrl": {
        "type": [
          "string",
          "null"
        ],
        "description": "URL to fetch the previous page of results. If `null`, this is the first page.\nThe URL includes all necessary parameters including the pagination cursor.\n",
        "example": "/v1/accounts?page=eyJlbmRpbmdfYmVmb3JlIjoiYWNjdF8wMWgyeGNlanF0ZjJuYnJleHgzdnFqaHA0MSIsImxpbWl0IjoxMH0"
      },
      "Account": {
        "type": "object",
        "description": "A customer organization of a vSaaS platform (e.g., Jones Chiropractic using Spineline)",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              }
            ]
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "format": "email",
            "description": "Email address for the account (optional)",
            "example": "contact@example.com"
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Company or organization name",
            "example": "Acme Corp"
          },
          "phone": {
            "type": [
              "string",
              "null"
            ],
            "description": "Phone number in E.164 format",
            "example": "+12125550100"
          },
          "primary_contact_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Name of the primary contact",
            "example": "Jane Doe"
          },
          "config": {
            "$ref": "#/components/schemas/AccountConfig"
          },
          "default_outbound_did": {
            "type": [
              "string",
              "null"
            ],
            "description": "ID of the phone number to use as the default outbound caller ID. When null, the first outbound-enabled number is used."
          },
          "hold_music_clip": {
            "type": [
              "string",
              "null"
            ],
            "description": "ID of an audio clip on the account played in a loop to held callers\n(regular SIP hold, parking, queue wait). When null, callers hear the\nplatform default hold music.\n"
          },
          "main_location": {
            "type": [
              "string",
              "null"
            ],
            "description": "ID of the account's main location — the fallback used for any user\nor phone number that doesn't have a specific location of its own.\nA user with no device (e.g., WebRTC-only) is considered roaming and\nresolves to this location; a phone number not tied to a specific\nlocation is similarly roaming. Used to determine tax\njurisdiction and regulatory fees for roaming users and numbers.\nE911 dispatch uses per-device location, not this field. Created from\nthe address supplied to POST /v1/accounts and swappable via\nPOST /v1/accounts/{account_id}. Cannot be cleared once set — only a\nswap to another active location is accepted. Null only for legacy\naccounts created before main locations were seeded at creation (and\nnot yet backfilled).\n"
          },
          "default_button_template": {
            "type": [
              "string",
              "null"
            ],
            "description": "ID of the account's default button template. Compatible deskphones\nand DECT handsets created after this is set inherit it at creation\ntime; existing devices are not changed retroactively. Null when the\naccount has no default.\n"
          },
          "provisioning_base_url": {
            "type": [
              "string",
              "null"
            ],
            "readOnly": true,
            "description": "The full provisioning base URL for this account. Phones use this URL prefix for auto-provisioning configuration files.",
            "example": "https://prov.netvoice.io/a/abc12345"
          },
          "billing_address": {
            "deprecated": true,
            "oneOf": [
              {
                "$ref": "#/components/schemas/Address"
              },
              {
                "type": "null"
              }
            ],
            "description": "Deprecated. The account's stored address snapshot, kept for backwards compatibility. The authoritative address now lives on the account's main location (`main_location`); this field is not updated when the main location's address is edited, so it can drift. Null if not set."
          },
          "onboarding_complete": {
            "type": "boolean",
            "readOnly": true,
            "description": "True when every required onboarding step is satisfied by real\naccount data: a business profile with a location, at least one team\nmember, an active phone number with E911 provisioned, and a device\nassigned to a user.\n"
          },
          "tos_status": {
            "type": "string",
            "readOnly": true,
            "enum": [
              "signed",
              "unsigned",
              "not_required"
            ],
            "description": "Subscription-agreement (SSA/TOS) coverage status. `signed` — a live\naccount whose acceptance matches the current agreement version;\n`unsigned` — a live account with no acceptance, or one accepted\nagainst a superseded version (a version bump re-opens the gate);\n`not_required` — a non-live (sandbox/demo) account, which is never\nprompted. Filter the list with `?tos_status=`. The full agreement\ndocument and the evidence-bearing acceptance are on\n`GET /v1/accounts/{account_id}/tos`.\n"
          },
          "tos_accepted_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "readOnly": true,
            "description": "When the current agreement was accepted; null unless `tos_status` is `signed`."
          },
          "created_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CreatedAt"
              }
            ]
          },
          "updated_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/UpdatedAt"
              }
            ]
          }
        },
        "required": [
          "id",
          "config",
          "created_at"
        ]
      },
      "WebhookEventType": {
        "type": "string",
        "description": "A webhook event type, or `*` to subscribe to every event. See the\n[Webhook Events](/guides/webhook-events#event-types) guide for the\npayload of each.\n",
        "enum": [
          "*",
          "call.initiated",
          "call.incoming",
          "call.ringing",
          "call.mobile_push_wakeup",
          "call.answered",
          "call.end",
          "call.transfer",
          "call.emergency",
          "fax.received",
          "fax.delivered",
          "fax.failed",
          "voicemail.new",
          "recording.available",
          "recording.failed",
          "recording.transcription.complete",
          "recording.summary.complete",
          "voicemail.transcription.complete",
          "voicemail.summary.complete",
          "queue.call.queued",
          "queue.call.dispatched",
          "queue.call.answered",
          "queue.call.abandoned",
          "queue.call.timed_out",
          "queue.call.completed",
          "queue.call.callback_requested",
          "queue.call.callback_attempted",
          "queue.call.callback_failed",
          "device.provisioned",
          "device.config_fetched",
          "device.provisioning_failed"
        ]
      },
      "WebhookEndpoint": {
        "type": "object",
        "description": "A URL that receives event notifications. Endpoints are mode-scoped: an\nendpoint only receives events from accounts whose mode matches its\n`livemode`. The mode is fixed at creation by the API key used and\ncannot be changed.\n",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              }
            ]
          },
          "url": {
            "type": "string",
            "description": "HTTPS URL that receives event POST requests.",
            "example": "https://example.com/webhooks"
          },
          "livemode": {
            "type": "boolean",
            "description": "Whether this endpoint receives live-mode events. `true` endpoints\nreceive events from live accounts; `false` endpoints receive events\nfrom sandbox accounts. Set from the API key's mode at creation;\nimmutable thereafter.\n"
          },
          "enabled_events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookEventType"
            },
            "description": "Event types this endpoint is subscribed to, or `[\"*\"]` for all\nevents.\n",
            "example": [
              "*"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "enabled",
              "disabled"
            ],
            "description": "A disabled endpoint receives no events."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "An optional description for the endpoint."
          },
          "secret": {
            "type": "string",
            "description": "The signing secret used to verify webhook signatures. Returned\n**only** in the response that creates the endpoint; omitted on\nlist, retrieve, and update. Store it securely.\n",
            "example": "whsec_3f9a..."
          },
          "created_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CreatedAt"
              }
            ]
          }
        },
        "required": [
          "id",
          "url",
          "livemode",
          "enabled_events",
          "status",
          "description",
          "created_at"
        ]
      },
      "CreateWebhookEndpointRequest": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "description": "HTTPS URL that will receive event POST requests.",
            "example": "https://example.com/webhooks"
          },
          "enabled_events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookEventType"
            },
            "description": "Event types to subscribe to, or `[\"*\"]` for all events. Defaults to\n`[\"*\"]` when omitted.\n"
          },
          "description": {
            "type": "string",
            "description": "An optional description for the endpoint."
          }
        },
        "required": [
          "url"
        ]
      },
      "UpdateWebhookEndpointRequest": {
        "type": "object",
        "description": "All fields are optional. `livemode` is fixed at creation and cannot be\nupdated.\n",
        "properties": {
          "url": {
            "type": "string",
            "description": "HTTPS URL that will receive event POST requests."
          },
          "enabled_events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookEventType"
            },
            "description": "Event types to subscribe to, or `[\"*\"]` for all events."
          },
          "status": {
            "type": "string",
            "enum": [
              "enabled",
              "disabled"
            ]
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass null to clear the description."
          }
        }
      },
      "AccountConfig": {
        "type": "object",
        "description": "Account-level configuration settings",
        "properties": {
          "region": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2 country code for the account. Used for region-specific features. Defaults to \"US\".",
            "example": "US"
          },
          "extension_length": {
            "type": "integer",
            "minimum": 3,
            "maximum": 6,
            "description": "Number of digits for extension numbers (3-6). Defaults to 4.",
            "example": 4
          },
          "transcription_enabled": {
            "type": "boolean",
            "description": "Whether calls are transcribed. Defaults to true.",
            "example": true
          },
          "recording_enabled": {
            "type": "boolean",
            "description": "Whether call audio recordings are retained. Defaults to true.",
            "example": true
          },
          "redaction_enabled": {
            "type": "boolean",
            "description": "Whether sensitive information (PII) is redacted from transcripts and audio recordings. When enabled, redacted words appear as `[PII]` in transcripts, the matching audio is silenced in the recording, calls are transcribed in English only, and a call's recording is available for download only after redaction completes. Defaults to false.",
            "example": false
          },
          "timezone": {
            "type": "string",
            "description": "IANA timezone for the account (e.g., \"America/New_York\"). Used as the default timezone for schedules when not explicitly set. Defaults to \"UTC\".",
            "example": "America/New_York"
          },
          "max_phone_numbers": {
            "type": "integer",
            "minimum": 1,
            "maximum": 1000,
            "description": "Maximum number of phone numbers the account can hold. Enforced whenever the account acquires a number — purchasing, creating or editing a port order, and recovering a released number — and counted over the numbers the account already holds plus any reserved by a pending port order. Released numbers are not counted. A request that would take the account past the limit is rejected with `409 Conflict` and the stable error code `phone_number_limit_exceeded`. Defaults to 25. Platform-controlled: settable only with a platform secret key; setting it from an account session returns `403`.",
            "example": 25
          },
          "parking_timeout_seconds": {
            "type": "integer",
            "minimum": 1,
            "description": "Duration in seconds before a parked call rings back the parker. Defaults to 300 (5 minutes).",
            "example": 300
          },
          "fax_inbound_per_hour": {
            "type": "integer",
            "minimum": 1,
            "maximum": 1000,
            "description": "Maximum inbound faxes accepted per rolling hour across the account. Over-limit faxes are rejected. Omit to use the default (25). Platform-controlled: settable only with a platform secret key; setting it from an account session returns `403`.",
            "example": 25
          },
          "fax_outbound_per_hour": {
            "type": "integer",
            "minimum": 1,
            "maximum": 1000,
            "description": "Maximum outbound faxes submitted per rolling hour across the account. Omit to use the default (25). Platform-controlled: settable only with a platform secret key; setting it from an account session returns `403`.",
            "example": 25
          },
          "default_agent_visible": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Account-level override for whether the managed AI agent is offered when creating a voice app. Omit (null) to inherit the platform default, `true` to always show it, `false` to hide it. When hidden, creating a managed AI agent is rejected. Platform-controlled: settable only with a platform secret key; setting it from an account session returns `403`.",
            "example": false
          },
          "e911_notification": {
            "$ref": "#/components/schemas/E911NotificationConfig"
          }
        }
      },
      "E911NotificationConfig": {
        "type": "object",
        "description": "Email recipients alerted when an emergency number (911 or a regional\nequivalent) is dialed.\n\nOn an account, recipients are alerted for every call on the account.\nOn a location, recipients are alerted only for calls placed from that\nlocation, in addition to the account-level recipients. The two lists\nare unioned at delivery time.\n\nThe `call.emergency` webhook event is delivered to the account's\nplatform webhook URL regardless of this setting.\n",
        "properties": {
          "emails": {
            "type": "array",
            "description": "Email recipients for emergency call alerts.",
            "items": {
              "type": "string",
              "format": "email"
            },
            "example": [
              "security@example.com",
              "frontdesk@example.com"
            ]
          }
        }
      },
      "LocationConfig": {
        "type": "object",
        "description": "Per-location configuration overrides",
        "properties": {
          "e911_notification": {
            "$ref": "#/components/schemas/E911NotificationConfig"
          }
        }
      },
      "AdminUser": {
        "type": "object",
        "description": "A person who can administer this account in the admin portal.\n\nAdmin portal users are a different population from voice users: they are\nidentified by email at the platform level and need not have phone\nservice. An account owner, for example, usually has no voice user at\nall, and so never appears in `GET /v1/users`. Conversely most voice\nusers are not administrators. The two overlap only by email address,\nwhich is what the `user` field resolves for you.\n\nMembership is by explicit role grant on **this** account. Someone who\nadministers a different account, or who holds platform-wide access\nrather than a grant on this account, is not listed here.\n",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              }
            ],
            "description": "Unique identifier for the admin portal user",
            "example": "admin_user_01h2xcejqtf2nbrexx3vqjhp43"
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Display name. Shared across every account this person administers,\nso it is not per-account editable.\n",
            "example": "Jane Rosen"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Login address for the portal. Also the only link between an admin\nportal user and a voice user.\n",
            "example": "jane@example.com"
          },
          "role": {
            "type": "string",
            "enum": [
              "account_admin",
              "owner"
            ],
            "description": "The role granted on this account. `owner` is the account's mandatory\nsigner and a superset of `account_admin`; there is exactly one per\naccount.\n",
            "example": "account_admin"
          },
          "user": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "$ref": "#/components/schemas/User"
              },
              {
                "type": "null"
              }
            ],
            "description": "This person's voice user in this account, matched by email, or\n`null` when they have no phone service. The user's id by default;\nthe full User object when `expand[]=user` is requested.\n",
            "example": "user_01h2xcejqtf2nbrexx3vqjhp42"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When this person was granted their role on this account — not when\ntheir portal identity was first created.\n"
          }
        },
        "required": [
          "id",
          "name",
          "email",
          "role",
          "user",
          "created_at"
        ]
      },
      "User": {
        "type": "object",
        "description": "A person with phone service (may have multiple devices/endpoints)",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              }
            ]
          },
          "name": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityName"
              }
            ]
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "format": "email",
            "description": "Email address (optional)",
            "example": "alice@spineline.dev"
          },
          "outbound_caller_id_did": {
            "type": [
              "string",
              "null"
            ],
            "description": "ID of the phone number to use as this user's outbound caller ID, overriding the account default. When null, the account default is used."
          },
          "voicemail_pin": {
            "type": [
              "string",
              "null"
            ],
            "description": "Numeric PIN for remote voicemail access (4-10 digits). When null, no PIN is set.",
            "example": "1234"
          },
          "config": {
            "$ref": "#/components/schemas/UserConfig"
          },
          "do_not_disturb": {
            "type": "boolean",
            "description": "When `true`, the calling path declines calls to this user (server-side do-not-disturb). Independent of the user's live availability, which is reported separately on the presence resource.\n",
            "example": false
          },
          "extensions": {
            "description": "List of extensions assigned to this user. Only included when `expand[]=extensions` is requested.\n",
            "type": "object",
            "properties": {
              "object": {
                "type": "string",
                "enum": [
                  "list"
                ]
              },
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Extension"
                }
              }
            }
          },
          "created_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CreatedAt"
              }
            ]
          },
          "updated_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/UpdatedAt"
              }
            ]
          }
        },
        "required": [
          "id",
          "do_not_disturb"
        ]
      },
      "UserConfig": {
        "type": "object",
        "description": "User-level configuration settings",
        "properties": {
          "voicemail_notifications": {
            "$ref": "#/components/schemas/VoicemailNotificationConfig"
          },
          "find_me_follow_me": {
            "$ref": "#/components/schemas/FMFM"
          },
          "mobile_push_wakeup": {
            "type": "boolean",
            "description": "Set to `true` when your application can deliver push notifications to wake this user's mobile app.\nWhen enabled and the user has no active web/mobile calling session, an incoming call is held for a\nshort wake-up window instead of skipping the app immediately — giving your `call.mobile_push_wakeup` webhook →\npush notification → app wake-up → connect flow time to pick up the still-ringing call.\nWhen disabled (default), routing moves on without waiting.\n",
            "default": false,
            "example": true
          }
        }
      },
      "FMFM": {
        "type": "object",
        "description": "Find Me / Follow Me call routing configuration. Steps are tried sequentially; within each step, all targets ring simultaneously.",
        "required": [
          "steps",
          "fallback"
        ],
        "properties": {
          "steps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FMFMStep"
            },
            "minItems": 1,
            "maxItems": 5
          },
          "fallback": {
            "type": "string",
            "enum": [
              "voicemail",
              "hangup",
              "target"
            ],
            "description": "Action when all steps are exhausted without an answer. When `target`, routes to the resource specified by `fallback_target`."
          },
          "fallback_target": {
            "type": "string",
            "description": "ID of the routing target for fallback. Required when fallback is `target`. Accepts user, ring group, voice app, dial plan, or shared voicemail IDs."
          }
        }
      },
      "FMFMStep": {
        "type": "object",
        "description": "A single ring step. All targets ring simultaneously with a shared timeout.",
        "required": [
          "targets",
          "timeout"
        ],
        "properties": {
          "targets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FMFMTarget"
            },
            "minItems": 1,
            "maxItems": 10
          },
          "timeout": {
            "type": "integer",
            "minimum": 1,
            "maximum": 120,
            "description": "How long to ring all targets in this step (seconds)."
          }
        }
      },
      "FMFMTarget": {
        "type": "object",
        "description": "A target to ring within a step.",
        "required": [
          "type"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "external",
              "user"
            ],
            "description": "Target type:\n- `external` — dial a PSTN phone number.\n- `user` — ring a user's SIP endpoints (can be the current user or another user).\n"
          },
          "number": {
            "type": "string",
            "description": "Phone number in E.164 format. Required when type is `external`.",
            "example": "+15551234567"
          },
          "id": {
            "type": "string",
            "description": "ID of the user to ring. Required when type is `user`."
          }
        }
      },
      "VoicemailNotificationConfig": {
        "type": "object",
        "description": "Voicemail email notification preferences",
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Whether voicemail email notifications are enabled (user voicemails only)",
            "default": false
          },
          "attach_audio": {
            "type": "boolean",
            "description": "Attach the voicemail audio file (MP3) to the email. Forced true when delete_after_email is true.",
            "default": true
          },
          "include_summary": {
            "type": "boolean",
            "description": "Include the AI-generated summary in the email. When true, email is sent after transcription completes.",
            "default": true
          },
          "include_transcript": {
            "type": "boolean",
            "description": "Include the full transcript in the email. When true, email is sent after transcription completes.",
            "default": true
          },
          "delete_after_email": {
            "type": "boolean",
            "description": "Automatically delete the voicemail after the notification email is sent. Implies attach_audio.",
            "default": false
          }
        }
      },
      "Voicemail": {
        "type": "object",
        "description": "A voicemail message with audio recording. Each voicemail has exactly\none owner — either a user or a shared voicemail box.\n",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              }
            ]
          },
          "owner": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "ID of the owner — either the user who received the voicemail or the shared voicemail box it was left in."
              }
            ]
          },
          "from_number": {
            "type": "string",
            "maxLength": 20,
            "description": "Caller's phone number",
            "example": "+14155551234"
          },
          "from_name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 255,
            "description": "Caller's name (if available from caller ID)",
            "example": "John Smith"
          },
          "duration_seconds": {
            "type": "integer",
            "minimum": 0,
            "description": "Length of the voicemail recording in seconds",
            "example": 42
          },
          "format": {
            "type": "string",
            "maxLength": 10,
            "description": "Audio format",
            "example": "mp3"
          },
          "audio_url": {
            "type": "string",
            "format": "uri",
            "description": "URL for downloading the audio recording",
            "example": "https://voicemails.dialstack.ai/550e8400-e29b-41d4-a716-446655440000/20251018-143000_John_Smith.mp3"
          },
          "is_read": {
            "type": "boolean",
            "description": "Whether the voicemail has been listened to",
            "example": false
          },
          "created_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CreatedAt"
              }
            ]
          },
          "read_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the voicemail was marked as read",
            "example": "2025-10-18T15:00:00Z"
          },
          "summary": {
            "type": [
              "string",
              "null"
            ],
            "description": "AI-generated summary of the voicemail content. Null if transcription not yet processed.",
            "example": "John Smith called to reschedule his Thursday appointment to Friday."
          },
          "sentiment": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Sentiment"
              },
              {
                "type": "null"
              }
            ],
            "description": "AI-derived sentiment of the voicemail transcript. Single-channel\naudio, so no `local`/`remote` breakdown. Null when not analyzed.\n"
          },
          "call": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "$ref": "#/components/schemas/CallLog"
              },
              {
                "type": "null"
              }
            ],
            "description": "The call that produced this voicemail. By default this is the\ncall's id; when `expand[]=call` is requested it is the full call\nobject (identical to `GET /v1/calls/{call_id}`). Null for\nvoicemails with no associated call.\n"
          }
        },
        "required": [
          "id",
          "owner",
          "from_number",
          "duration_seconds",
          "format",
          "audio_url",
          "is_read",
          "created_at",
          "call"
        ]
      },
      "VoicemailGreetingResponse": {
        "type": "object",
        "description": "A custom voicemail greeting that replaces the system-default prompts\nfor a user mailbox or a shared voicemail box. Each (owner, type) pair\nhas at most one greeting — re-uploading overwrites.\n",
        "properties": {
          "owner": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "ID of the owner — either the user whose mailbox the greeting belongs to, or the shared voicemail box it belongs to."
              }
            ]
          },
          "greeting_type": {
            "type": "string",
            "description": "The greeting variant. Today only `unavailable` is supported —\nthe full custom greeting that replaces the system prompts\n(caller hears it when the owner does not answer).\n",
            "enum": [
              "unavailable"
            ]
          },
          "format": {
            "type": "string",
            "description": "Audio format of the stored greeting.",
            "enum": [
              "wav"
            ],
            "example": "wav"
          },
          "duration_seconds": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "description": "Length of the greeting audio in seconds.",
            "example": 12.4
          },
          "size_bytes": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Size of the stored greeting audio in bytes (post-transcode).",
            "example": 98560
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Short-lived signed URL (5 minutes) for downloading the greeting audio."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the greeting was last uploaded or replaced."
          }
        },
        "required": [
          "owner",
          "greeting_type",
          "format",
          "duration_seconds",
          "size_bytes",
          "url",
          "updated_at"
        ]
      },
      "AuditLogEntry": {
        "type": "object",
        "description": "A single audit log entry recording an API operation",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the audit log entry"
          },
          "actor": {
            "type": "string",
            "description": "Identifier of the actor that performed the operation"
          },
          "event": {
            "type": "string",
            "description": "Type of event (e.g., `user.create`, `auth.denied`)"
          },
          "resource": {
            "type": "string",
            "description": "Identifier of the affected resource"
          },
          "outcome": {
            "type": "string",
            "description": "Result of the operation",
            "enum": [
              "success",
              "failure",
              "denied"
            ]
          },
          "ip_address": {
            "type": "string",
            "description": "Client IP address"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "When the event occurred"
          }
        },
        "required": [
          "id",
          "event",
          "outcome",
          "ip_address",
          "timestamp"
        ]
      },
      "DIDSummary": {
        "type": "object",
        "description": "Compact phone number (DID) reference embedded in a resource when\n`expand[]=did` is requested (call logs, faxes). Intentionally limited to\nidentity and the dialable number — the full phone number resource\n(routing, caller ID, directory listing, configuration) is available via\n`/v1/phone-numbers`.\n",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              }
            ]
          },
          "phone_number": {
            "type": "string",
            "description": "The DID in E.164 format.",
            "example": "+14155559876"
          }
        },
        "required": [
          "id",
          "phone_number"
        ]
      },
      "CallLog": {
        "type": "object",
        "description": "Record of a completed or attempted call. The `id` is an opaque call\nlog identifier — a single call log may span multiple underlying call\nlegs, so it does not correspond to any single leg.\n\nThe record is lifecycle-spanning: it can be retrieved while the call is\nstill live. While a call is in progress it is a sparse projection —\n`status`, `to_label`, `ended_at`, `duration_seconds`, `answered_at`,\n`connected_at`, `hangup_cause`, `summary`, and `recording_url` are null\nuntil the call completes, and `quality_metrics` is an empty array.\n`to_number` is present live for outbound and internal calls (whose\ndestination is known at call start) but null for inbound calls (the\nrouted destination is resolved later), and `from_label` carries the\ncaller's display name when one is available; see each field for its live\nbehavior.\n",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              }
            ]
          },
          "user": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "type": "null"
              }
            ],
            "description": "The user associated with this call"
          },
          "endpoint": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "type": "null"
              }
            ],
            "description": "The endpoint (device) that handled this call"
          },
          "did": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "$ref": "#/components/schemas/DIDSummary"
              },
              {
                "type": "null"
              }
            ],
            "description": "The phone number (DID) associated with this call. By default this\nis the DID's id; when `expand[]=did` is requested it is a compact\nDID object (id and phone number only). Null for calls without a DID.\n"
          },
          "direction": {
            "type": "string",
            "enum": [
              "inbound",
              "outbound",
              "internal"
            ],
            "description": "Call direction (inbound from PSTN, outbound to PSTN, or internal extension-to-extension)",
            "example": "inbound"
          },
          "from_number": {
            "type": "string",
            "minLength": 0,
            "maxLength": 20,
            "description": "Caller's phone number or originating extension. May be empty when the originating identity could not be determined.",
            "example": "+14155551234"
          },
          "from_label": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 80,
            "description": "The caller's display name. For internal callers this is the calling user's display name (the caller is always a user's device); for external callers it is the caller ID name (CNAM). While a call is live it is the name captured at call start. Null when no name is available. For external callers the CNAM is not interpreted, only trimmed and limited to 80 characters, so it may be a locality rather than a person (\"LA MESA CA\"), a placeholder (\"WIRELESS CALLER\"), or a restatement of `from_number` — check for the latter before rendering the name beside the number.",
            "example": "Front Desk"
          },
          "to_number": {
            "type": [
              "string",
              "null"
            ],
            "minLength": 0,
            "maxLength": 20,
            "description": "The call's destination — an E.164 phone number for PSTN destinations, or the internal extension number the call was routed to for calls that terminate inside the account (including inbound calls to one of the account's phone numbers). May be empty when the destination could not be determined. While a call is live it is present when the destination is known at call start — outbound calls and internal extension-to-extension calls; for an inbound call the routed destination is resolved later, so `to_number` is null for the entire time the call is in flight and is populated once the call completes. Note that webhook events report the number as dialed instead, so an inbound call's webhook `to_number` (the E.164 phone number) can differ from this field (the routed extension).",
            "example": "+14155559876"
          },
          "to_label": {
            "type": [
              "string",
              "null"
            ],
            "description": "Display label for the recipient, resolved from the extension's target name (user, dial plan, voice app, or ring group). Null if the number does not match an extension.",
            "example": "Sales Queue"
          },
          "started_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the call was initiated",
            "example": "2025-10-18T14:30:00Z"
          },
          "answered_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the call was answered at the signalling level. A greeting, menu, or voice app answering the media path counts, so for inbound calls that play one this is the platform answer (≈ started_at), not when a person picked up. Null for unanswered calls. Use connected_at for when a person or external number actually took the call.",
            "example": "2025-10-18T14:30:05Z"
          },
          "connected_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the winning leg — a user's device or an external-number fallback — answered, i.e. when live conversation began. Null when the call never connected to anyone: the caller hung up during the greeting or while ringing, or the call was answered by voicemail. For a direct call with no greeting this equals answered_at.",
            "example": "2025-10-18T14:31:02Z"
          },
          "ended_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the call ended. Null if the call is still in flight.",
            "example": "2025-10-18T14:35:30Z"
          },
          "duration_seconds": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Call duration in seconds (from answer to hangup). Null for unanswered calls.",
            "example": 325
          },
          "status": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "completed",
              "no-answer",
              "busy",
              "failed",
              "voicemail",
              null
            ],
            "description": "Final call status, derived once the call ends. Null while the call is still live (in progress) — the status values are terminal only.",
            "example": "completed"
          },
          "hangup_cause": {
            "type": [
              "integer",
              "null"
            ],
            "description": "The Q.850 hangup cause code of the destination leg when the call could not be connected — the standard telephony cause number (for example, 17 user busy, 21 call rejected, 38 network out of order). Set even if the call was answered on the originating side (for example, a click-to-call where your own phone picks up before the destination is dialed). Null when the call connected normally or no cause was recorded.",
            "example": 21
          },
          "summary": {
            "type": [
              "string",
              "null"
            ],
            "description": "AI-generated summary of the call. Null if call wasn't recorded or transcript not yet processed.",
            "example": "Customer called to reschedule appointment from Thursday to Friday due to work conflict."
          },
          "sentiment": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Sentiment"
              },
              {
                "type": "null"
              }
            ],
            "description": "AI-derived sentiment of the call transcript. Null if the call was\nnot recorded, the transcript is not yet processed, or the analysis\ndid not produce a usable result.\n"
          },
          "recording_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Signed URL to download the call recording audio. Null if the call was not recorded. The URL expires after 10 minutes.",
            "example": "https://cdn.example.com/recordings/2026-03-05/call.wav?Expires=1709654400&Signature=abc123"
          },
          "quality_metrics": {
            "type": "array",
            "description": "RTP quality metrics per call leg. Each call may have multiple legs (e.g., PSTN + endpoint for inbound calls). Empty array for unanswered calls.",
            "items": {
              "$ref": "#/components/schemas/QualityMetricLeg"
            }
          }
        },
        "required": [
          "id",
          "user",
          "endpoint",
          "did",
          "direction",
          "from_number",
          "from_label",
          "to_number",
          "to_label",
          "started_at",
          "answered_at",
          "connected_at",
          "ended_at",
          "duration_seconds",
          "status",
          "hangup_cause",
          "summary",
          "recording_url",
          "quality_metrics"
        ]
      },
      "QualityMetricLeg": {
        "type": "object",
        "description": "RTP quality metrics for a single call leg (PSTN or endpoint)",
        "properties": {
          "leg": {
            "type": "string",
            "enum": [
              "pstn",
              "endpoint"
            ],
            "description": "Type of call leg",
            "example": "endpoint"
          },
          "endpoint": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "type": "null"
              }
            ],
            "description": "The endpoint ID for endpoint legs. Null for PSTN legs."
          },
          "jitter_ms": {
            "type": [
              "number",
              "null"
            ],
            "format": "float",
            "minimum": 0,
            "description": "Average jitter in milliseconds during the call leg",
            "example": 5.2
          },
          "jitter_min_ms": {
            "type": [
              "number",
              "null"
            ],
            "format": "float",
            "minimum": 0,
            "description": "Minimum jitter observed during the call leg in milliseconds",
            "example": 1
          },
          "jitter_max_ms": {
            "type": [
              "number",
              "null"
            ],
            "format": "float",
            "minimum": 0,
            "description": "Maximum jitter observed during the call leg in milliseconds",
            "example": 15.5
          },
          "jitter_stddev_ms": {
            "type": [
              "number",
              "null"
            ],
            "format": "float",
            "minimum": 0,
            "description": "Standard deviation of jitter during the call leg in milliseconds",
            "example": 2.3
          },
          "packet_loss_pct": {
            "type": [
              "number",
              "null"
            ],
            "format": "float",
            "minimum": 0,
            "maximum": 100,
            "description": "Packet loss percentage during the call leg",
            "example": 0.5
          },
          "rtt_ms": {
            "type": [
              "number",
              "null"
            ],
            "format": "float",
            "minimum": 0,
            "description": "Average round-trip time (RTT) in milliseconds during the call leg",
            "example": 45
          },
          "rtt_min_ms": {
            "type": [
              "number",
              "null"
            ],
            "format": "float",
            "minimum": 0,
            "description": "Minimum round-trip time observed during the call leg in milliseconds",
            "example": 30
          },
          "rtt_max_ms": {
            "type": [
              "number",
              "null"
            ],
            "format": "float",
            "minimum": 0,
            "description": "Maximum round-trip time observed during the call leg in milliseconds",
            "example": 80
          },
          "rtt_stddev_ms": {
            "type": [
              "number",
              "null"
            ],
            "format": "float",
            "minimum": 0,
            "description": "Standard deviation of round-trip time during the call leg in milliseconds",
            "example": 12.5
          },
          "rx_count": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "minimum": 0,
            "description": "Total number of RTP packets received during the call leg",
            "example": 10000
          },
          "tx_count": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "minimum": 0,
            "description": "Total number of RTP packets transmitted during the call leg",
            "example": 10050
          },
          "mos": {
            "type": [
              "number",
              "null"
            ],
            "format": "float",
            "minimum": 1,
            "maximum": 4.5,
            "description": "Mean Opinion Score (MOS) computed from RTP quality metrics using ITU-T G.107 E-model. Ranges from 1.0 (bad) to 4.5 (excellent).",
            "example": 4.2
          }
        },
        "required": [
          "leg"
        ]
      },
      "Sentiment": {
        "type": "object",
        "description": "AI-derived sentiment of a call or voicemail transcript, generated\nautomatically alongside the summary once transcription completes.\n\nTwo independent axes:\n\n- `score` is the emotional **leaning**, from -1.0 (strongly negative)\n  through 0 (neutral) to +1.0 (strongly positive). `overall` is derived\n  from it, so the two never disagree.\n- `magnitude` is how strongly feeling was expressed **at all**, from 0.0\n  to 1.0. It is unsigned.\n\nReading them together matters: a call where one side was angry and the\nother delighted scores near 0 with a **high** magnitude, while a routine\ncall scores near 0 with a **low** one. Both are `neutral` by label.\n\nMost business calls are neutral with a low magnitude — routine,\nbusinesslike exchanges score near 0 even when both parties are perfectly\npolite — so anything else is meaningful rather than routine.\n\nSentiment reflects how the participants feel about the interaction, not\nthe subject matter: a calm conversation about an unpleasant topic is\nneutral, while a caller who is frustrated or distressed is negative even\nif the exchange stays cordial.\n",
        "properties": {
          "overall": {
            "type": "string",
            "enum": [
              "positive",
              "neutral",
              "negative"
            ],
            "description": "Overall sentiment, derived from `score`. Check `magnitude` before\nreading `neutral` as \"nobody felt anything\".\n",
            "example": "negative"
          },
          "score": {
            "type": "number",
            "format": "float",
            "minimum": -1,
            "maximum": 1,
            "description": "Emotional leaning, from -1.0 (strongly negative) to +1.0 (strongly positive).",
            "example": -0.7
          },
          "magnitude": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "maximum": 1,
            "description": "Unsigned strength of expressed feeling, from 0.0 (flat and\nbusinesslike) to 1.0 (intense).\n",
            "example": 0.9
          },
          "local": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ChannelSentiment"
              },
              {
                "description": "Sentiment of your user's side of the conversation. Absent for\nvoicemail, whose audio is single-channel.\n"
              }
            ]
          },
          "remote": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ChannelSentiment"
              },
              {
                "description": "Sentiment of the other party's side of the conversation. Absent\nfor voicemail, whose audio is single-channel.\n"
              }
            ]
          }
        },
        "required": [
          "overall",
          "score",
          "magnitude"
        ]
      },
      "ChannelSentiment": {
        "type": "object",
        "description": "Sentiment for one speaker on a two-party call.",
        "properties": {
          "sentiment": {
            "type": "string",
            "enum": [
              "positive",
              "neutral",
              "negative"
            ],
            "description": "This speaker's sentiment, derived from their `score`.",
            "example": "negative"
          },
          "score": {
            "type": "number",
            "format": "float",
            "minimum": -1,
            "maximum": 1,
            "description": "This speaker's emotional leaning, on the same -1.0 to +1.0 scale.",
            "example": -0.85
          },
          "magnitude": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "maximum": 1,
            "description": "How strongly this speaker expressed feeling, 0.0 to 1.0.",
            "example": 0.95
          }
        },
        "required": [
          "sentiment",
          "score",
          "magnitude"
        ]
      },
      "Transcript": {
        "type": "object",
        "description": "Call transcript containing transcription status and text",
        "properties": {
          "call_id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "The call this transcript belongs to"
              }
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "processing",
              "completed",
              "failed"
            ],
            "description": "Current status of the transcription:\n- `pending`: Recording uploaded, transcription not started\n- `processing`: Transcription in progress\n- `completed`: Transcription finished successfully\n- `failed`: Transcription failed\n",
            "example": "completed"
          },
          "text": {
            "type": [
              "string",
              "null"
            ],
            "description": "Full text transcript. Null if transcription is not completed.",
            "example": "Hello, this is Dr. Smith calling to confirm your appointment..."
          },
          "sentiment": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Sentiment"
              },
              {
                "type": "null"
              }
            ],
            "description": "Sentiment derived from the transcript. Null while transcription is\nincomplete, or when the analysis did not produce a usable result.\n"
          }
        },
        "required": [
          "call_id",
          "status"
        ]
      },
      "Recording": {
        "type": "object",
        "description": "Call recording metadata with a signed download URL",
        "properties": {
          "call_id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "The call this recording belongs to"
              }
            ]
          },
          "duration_seconds": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Duration of the recording in seconds. Null if not available.",
            "example": 185
          },
          "file_size_bytes": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Size of the recording file in bytes. Null if not available.",
            "example": 2960000
          },
          "download_url": {
            "type": "string",
            "format": "uri",
            "description": "Signed URL to download the recording audio file. Expires after 10 minutes.",
            "example": "https://cdn.example.com/recordings/2026-03-05/call.wav?Expires=1709654400&Signature=abc123"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the download URL expires",
            "example": "2026-03-05T15:40:00Z"
          }
        },
        "required": [
          "call_id",
          "download_url",
          "expires_at"
        ]
      },
      "VoicemailTranscript": {
        "type": "object",
        "description": "Voicemail transcript containing transcription status and text",
        "properties": {
          "voicemail": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "The voicemail this transcript belongs to"
              }
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "processing",
              "completed",
              "failed"
            ],
            "description": "Current status of the transcription:\n- `pending`: Voicemail uploaded, transcription not started\n- `processing`: Transcription in progress\n- `completed`: Transcription finished successfully\n- `failed`: Transcription failed\n",
            "example": "completed"
          },
          "text": {
            "type": [
              "string",
              "null"
            ],
            "description": "Full text transcript. Null if transcription is not completed.",
            "example": "Hi, this is John Smith calling about my appointment tomorrow..."
          },
          "sentiment": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Sentiment"
              },
              {
                "type": "null"
              }
            ],
            "description": "Sentiment derived from the transcript. Voicemail audio is\nsingle-channel, so this never carries the `local`/`remote` breakdown a\ncall transcript does. Null when not analyzed.\n"
          }
        },
        "required": [
          "voicemail",
          "status"
        ]
      },
      "PhoneNumber": {
        "type": "object",
        "description": "A phone number (DID) assigned to an account for inbound/outbound calling",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              }
            ]
          },
          "phone_number": {
            "type": "string",
            "maxLength": 20,
            "description": "Phone number in E.164 format",
            "example": "+14155551234"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "inactive",
              "released"
            ],
            "description": "Current status of the phone number",
            "example": "active"
          },
          "outbound_enabled": {
            "type": "boolean",
            "description": "Whether this phone number can be used for outbound calling",
            "example": true
          },
          "fax_enabled": {
            "type": "boolean",
            "description": "Whether this number is set up for faxing. When true, inbound calls\nare received as faxes (its inbound routing target is bypassed but\npreserved, and resumes if fax is disabled). The number can still be\nused as an outbound caller ID.\n",
            "example": false
          },
          "config": {
            "$ref": "#/components/schemas/DIDConfig"
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the phone number is scheduled to be released back to the carrier. Set on temporary numbers issued during signup; null on permanent numbers.",
            "example": null
          },
          "disconnected_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the phone number was released back to the carrier. Null while the number is in service.",
            "example": null
          },
          "caller_id_name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 15,
            "description": "The caller ID name (CNAM) configured for this phone number, or null if not set",
            "example": "ACME Corp"
          },
          "caller_id_prefix": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 32,
            "description": "A prefix added to the inbound caller's display name (e.g. `[Acme] John Smith`, or `[Acme] +14084806024` when the caller's name is unknown). Useful when calls to this number are answered on behalf of a specific brand or business. Applies both to the device that answers and to calls forwarded out to an external number, so a forwarded business call can be told apart from a personal one. Unlike `caller_id_name` (the outbound caller ID name), this affects only the caller ID presented for inbound calls; it does not change call records. Null when not set.",
            "example": "[Acme]"
          },
          "directory_listing_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "The business name used for directory listing (411/white pages), or null if not set",
            "example": "Acme Corporation"
          },
          "directory_listing_type": {
            "type": "string",
            "enum": [
              "listed",
              "non_listed",
              "non_published",
              "non_registered"
            ],
            "description": "How the number appears in directory services",
            "example": "listed"
          },
          "directory_listing_location": {
            "type": [
              "string",
              "null"
            ],
            "description": "ID of the location whose address is published in the directory listing, or null",
            "example": null
          },
          "routing_target": {
            "type": [
              "string",
              "null"
            ],
            "description": "ID of the target that inbound calls to this number are routed to, or null when no target is set. Always null when `inbound_routing` is `drop`.",
            "example": null
          },
          "inbound_routing": {
            "type": "string",
            "enum": [
              "default",
              "drop"
            ],
            "description": "How inbound calls to this number are handled. `default` follows `routing_target` — routing to the target when one is set, otherwise ringing all users on the account. `drop` deliberately drops inbound calls (no ring, no message); `routing_target` is null in that case.",
            "example": "default"
          },
          "created_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CreatedAt"
              }
            ]
          },
          "updated_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/UpdatedAt"
              }
            ]
          }
        },
        "required": [
          "id",
          "phone_number",
          "status",
          "outbound_enabled",
          "fax_enabled",
          "expires_at",
          "disconnected_at",
          "routing_target",
          "inbound_routing",
          "created_at",
          "updated_at"
        ]
      },
      "SmsPortOutWindow": {
        "type": "object",
        "description": "The SMS port-out window for a number. `expires_at` is the instant until\nwhich an inbound SMS port-out (messaging transfer) request is authorized;\n`null` means the window is locked and requests are denied.\n",
        "properties": {
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "RFC 3339 timestamp the window stays open until, or null when locked."
          }
        },
        "required": [
          "expires_at"
        ]
      },
      "DIDConfig": {
        "type": "object",
        "description": "Per-number configuration blob.",
        "properties": {
          "fax_notifications": {
            "$ref": "#/components/schemas/FaxNotificationConfig"
          }
        }
      },
      "FaxNotificationConfig": {
        "type": "object",
        "description": "Email notifications sent when a fax is received on this number.",
        "properties": {
          "recipients": {
            "type": "array",
            "maxItems": 10,
            "items": {
              "type": "string",
              "format": "email"
            },
            "description": "Up to 10 email addresses notified when a fax is received on this number. An empty list disables notifications.",
            "example": [
              "fax@example.com"
            ]
          },
          "delete_documents": {
            "type": "boolean",
            "description": "When true, fax documents are not retained on the server, in both directions (defaults to false). Inbound: the received document is attached to the notification email as a PDF and the stored copy is removed after the email is sent. Outbound: the uploaded source document is deleted once the fax reaches a terminal status (`delivered` or `failed`). Either way the document is no longer retrievable in-app. When false, the notification email instead includes a time-bounded link to view the received document and documents are retained. Requires at least one entry in `recipients`: enabling this with an empty recipient list is rejected, since a received fax would be neither stored nor delivered.",
            "example": false
          },
          "attach_pdf": {
            "type": "boolean",
            "deprecated": true,
            "description": "Deprecated and retained only for backwards compatibility. It is accepted on input but ignored (not stored, no effect) and always returned as `true` (its historical default). Use `delete_documents` to control document handling. This field will be removed in a future release."
          }
        }
      },
      "AvailablePhoneNumber": {
        "type": "object",
        "description": "A phone number available for purchase",
        "properties": {
          "phone_number": {
            "type": "string",
            "maxLength": 20,
            "description": "Phone number in E.164 format",
            "example": "+19195551234"
          },
          "city": {
            "type": "string",
            "description": "City where the number is registered",
            "example": "RALEIGH"
          },
          "state": {
            "type": "string",
            "description": "Two-letter state abbreviation",
            "example": "NC"
          },
          "rate_center": {
            "type": "string",
            "description": "Rate center for the number",
            "example": "RALEIGH"
          },
          "lata": {
            "type": "string",
            "description": "Local access and transport area",
            "example": "422"
          }
        },
        "required": [
          "phone_number"
        ]
      },
      "NumberOrder": {
        "type": "object",
        "description": "Tracks the status of a phone number purchase or disconnect request.\nPurchase orders acquire new numbers — number porting is not supported.\n",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              }
            ]
          },
          "order_type": {
            "type": "string",
            "enum": [
              "purchase",
              "disconnect"
            ],
            "description": "`purchase` — acquire new phone numbers.\n`disconnect` — release existing phone numbers back to the provider.\n",
            "example": "purchase"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "complete",
              "partial",
              "failed"
            ],
            "description": "`pending` — order submitted, awaiting provider confirmation.\n`complete` — all requested numbers were successfully provisioned (or released).\n`partial` — some numbers succeeded, others failed.\n`failed` — the entire order was rejected.\n",
            "example": "pending"
          },
          "phone_numbers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Phone numbers included in the order (E.164 format)",
            "example": [
              "+19195551234",
              "+19195555678"
            ]
          },
          "completed_numbers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Phone numbers that completed successfully",
            "example": [
              "+19195551234"
            ]
          },
          "failed_numbers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Phone numbers that failed",
            "example": []
          },
          "error_message": {
            "type": [
              "string",
              "null"
            ],
            "description": "Error details if the order failed"
          },
          "created_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CreatedAt"
              }
            ]
          },
          "updated_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/UpdatedAt"
              }
            ]
          }
        },
        "required": [
          "id",
          "order_type",
          "status",
          "phone_numbers",
          "completed_numbers",
          "failed_numbers",
          "created_at",
          "updated_at"
        ]
      },
      "VoiceApp": {
        "type": "object",
        "description": "A voice app handles calls via HTTP webhook notification and optional WebSocket\naudio streaming. When a call is routed to a voice app, DialStack sends an HTTP\nPOST notification to the configured URL. The platform can then use the Update\nCall API to control the call (e.g., attach a WebSocket for bidirectional audio\nstreaming, or transfer to another extension).\n\nVoice apps also receive notifications from Voice App (Notify) dial plan nodes,\nenabling real-time call monitoring via the Listeners API without affecting call routing.\n\n## Webhook Events\n\nVoice apps receive two types of webhooks, distinguished by the `event` field:\n\n- `call.received` — The call has been routed to this voice app for handling.\n  Your server takes control of the call via the Update Call API.\n- `call.notify` — A call is passing through a Voice App (Notify) node in a dial plan.\n  The call continues routing normally. Use the Listeners API to stream audio.\n\n## Webhook Notification\n\nWhen a call arrives, DialStack sends a POST request to the voice app's URL:\n\n```\nPOST https://your-app.example.com/calls\nContent-Type: application/json\nX-DialStack-Signature: t=1697634600,v1=5257a869...\n\n{\n  \"event\": \"call.received\",\n  \"call_id\": \"call_...\",\n  \"account_id\": \"acct_...\",\n  \"voice_app_id\": \"va_...\",\n  \"from_number\": \"+14155551234\",\n  \"from_name\": \"John Smith\",\n  \"to_number\": \"+14155559876\"\n}\n```\n\n**Signature Verification:**\nThe `X-DialStack-Signature` header contains a timestamp and HMAC-SHA256 signature:\n- `t` = Unix timestamp (seconds) when signature was generated\n- `v1` = HMAC-SHA256 signature\n\nTo verify: compute `HMAC-SHA256(\"${t}.${request_body}\", voice_app_secret)` and compare.\nReject timestamps older than 5 minutes to prevent replay attacks.\n\n**Response:** Return `200 OK` to acknowledge. Response body is ignored.\n\n**Delivery:** Failed webhooks are retried with exponential backoff (3 attempts, 5-second timeout).\n\nSee [Voice Apps Guide](/guides/voice-apps) for complete examples.\n",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              }
            ],
            "example": "va_01h2xcejqtf2nbrexx3vqjhp49"
          },
          "name": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityName"
              }
            ],
            "example": "AI Receptionist"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "HTTPS webhook URL for call control notifications",
            "example": "https://ai.platform.example.com/calls"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "inactive"
            ],
            "description": "Current status of the voice app",
            "example": "active"
          },
          "secret": {
            "type": "string",
            "description": "Webhook signing secret for this voice app. Used to verify webhook signatures.",
            "example": "whsec_abc123def456..."
          },
          "created_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CreatedAt"
              }
            ]
          },
          "updated_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/UpdatedAt"
              }
            ]
          },
          "extensions": {
            "description": "List of extensions assigned to this voice app. Only included when `expand[]=extensions` is requested.\n",
            "type": "object",
            "properties": {
              "object": {
                "type": "string",
                "enum": [
                  "list"
                ]
              },
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Extension"
                }
              }
            }
          }
        },
        "required": [
          "id",
          "name",
          "url",
          "status",
          "secret",
          "created_at"
        ]
      },
      "TimeRange": {
        "type": "object",
        "description": "A time range within a specific day of the week",
        "properties": {
          "day": {
            "type": "integer",
            "minimum": 0,
            "maximum": 6,
            "description": "Day of the week (0=Sunday, 1=Monday, ..., 6=Saturday)",
            "example": 1
          },
          "start": {
            "type": "string",
            "format": "time-local",
            "description": "Start time in HH:MM format (24-hour)",
            "example": "09:00"
          },
          "end": {
            "type": "string",
            "format": "time-local",
            "description": "End time in HH:MM format (24-hour)",
            "example": "17:00"
          }
        },
        "required": [
          "day",
          "start",
          "end"
        ]
      },
      "DateRange": {
        "type": "object",
        "description": "A date range for holidays (full days only)",
        "properties": {
          "start": {
            "type": "string",
            "format": "date",
            "description": "Start date (YYYY-MM-DD)",
            "example": "2025-12-25"
          },
          "end": {
            "type": "string",
            "format": "date",
            "description": "End date (YYYY-MM-DD), inclusive",
            "example": "2025-12-25"
          }
        },
        "required": [
          "start",
          "end"
        ]
      },
      "ScheduleHold": {
        "type": "object",
        "description": "Temporary hold override for a schedule. When set, the hold value overrides\nthe normal schedule calculation until the specified time.\n",
        "properties": {
          "value": {
            "type": "boolean",
            "description": "Override value (true=force open, false=force closed)",
            "example": false
          },
          "until": {
            "type": "string",
            "format": "date-time",
            "description": "When the hold expires, as an absolute RFC3339 instant.",
            "example": "2025-12-20T22:00:00Z"
          }
        },
        "required": [
          "value",
          "until"
        ]
      },
      "Schedule": {
        "type": "object",
        "description": "A business hours schedule for call routing. Schedules define when the business\nis open based on weekly time ranges and holidays. A temporary hold can override\nthe schedule calculation.\n",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              }
            ],
            "example": "sched_01h2xcejqtf2nbrexx3vqjhp50"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Display name for the schedule",
            "example": "Business Hours"
          },
          "timezone": {
            "type": [
              "string",
              "null"
            ],
            "description": "IANA timezone for interpreting times (e.g., \"America/New_York\"). If null, uses account default.",
            "example": "America/New_York"
          },
          "ranges": {
            "type": "array",
            "description": "Weekly time ranges when the schedule is considered \"open\"",
            "items": {
              "$ref": "#/components/schemas/TimeRange"
            },
            "example": [
              {
                "day": 1,
                "start": "09:00",
                "end": "17:00"
              },
              {
                "day": 2,
                "start": "09:00",
                "end": "17:00"
              }
            ]
          },
          "holidays": {
            "type": "array",
            "description": "Date ranges when the schedule is closed regardless of weekly ranges",
            "items": {
              "$ref": "#/components/schemas/DateRange"
            },
            "example": [
              {
                "start": "2025-12-25",
                "end": "2025-12-25"
              }
            ]
          },
          "hold": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ScheduleHold"
              },
              {
                "type": "null"
              }
            ],
            "description": "Temporary override for the schedule"
          },
          "created_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CreatedAt"
              }
            ]
          },
          "updated_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/UpdatedAt"
              }
            ]
          }
        },
        "required": [
          "id",
          "name",
          "ranges",
          "created_at"
        ]
      },
      "AccountRequest": {
        "type": "object",
        "properties": {
          "email": {
            "type": [
              "string",
              "null"
            ],
            "format": "email",
            "description": "Contact email address for the account. Required when creating an account — at creation it also establishes the account owner identity. Afterwards it is an ordinary contact address and can be updated freely: changing it does not move the account owner, and does not change who receives or has accepted the subscription agreement. On update, omit the field to leave it unchanged, or send null (or an empty string) to clear it. Clearing it removes the account's contact address only — the owner is unaffected — but it does make the account incomplete for onboarding purposes.",
            "example": "contact@example.com"
          },
          "name": {
            "type": "string",
            "description": "Company or organization name",
            "example": "Acme Corp"
          },
          "phone": {
            "type": "string",
            "description": "Phone number in E.164 format",
            "example": "+12125550100"
          },
          "primary_contact_name": {
            "type": "string",
            "description": "Name of the primary contact (the account owner). Required when creating an account.",
            "example": "Jane Doe"
          },
          "config": {
            "$ref": "#/components/schemas/AccountConfig"
          }
        }
      },
      "CreateAccountRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AccountRequest"
          },
          {
            "type": "object",
            "required": [
              "email",
              "primary_contact_name",
              "pricing"
            ],
            "anyOf": [
              {
                "required": [
                  "address"
                ]
              },
              {
                "required": [
                  "billing_address"
                ]
              }
            ],
            "properties": {
              "address": {
                "$ref": "#/components/schemas/AddressInput",
                "description": "The account's physical address. Required. On creation it becomes the account's main location — the default location used for E911 and for tax and fee jurisdiction — so a single-site account is immediately correct for 911 and taxes and fees with no separate step. The address is geocoded via address validation. Edit it afterwards on the main location, not here."
              },
              "billing_address": {
                "$ref": "#/components/schemas/AddressInput",
                "deprecated": true,
                "description": "Deprecated: use `address`. Still accepted for backwards compatibility — when `address` is omitted it seeds the main location — but it is no longer authoritative; the account's address lives on the main location. `address` wins when both are sent."
              },
              "pricing": {
                "$ref": "#/components/schemas/AccountPricingRequest",
                "description": "Agreed monthly rates. Required — all three rates must be provided, and they are persisted atomically with the account (the account and its pricing commit together or not at all)."
              }
            }
          }
        ]
      },
      "UpdateAccountRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AccountRequest"
          },
          {
            "type": "object",
            "properties": {
              "default_outbound_did": {
                "type": "string",
                "description": "ID of the phone number to use as the default outbound caller ID. Send null to clear."
              },
              "hold_music_clip": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "ID of the audio clip played as hold music. Send null to clear (uses platform default)."
              },
              "main_location": {
                "type": "string",
                "description": "ID of the location to set as this account's main location. The\nlocation must belong to the account. The main location is the\nfallback for any user or phone number that doesn't have a\nspecific location of its own (roaming). Cannot be cleared once\nset — swap to another location instead. Omit to leave\nunchanged.\n"
              },
              "default_button_template": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "ID of a button template on the account to set as the default.\nCompatible deskphones and DECT handsets inherit it at creation.\nSend null to clear the default. Omit to leave unchanged.\n"
              },
              "billing_address": {
                "deprecated": true,
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/AddressInput"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Deprecated. The account's stored address snapshot. Editing it here no longer moves the account's physical location — the authoritative address lives on the main location, so relocate by editing that location's address instead. When present it is geocoded and stored; send null to clear; omit to leave unchanged."
              }
            }
          }
        ]
      },
      "UserRequest": {
        "type": "object",
        "properties": {
          "name": {
            "$ref": "#/components/schemas/EntityName"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Email address (optional)",
            "example": "bob@spineline.dev"
          }
        }
      },
      "CreateUserRequest": {
        "$ref": "#/components/schemas/UserRequest"
      },
      "UpdateUserRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/UserRequest"
          },
          {
            "type": "object",
            "properties": {
              "outbound_caller_id_did": {
                "type": "string",
                "description": "ID of the phone number to use as this user's outbound caller ID, overriding the account default. Send null to clear."
              },
              "voicemail_pin": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Numeric PIN for remote voicemail access (4-10 digits). Send null to clear.",
                "example": "1234"
              },
              "do_not_disturb": {
                "type": "boolean",
                "description": "Enable or disable server-side do-not-disturb for this user. Omit to leave unchanged. Must be a boolean — `null` is rejected.\n",
                "example": true
              },
              "config": {
                "type": "object",
                "description": "User configuration. Only provided fields are updated; omitted fields are left unchanged.",
                "properties": {
                  "voicemail_notifications": {
                    "$ref": "#/components/schemas/VoicemailNotificationConfig"
                  },
                  "find_me_follow_me": {
                    "description": "Find Me / Follow Me configuration. Send null to clear and revert to default behavior.",
                    "oneOf": [
                      {
                        "$ref": "#/components/schemas/FMFM"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "mobile_push_wakeup": {
                    "type": "boolean",
                    "description": "Whether incoming calls should be held for a wake-up window when this user has no active\nweb/mobile calling session, so a push notification can wake their app to answer.\n"
                  }
                }
              }
            }
          }
        ]
      },
      "UpdateVoicemailRequest": {
        "type": "object",
        "properties": {
          "is_read": {
            "type": "boolean",
            "description": "Mark voicemail as read or unread"
          }
        }
      },
      "CreateVoiceAppRequest": {
        "type": "object",
        "properties": {
          "name": {
            "$ref": "#/components/schemas/EntityName"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "HTTPS webhook URL for call control notifications",
            "example": "https://ai.platform.example.com/calls"
          }
        },
        "required": [
          "name",
          "url"
        ]
      },
      "UpdateCallRequest": {
        "type": "object",
        "description": "Request to control an active call by sending actions",
        "properties": {
          "actions": {
            "type": "array",
            "description": "List of actions to execute on the call. Actions are processed sequentially.\nEach action may block processing or allow it to continue based on its outcome.\n\n**Supported Actions:**\n\n### attach\nConnect bidirectional audio streaming to a WebSocket URL.\n\n- `type`: `\"attach\"`\n- `url`: WebSocket URL (wss://) for bidirectional audio streaming\n\n**Processing behavior:** This action blocks processing while the WebSocket\nconnection is active. When the WebSocket disconnects (either side closes),\nprocessing resumes with the next action.\n\nSee [WebSocket API](/websocket-api) for the message protocol.\n\n### transfer\nBlind transfer the call to an extension number, an E.164 phone\nnumber, or a SIP address.\n\n- `type`: `\"transfer\"`\n- `target`: Extension number, E.164 phone number, or `sip:` URI to\n  transfer to. A `sip:` URI lets you route the call to an external\n  SIP endpoint such as an AI voice agent\n  (e.g. `sip:agent-7f3c@sip.example-ai.com`).\n- `mode`: `\"blind\"` (default) connects the caller and drops the originator immediately. Only `\"blind\"` is accepted in this release.\n\n**Processing behavior:** If the transfer target answers or the caller hangs up,\nprocessing stops. If the transfer cannot be completed (no answer, busy, rejected),\nprocessing continues with the next action.\n",
            "items": {
              "$ref": "#/components/schemas/CallAction"
            },
            "minItems": 1
          }
        },
        "required": [
          "actions"
        ]
      },
      "CallAction": {
        "type": "object",
        "oneOf": [
          {
            "$ref": "#/components/schemas/AttachAction"
          },
          {
            "$ref": "#/components/schemas/TransferAction"
          }
        ],
        "discriminator": {
          "propertyName": "type",
          "mapping": {
            "attach": "#/components/schemas/AttachAction",
            "transfer": "#/components/schemas/TransferAction"
          }
        }
      },
      "AttachAction": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "attach"
            ],
            "description": "Action type"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "WebSocket URL (wss://) for bidirectional audio streaming",
            "example": "wss://ai.platform.example.com/voice"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Optional key/value pairs echoed on the media WebSocket `begin`\nmessage. Useful for correlating the stream with application-side\nstate (agent ID, queue, trace ID, etc.) without a separate lookup.\n",
            "example": {
              "agent_id": "user_01h2xcejqtf2nbrexx3vqjhp42",
              "queue": "support"
            }
          }
        },
        "required": [
          "type",
          "url"
        ]
      },
      "TransferAction": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "transfer"
            ],
            "description": "Action type"
          },
          "target": {
            "type": "string",
            "description": "Where to transfer the call. One of: an extension number, an E.164\nphone number, or a `sip:` URI for an external SIP endpoint such as\nan AI voice agent (e.g. `sip:agent-7f3c@sip.example-ai.com`).\n",
            "example": "+14165550123"
          },
          "mode": {
            "type": "string",
            "enum": [
              "blind"
            ],
            "description": "Transfer mode. `blind` connects the caller to the target and drops the originator immediately. Defaults to blind when omitted.",
            "example": "blind"
          }
        },
        "required": [
          "type",
          "target"
        ]
      },
      "Listener": {
        "type": "object",
        "description": "A listener streams real-time audio from an active call over a WebSocket connection.\nAudio flows unidirectionally from DialStack to your server. The call is not affected\nby the listener — both parties remain unaware that audio is being streamed.\n\nSee the [WebSocket API](/websocket-api) for the listener message protocol.\n",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              }
            ],
            "example": "lstn_01h2xcejqtf2nbrexx3vqjhp50"
          },
          "call_id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              }
            ],
            "description": "The active call being listened to",
            "example": "call_01h2xcejqtf2nbrexx3vqjhp45"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "WebSocket URL where audio is being streamed",
            "example": "wss://your-server.example.com/audio"
          },
          "channel": {
            "type": "string",
            "enum": [
              "caller",
              "callee",
              "both"
            ],
            "description": "Which audio channel(s) to stream:\n- `caller`: audio from the party that initiated the call\n- `callee`: audio from the party that received the call\n- `both`: both channels, delivered as separate tagged messages\n",
            "example": "both"
          },
          "created_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CreatedAt"
              }
            ]
          }
        },
        "required": [
          "id",
          "call_id",
          "url",
          "channel",
          "created_at"
        ]
      },
      "SetAgentStatusRequest": {
        "type": "object",
        "description": "Request to change a queue agent's availability state. `reason` is only\nvalid when `status` is `paused`; sending it with any other status\nreturns 400.\n",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "available",
              "paused",
              "logged_out"
            ],
            "description": "Target availability state:\n- `available` — the agent is logged in and eligible to receive calls\n- `paused` — the agent is logged in but temporarily unavailable\n- `logged_out` — the agent is not signed in to the queue\n",
            "example": "paused"
          },
          "reason": {
            "type": "string",
            "maxLength": 255,
            "description": "Optional free-form reason associated with a `paused` state\n(e.g., `break`, `lunch`, `training`). Only allowed when\n`status` is `paused`.\n",
            "example": "break"
          }
        },
        "required": [
          "status"
        ]
      },
      "AgentStatus": {
        "type": "object",
        "description": "Current availability state for a queue agent. Timestamps are omitted\nwhen the corresponding attribute has not been set.\n",
        "properties": {
          "user": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              }
            ],
            "description": "The agent (user) this status belongs to",
            "example": "user_01h2xcejqtf2nbrexx3vqjhp42"
          },
          "status": {
            "type": "string",
            "enum": [
              "available",
              "paused",
              "logged_out"
            ],
            "description": "Current availability state",
            "example": "paused"
          },
          "paused_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the agent entered the `paused` state, if applicable"
          },
          "pause_reason": {
            "type": "string",
            "description": "Free-form reason for the current pause, if provided",
            "example": "break"
          },
          "logged_in_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the agent first logged in to the queue"
          },
          "in_call_since": {
            "type": "string",
            "format": "date-time",
            "description": "When the agent's currently-active call started, if any"
          },
          "updated_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/UpdatedAt"
              }
            ]
          }
        },
        "required": [
          "user",
          "status",
          "updated_at"
        ]
      },
      "PresenceState": {
        "type": "string",
        "enum": [
          "available",
          "on_call",
          "offline"
        ],
        "description": "Real-time reachability of a user, derived live from the phone system:\n\n- `available` — reachable on a device and not currently on a call.\n- `on_call` — currently on a call.\n- `offline` — a verified read that found the user reachable on no device.\n\nThis is always a freshly verified value. When the underlying state\ncannot be confirmed, the request fails with `503` rather than returning\na stale or guessed value — there is no `unknown`.\n",
        "example": "available"
      },
      "WebRTCReachability": {
        "type": "object",
        "description": "A user's reachability over WebRTC (a browser or in-app softphone)\nspecifically, separate from the top-level `state`, which reflects any\nendpoint type. Use this to tell whether a user is genuinely reachable in\ntheir browser right now — e.g. to warn them their session has dropped\nbefore calls start skipping them.\n",
        "properties": {
          "state": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PresenceState"
              }
            ],
            "description": "WebRTC-only reachability, using the same values as `state` but\nscoped to WebRTC:\n\n- `available` — at least one live WebRTC session, ready to ring.\n- `on_call` — currently on a call answered in a WebRTC session.\n- `offline` — no live WebRTC session (the user may still be\n  reachable on another endpoint type; see the top-level `state`).\n\nUnlike the top-level `state`, this value does not carry a\nno-`unknown` guarantee in the strict sense: attributing a call to\nWebRTC specifically depends on a label the answering leg carries,\nand a call answered before that label was available reads as not-on-\nWebRTC rather than failing the request. This is deliberate — the\ntop-level `state` stays fully verified rather than being degraded to\na `503` over a WebRTC-only attribution gap. The condition is\ntransient and clears as calls turn over.\n"
          },
          "sessions": {
            "type": "integer",
            "description": "Number of live WebRTC sessions for the user (for example, the same\nuser signed in on two browser tabs counts as two).\n\nTreat this as eventually consistent in both directions, not as an\nexact live count. A session that reconnects (network change,\nsleep/wake) may be counted twice for a short window until the old\nconnection times out, so this can briefly over-count; a\njust-established session may not be counted yet, so it can briefly\nunder-count. In particular `sessions` can read `0` while `state` is\n`available` or `on_call` — `state` is the reachability answer, and\n`sessions` is a best-effort \"how many\" alongside it.\n",
            "example": 1
          }
        },
        "required": [
          "state",
          "sessions"
        ]
      },
      "UserPresence": {
        "type": "object",
        "description": "A user's current presence.",
        "properties": {
          "object": {
            "type": "string",
            "enum": [
              "user_presence"
            ],
            "description": "The resource this is. Always `user_presence`. Present on the\nsingleton read as well as on every element of a presence list, which\nis what tells user presence apart from the other presentity types a\nlist can carry.\n"
          },
          "state": {
            "$ref": "#/components/schemas/PresenceState"
          },
          "notifiable": {
            "type": "boolean",
            "description": "Whether the user can still be reached by waking a backgrounded or\nparked device when they are not currently registered. A separate\naxis from `state`: a user can be `offline` but `notifiable`.\n",
            "example": false
          },
          "do_not_disturb": {
            "type": "boolean",
            "description": "Whether server-side do-not-disturb is enabled for this user. A\nseparate axis from `state`: a user can be `available` but decline\ncalls because `do_not_disturb` is on.\n",
            "example": false
          },
          "webrtc": {
            "$ref": "#/components/schemas/WebRTCReachability"
          }
        },
        "required": [
          "object",
          "state",
          "notifiable",
          "do_not_disturb",
          "webrtc"
        ]
      },
      "UserPresenceItem": {
        "description": "A single user's presence within a presence response: every\n`UserPresence` field plus the user it belongs to. Composed with `allOf`\nso the singleton and bulk shapes cannot drift as fields are added — that\nincludes the `object` discriminator, which comes from `UserPresence`\nrather than being restated here.\n",
        "allOf": [
          {
            "$ref": "#/components/schemas/UserPresence"
          },
          {
            "type": "object",
            "properties": {
              "user": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/EntityId"
                  }
                ],
                "description": "The user this presence belongs to",
                "example": "user_01h2xcejqtf2nbrexx3vqjhp42"
              }
            },
            "required": [
              "user"
            ]
          }
        ]
      },
      "ParkedCall": {
        "type": "object",
        "description": "The call occupying a park slot — who is waiting, who parked them, and\nwhen they will be rung back.\n",
        "properties": {
          "call": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "type": "null"
              }
            ],
            "description": "The call this parked leg belongs to, or `null` if no call id was\nrecorded when the call was parked.\n\nA `null` here does not mean the slot is free: an occupant can be\npresent without a recorded call id. `parked_call` is what says whether\nthe slot is occupied.\n",
            "example": "call_01kyqarr27ejcscvv5wbw7c4h5"
          },
          "from_number": {
            "type": "string",
            "description": "The parked caller's number, in the same vocabulary as the call log's\n`from_number`.\n",
            "example": "+16135551234"
          },
          "from_label": {
            "type": "string",
            "description": "The parked caller's display name, in the same vocabulary as the call\nlog's `from_label`. Passed through as received: a locality or a\nplaceholder like `WIRELESS CALLER` are both things carriers send, and\nwhether to filter them is left to you.\n",
            "example": "JANE DOE"
          },
          "status": {
            "type": "string",
            "enum": [
              "parked",
              "ringing_back"
            ],
            "description": "`parked` while the caller waits, `ringing_back` once the park has\ntimed out and the parker's phones are being called. Both are occupied\nstates — the caller stays on hold throughout — so `ringing_back` is\nnot a slot that has been released.\n\nUse this rather than comparing `rings_back_at` against the clock:\nonly this field distinguishes a slot that is ringing back from one\nwhose deadline has merely passed.\n",
            "example": "parked"
          },
          "parked_by": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "type": "null"
              }
            ],
            "description": "The user who parked the call, or `null` if no parker id was\nrecorded, which likewise does not mean the slot is free.\n",
            "example": "user_01h2xcejqtf2nbrexx3vqjhp42"
          },
          "parked_by_extension": {
            "type": "string",
            "description": "The extension of the user who parked the call. Carried alongside\n`parked_by` so the parker can be identified without a second request.\nOmitted for a user with no extension.\n",
            "example": "1001"
          },
          "parked_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the call was parked.",
            "example": "2026-08-03T14:12:04Z"
          },
          "rings_back_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the call will ring back to whoever parked it, if nobody\nretrieves it first. The caller is not disconnected at this moment\nprovided somebody answers the ring-back; if nobody does, the call\nends there. If the parker's device is no longer reachable the\nring-back has nowhere to go, so treat this as intent rather than a\nguarantee — watch `status` for what actually happened.\n",
            "example": "2026-08-03T14:14:04Z"
          }
        },
        "required": [
          "call",
          "from_number",
          "from_label",
          "status",
          "parked_by",
          "parked_at",
          "rings_back_at"
        ]
      },
      "ParkSlotPresence": {
        "type": "object",
        "description": "One park slot's current state. It describes state rather than a\ntransition, so it fully replaces whatever was previously known about the\nslot, and receiving the same one twice changes nothing.\n\nA slot with nobody in it arrives as `parked_call: null`, which says the\nslot is now free rather than asserting that the slot durably exists.\nSlots absent from a snapshot are free.\n",
        "properties": {
          "object": {
            "type": "string",
            "enum": [
              "park_slot"
            ],
            "description": "The resource this is. Always `park_slot`, which is what tells it apart\nfrom the other presentity types a list can carry.\n"
          },
          "slot": {
            "type": "integer",
            "description": "The slot number, as dialled (`*68<slot>`).",
            "example": 3
          },
          "parked_call": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ParkedCall"
              },
              {
                "type": "null"
              }
            ],
            "description": "The occupant, or `null` when the slot is free. This is the only\nsignal of occupancy — there is no separate boolean to agree with. Its\nfields are present together or not at all, so a single null check\nsettles whether there is an occupant to read.\n\nAn occupant whose caller identity is unavailable is still an\noccupant: the object is present with its identity fields empty.\n"
          }
        },
        "required": [
          "object",
          "slot",
          "parked_call"
        ]
      },
      "CreateListenerRequest": {
        "type": "object",
        "description": "Request to create a listener on an active call",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Secure WebSocket URL where DialStack will stream audio. Must use\nthe `wss://` scheme; insecure `ws://` URLs are rejected with 422.\n",
            "example": "wss://your-server.example.com/audio"
          },
          "channel": {
            "type": "string",
            "enum": [
              "caller",
              "callee",
              "both"
            ],
            "default": "both",
            "description": "Which audio channel(s) to stream:\n- `caller`: audio from the party that initiated the call\n- `callee`: audio from the party that received the call\n- `both`: both channels, delivered as separate tagged messages\n",
            "example": "both"
          }
        },
        "required": [
          "url"
        ]
      },
      "UpdateVoiceAppRequest": {
        "type": "object",
        "properties": {
          "name": {
            "$ref": "#/components/schemas/EntityName"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "HTTPS webhook URL for call control notifications",
            "example": "https://ai.platform.example.com/calls"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "inactive"
            ],
            "description": "Voice app status"
          }
        }
      },
      "FAQItem": {
        "type": "object",
        "description": "A question-answer pair for the AI agent's FAQ responses.",
        "properties": {
          "question": {
            "type": "string",
            "description": "The question the AI agent should recognize",
            "maxLength": 2000,
            "example": "What are your business hours?"
          },
          "answer": {
            "type": "string",
            "description": "The answer the AI agent should provide",
            "maxLength": 2000,
            "example": "We are open Monday through Friday, 9 AM to 5 PM."
          }
        },
        "required": [
          "question",
          "answer"
        ]
      },
      "AIAgent": {
        "type": "object",
        "description": "An AI agent provides an AI-powered voice receptionist for handling incoming calls.\nEach AI agent automatically manages a voice app and extension for call routing.\nOptional instructions and FAQ responses customize the agent's behavior at call time.\n",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              }
            ],
            "example": "aia_01h2xcejqtf2nbrexx3vqjhp60"
          },
          "name": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityName"
              }
            ],
            "example": "Front Desk Receptionist"
          },
          "voice_app": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              }
            ],
            "description": "The managed voice app used for call routing",
            "example": "va_01h2xcejqtf2nbrexx3vqjhp49"
          },
          "persona_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "The name the AI agent uses to introduce itself on calls (e.g. \"Tony\"). Defaults to \"the receptionist\" if not set.",
            "maxLength": 255,
            "example": "Tony"
          },
          "greeting_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "The business name used in call greetings (e.g. \"Thanks for calling [Greeting Name]\"). When not set, the account name is used as a fallback.",
            "maxLength": 255,
            "example": "Jones Family Dental"
          },
          "instructions": {
            "type": [
              "string",
              "null"
            ],
            "description": "Custom instructions for the AI agent's behavior",
            "maxLength": 10000,
            "example": "You are the receptionist for Jones Family Dental. Be warm and professional."
          },
          "faq_responses": {
            "type": "array",
            "description": "Pre-configured question-answer pairs",
            "items": {
              "$ref": "#/components/schemas/FAQItem"
            }
          },
          "scheduling": {
            "$ref": "#/components/schemas/SchedulingConfig"
          },
          "extensions": {
            "description": "List of extensions routing to this AI agent. Only included when `expand[]=extensions` is requested.\n",
            "type": "object",
            "properties": {
              "object": {
                "type": "string",
                "enum": [
                  "list"
                ]
              },
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Extension"
                }
              }
            }
          },
          "created_at": {
            "$ref": "#/components/schemas/CreatedAt"
          },
          "updated_at": {
            "$ref": "#/components/schemas/UpdatedAt"
          }
        },
        "required": [
          "id",
          "name",
          "voice_app",
          "faq_responses",
          "created_at",
          "updated_at"
        ]
      },
      "CreateAIAgentRequest": {
        "type": "object",
        "description": "Request body for creating an AI agent.",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Display name for the AI agent",
            "example": "Front Desk Receptionist"
          },
          "extension_number": {
            "type": "string",
            "description": "Extension number to assign for routing calls to this agent",
            "example": "200"
          },
          "persona_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "The name the AI agent uses to introduce itself on calls",
            "maxLength": 255,
            "example": "Tony"
          },
          "greeting_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "The business name used in call greetings (e.g. \"Thanks for calling [Greeting Name]\"). When not set, the account name is used as a fallback.",
            "maxLength": 255,
            "example": "Jones Family Dental"
          },
          "instructions": {
            "type": [
              "string",
              "null"
            ],
            "description": "Custom instructions for the AI agent's behavior",
            "maxLength": 10000,
            "example": "You are the receptionist for Jones Family Dental."
          },
          "faq_responses": {
            "type": "array",
            "description": "Pre-configured question-answer pairs",
            "items": {
              "$ref": "#/components/schemas/FAQItem"
            }
          },
          "scheduling": {
            "$ref": "#/components/schemas/SchedulingConfig"
          }
        },
        "required": [
          "name"
        ]
      },
      "UpdateAIAgentRequest": {
        "type": "object",
        "description": "Request body for updating an AI agent. All fields are optional.",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Display name for the AI agent",
            "example": "Updated Receptionist"
          },
          "persona_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "The name the AI agent uses to introduce itself on calls",
            "maxLength": 255,
            "example": "Tony"
          },
          "greeting_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "The business name used in call greetings (e.g. \"Thanks for calling [Greeting Name]\"). When not set, the account name is used as a fallback.",
            "maxLength": 255,
            "example": "Jones Family Dental"
          },
          "instructions": {
            "type": [
              "string",
              "null"
            ],
            "description": "Custom instructions for the AI agent's behavior",
            "maxLength": 10000
          },
          "faq_responses": {
            "type": "array",
            "description": "Pre-configured question-answer pairs (replaces all existing items)",
            "items": {
              "$ref": "#/components/schemas/FAQItem"
            }
          },
          "scheduling": {
            "description": "Scheduling configuration. Replaces the entire scheduling object (not merged field-by-field). Omit entirely to leave unchanged.",
            "$ref": "#/components/schemas/SchedulingConfig"
          }
        }
      },
      "SchedulingConfig": {
        "type": "object",
        "description": "Scheduling webhook configuration. Scheduling is on when webhook_url is provided, off when absent or empty. DialStack appends standard paths to the base URL for each operation. This is a replace-all object — send the complete configuration on every update.",
        "properties": {
          "webhook_url": {
            "type": "string",
            "format": "uri",
            "description": "Base HTTPS URL for scheduling webhooks. DialStack appends paths for each operation: /customers/lookup, /availability/search, /bookings. Provide a URL to enable scheduling; omit or send empty to disable.",
            "maxLength": 2048
          }
        }
      },
      "CreateScheduleRequest": {
        "type": "object",
        "description": "Request body for creating a new schedule",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Display name for the schedule",
            "example": "Business Hours"
          },
          "timezone": {
            "type": "string",
            "description": "IANA timezone for interpreting times (e.g., \"America/New_York\")",
            "example": "America/New_York"
          },
          "ranges": {
            "type": "array",
            "description": "Weekly time ranges when the schedule is considered \"open\"",
            "items": {
              "$ref": "#/components/schemas/TimeRange"
            },
            "example": [
              {
                "day": 1,
                "start": "09:00",
                "end": "17:00"
              },
              {
                "day": 2,
                "start": "09:00",
                "end": "17:00"
              }
            ]
          },
          "holidays": {
            "type": "array",
            "description": "Date ranges when the schedule is closed regardless of weekly ranges",
            "items": {
              "$ref": "#/components/schemas/DateRange"
            }
          }
        },
        "required": [
          "name",
          "ranges"
        ]
      },
      "UpdateScheduleRequest": {
        "type": "object",
        "description": "Request body for updating a schedule (all fields optional).\nNote: The `hold` field cannot be updated via this endpoint.\nUse POST /schedules/{schedule_id}/hold to set a hold, or\nDELETE /schedules/{schedule_id}/hold to clear it.\n",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Display name for the schedule",
            "example": "Updated Business Hours"
          },
          "timezone": {
            "type": "string",
            "description": "IANA timezone for interpreting times",
            "example": "America/Los_Angeles"
          },
          "ranges": {
            "type": "array",
            "description": "Weekly time ranges when the schedule is considered \"open\"",
            "items": {
              "$ref": "#/components/schemas/TimeRange"
            }
          },
          "holidays": {
            "type": "array",
            "description": "Date ranges when the schedule is closed regardless of weekly ranges",
            "items": {
              "$ref": "#/components/schemas/DateRange"
            }
          }
        }
      },
      "HoldScheduleRequest": {
        "type": "object",
        "description": "Request body for setting a hold on a schedule.\nThe hold temporarily overrides the normal schedule calculation.\n",
        "properties": {
          "value": {
            "type": "boolean",
            "description": "Override value (true=force open, false=force closed)",
            "example": false
          },
          "until": {
            "type": "string",
            "format": "date-time",
            "description": "When the hold expires, as an absolute RFC3339 instant. If not provided,\ndefaults to midnight (00:00:00) the next day in the schedule's (or\naccount's) timezone.\n",
            "example": "2025-12-20T22:00:00Z"
          }
        },
        "required": [
          "value"
        ]
      },
      "DialPlan": {
        "type": "object",
        "description": "A dial plan defines how calls are routed through a series of steps,\nrepresented as a flowchart. Each step is called a **node**.\n\nSee the [Dial Plans Guide](/guides/dial-plans) for detailed documentation\nand examples.\n",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the dial plan",
            "example": "dp_01h2xcejqtf2nbrexx3vqjhp60"
          },
          "name": {
            "type": "string",
            "description": "Display name for the dial plan",
            "example": "Main Line Routing"
          },
          "entry_node": {
            "type": "string",
            "description": "ID of the first node to execute (the implicit Start node connects here)",
            "example": "check_hours"
          },
          "nodes": {
            "type": "array",
            "description": "All nodes in the dial plan graph",
            "items": {
              "$ref": "#/components/schemas/DialPlanNode"
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the dial plan was created",
            "example": "2025-10-18T10:00:00Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the dial plan was last modified",
            "example": "2025-10-18T10:00:00Z"
          },
          "extensions": {
            "description": "List of extensions assigned to this dial plan. Only included when `expand[]=extensions` is requested.\n",
            "type": "object",
            "properties": {
              "object": {
                "type": "string",
                "enum": [
                  "list"
                ]
              },
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Extension"
                }
              }
            }
          }
        },
        "required": [
          "id",
          "name",
          "entry_node",
          "nodes",
          "created_at",
          "updated_at"
        ]
      },
      "DialPlanNode": {
        "type": "object",
        "description": "A single step in a dial plan flowchart. Each node has a type that\ndetermines its behavior:\n\n- `schedule` — routes based on whether a schedule is currently open or closed; holidays optionally route to a dedicated branch\n- `internal_dial` — rings an internal target (user, ring group, call queue, dial plan, or shared voicemail) with timeout handling\n- `ring_all_users` — rings every user in the account at the same time\n- `external_dial` — dials an external phone number\n- `menu` — plays an audio prompt and routes based on DTMF input (IVR)\n- `audio_clip` — plays an audio clip then routes to the next node\n  (the legacy value `sound_clip` is still accepted on Create/Update\n  while in-flight clients catch up)\n- `voice_app` — hands the call off to a voice application via webhook\n- `hang_up` — ends the call with normal clearing\n\nThe shape of `config` is determined by `type` — see the individual\n`*NodeConfig` schemas.\n",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for this node within the dial plan",
            "example": "check_hours"
          },
          "type": {
            "type": "string",
            "enum": [
              "schedule",
              "internal_dial",
              "ring_all_users",
              "external_dial",
              "menu",
              "audio_clip",
              "sound_clip",
              "voice_app",
              "hang_up"
            ],
            "description": "The node type. Determines which `*NodeConfig` schema the `config`\nfield conforms to.\n",
            "example": "schedule"
          },
          "position": {
            "$ref": "#/components/schemas/DialPlanPosition"
          },
          "config": {
            "description": "Type-specific configuration. The schema is selected by the `type`\nfield:\n- `schedule` → `ScheduleNodeConfig`\n- `internal_dial` → `InternalDialNodeConfig`\n- `ring_all_users` → `RingAllUsersNodeConfig`\n- `external_dial` → `ExternalDialNodeConfig`\n- `menu` → `MenuNodeConfig`\n- `audio_clip` → `AudioClipNodeConfig` (legacy `sound_clip` is\n  accepted with the same shape)\n- `voice_app` → `VoiceAppNodeConfig`\n- `hang_up` → `HangUpNodeConfig`\n\nExit targets (the next node to execute) are embedded in the config\n(e.g. `open`/`closed` on schedule, `next` on dial nodes). A missing\nor null exit target terminates the call.\n",
            "oneOf": [
              {
                "$ref": "#/components/schemas/ScheduleNodeConfig"
              },
              {
                "$ref": "#/components/schemas/InternalDialNodeConfig"
              },
              {
                "$ref": "#/components/schemas/RingAllUsersNodeConfig"
              },
              {
                "$ref": "#/components/schemas/ExternalDialNodeConfig"
              },
              {
                "$ref": "#/components/schemas/MenuNodeConfig"
              },
              {
                "$ref": "#/components/schemas/AudioClipNodeConfig"
              },
              {
                "$ref": "#/components/schemas/VoiceAppNodeConfig"
              },
              {
                "$ref": "#/components/schemas/HangUpNodeConfig"
              }
            ]
          }
        },
        "required": [
          "id",
          "type",
          "config"
        ]
      },
      "DialPlanPosition": {
        "type": "object",
        "description": "X/Y coordinates for visual rendering in the dial plan editor.\nOptional - if not provided, the node will be auto-positioned.\n",
        "properties": {
          "x": {
            "type": "number",
            "format": "float",
            "description": "X coordinate in the visual editor",
            "example": 200
          },
          "y": {
            "type": "number",
            "format": "float",
            "description": "Y coordinate in the visual editor",
            "example": 100
          }
        },
        "required": [
          "x",
          "y"
        ]
      },
      "ScheduleNodeConfig": {
        "type": "object",
        "description": "Configuration for `schedule` nodes. Routes the call based on whether\nthe referenced schedule is currently open, closed, or on a holiday.\n\nHoliday routing is per-node opt-in: when `holiday` is omitted, holiday\nstate folds into the `closed` exit (the default for every dial plan).\nSet `holiday` to route holidays to a dedicated branch — for example,\na \"closed for holiday\" announcement that's distinct from the regular\nclosed-hours greeting.\n\nExit targets are optional — if omitted or null, the call terminates.\n",
        "properties": {
          "schedule": {
            "type": "string",
            "description": "ID of the schedule to check (returned by the Schedules API).\nMay be empty on draft dial plans (terminates the call).\n",
            "example": "sched_01h2xcejqtf2nbrexx3vqjhp50"
          },
          "open": {
            "type": [
              "string",
              "null"
            ],
            "description": "Node ID to route to when the schedule is open (null = terminate call)",
            "example": "reception"
          },
          "closed": {
            "type": [
              "string",
              "null"
            ],
            "description": "Node ID to route to when the schedule is closed (null = terminate call). Holiday state also routes here unless `holiday` is set.",
            "example": "voicemail"
          },
          "holiday": {
            "type": [
              "string",
              "null"
            ],
            "description": "Node ID to route to when the schedule is on a holiday. When omitted\nor null, holiday state folds into the `closed` exit.\n",
            "example": "holiday_announcement"
          }
        }
      },
      "InternalDialNodeConfig": {
        "type": "object",
        "description": "Configuration for `internal_dial` nodes. Rings an internal target and\nhandles no-answer / busy outcomes. If the call is answered the dial\nplan ends; otherwise it follows the `next` path (or terminates if\n`next` is missing or null).\n\n`target` may reference any of the following resources:\n\n- a **user** (returned by the Users API)\n- a **ring group** (returned by the Ring Groups API)\n- a **call queue** (returned by the Call Queues API)\n- a nested **dial plan** (returned by the Dial Plans API)\n- a **shared voicemail** (returned by the Voicemails API)\n- a **voice app** (deprecated; use the `voice_app` node type instead)\n\nThe runtime dispatches on the kind of resource the `target` points\nto. For shared-voicemail targets, and for targets with `timeout: 0`,\nthe call is delivered straight to voicemail and the dial plan ends —\n`next` is ignored in that case. For call-queue targets, the queue's\nown max-wait and timeout action take over once the caller is enqueued,\nand `next` is not used (except for the `timeout: 0` draft-skip).\n",
        "properties": {
          "target": {
            "type": "string",
            "description": "ID of the internal target to dial. May be empty on draft dial\nplans (skips to `next`).\n",
            "example": "user_01h2xcejqtf2nbrexx3vqjhp45"
          },
          "timeout": {
            "type": "integer",
            "minimum": 0,
            "maximum": 300,
            "default": 30,
            "description": "Ring timeout in seconds (0–300). A value of `0` delivers the call\ndirectly to the target without ringing; when the target is a user\nor shared voicemail, this routes straight to voicemail.\n",
            "example": 30
          },
          "next": {
            "type": [
              "string",
              "null"
            ],
            "description": "Node ID to route to on no-answer or busy (null = terminate call)",
            "example": "voicemail"
          }
        },
        "required": [
          "timeout"
        ]
      },
      "RingAllUsersNodeConfig": {
        "type": "object",
        "description": "Configuration for `ring_all_users` nodes. Rings every user in the\naccount at the same time and connects the first one to answer. If no\nuser answers within `timeout`, the call follows the `next` path (or\nterminates if `next` is missing or null).\n",
        "properties": {
          "timeout": {
            "type": "integer",
            "minimum": 1,
            "maximum": 300,
            "description": "Ring timeout in seconds (1–300)",
            "example": 24
          },
          "next": {
            "type": [
              "string",
              "null"
            ],
            "description": "Node ID to route to on no-answer (null = terminate call)",
            "example": "voicemail"
          }
        },
        "required": [
          "timeout"
        ]
      },
      "ExternalDialNodeConfig": {
        "type": "object",
        "description": "Configuration for `external_dial` nodes. Dials an external phone\nnumber over the PSTN. If the call is answered the dial plan ends;\notherwise it follows the `next` path (or terminates if `next` is\nmissing or null).\n",
        "properties": {
          "phone_number": {
            "type": "string",
            "pattern": "^(\\+[1-9]\\d{1,14})?$",
            "description": "Destination phone number in E.164 format (e.g. `+14155551234`).\nMay be empty on draft dial plans (skips to `next`).\n",
            "example": "+14155551234"
          },
          "timeout": {
            "type": "integer",
            "minimum": 1,
            "maximum": 120,
            "description": "Ring timeout in seconds (1–120)",
            "example": 60
          },
          "next": {
            "type": [
              "string",
              "null"
            ],
            "description": "Node ID to route to on no-answer or busy (null = terminate call)",
            "example": "voicemail"
          }
        },
        "required": [
          "timeout"
        ]
      },
      "MenuNodeConfig": {
        "type": "object",
        "description": "Configuration for `menu` nodes (IVR). Plays an audio prompt and waits\nfor DTMF input. Each digit maps to a next node in the dial plan.\n\nIf the caller presses an unmapped digit, the menu replays (or routes\nto `invalid_next_node` if connected). Any unconnected exit replays\nthe menu prompt.\n",
        "properties": {
          "prompt_clip": {
            "type": "string",
            "description": "ID of the audio clip to play as the menu prompt (returned by\nthe Audio Clips API). May be empty on draft dial plans — when\nempty, playback is skipped and the menu waits for DTMF directly.\n",
            "example": "aud_01h2xcejqtf2nbrexx3vqjhp50"
          },
          "timeout": {
            "type": "integer",
            "minimum": 1,
            "maximum": 30,
            "description": "Seconds to wait for DTMF input after the prompt finishes (1–30)",
            "example": 5
          },
          "options": {
            "type": "array",
            "maxItems": 12,
            "description": "DTMF digit-to-node mappings",
            "items": {
              "$ref": "#/components/schemas/MenuOption"
            }
          },
          "timeout_next_node": {
            "type": [
              "string",
              "null"
            ],
            "description": "Node ID to route to when no digit is pressed (null = replay menu prompt)",
            "example": "voicemail"
          },
          "invalid_next_node": {
            "type": [
              "string",
              "null"
            ],
            "description": "Node ID to route to when an unmapped digit is pressed (null = replay menu prompt)",
            "example": "operator"
          }
        },
        "required": [
          "timeout"
        ]
      },
      "MenuOption": {
        "type": "object",
        "description": "Maps a single DTMF digit to a destination node. Omit next_node to replay the menu prompt.",
        "properties": {
          "digit": {
            "type": "string",
            "pattern": "^[0-9*#]$",
            "description": "DTMF digit: 0–9, *, or #",
            "example": "1"
          },
          "next_node": {
            "type": [
              "string",
              "null"
            ],
            "description": "Node ID to route to when this digit is pressed (null = replay menu prompt).",
            "example": "sales"
          },
          "label": {
            "type": "string",
            "maxLength": 20,
            "description": "Optional human-readable description shown next to the digit in the\ndial-plan editor (e.g., \"Sales\"). Display-only — the runtime ignores\nthis field and routing is driven solely by `digit` and `next_node`.\n",
            "example": "Sales"
          }
        },
        "required": [
          "digit"
        ]
      },
      "AudioClipNodeConfig": {
        "type": "object",
        "description": "Configuration for `audio_clip` nodes (also accepted under the legacy\ntype name `sound_clip`). Plays an audio clip from the audio library\nthen immediately routes to the next node.\n",
        "properties": {
          "clip": {
            "type": "string",
            "description": "ID of the audio clip to play (returned by the Audio Clips API).\nMay be empty on draft dial plans (skips to `next`).\n",
            "example": "aud_01h2xcejqtf2nbrexx3vqjhp50"
          },
          "next": {
            "type": [
              "string",
              "null"
            ],
            "description": "Node ID to route to after playing the clip (null = terminate call)",
            "example": "main_menu"
          }
        }
      },
      "VoiceAppNodeConfig": {
        "type": "object",
        "description": "Configuration for `voice_app` nodes. Hands the call off to a voice\napplication via webhook dispatch. Voice apps do not ring; the dispatch\nis immediate.\n",
        "properties": {
          "voice_app": {
            "type": "string",
            "description": "ID of the voice app to route to. May be empty on draft dial plans.\n",
            "example": "va_01h2xcejqtf2nbrexx3vqjhp47"
          },
          "mode": {
            "type": "string",
            "enum": [
              "control",
              "notify"
            ],
            "default": "control",
            "description": "Dispatch mode:\n  - `control`: hands the call to the voice app. The webhook takes\n    ownership and decides what happens next via the Update Call API.\n  - `notify`: fires a `call.notify` webhook for visibility (BYO\n    Observer / transcription / analytics) while the dial plan\n    continues routing via `next`. The call is never answered or\n    held by this node.\n\n`notify` is rejected (422) when the referenced voice app is backed\nby an AI agent — those agents control calls and cannot function as\npassive observers. Use a plain webhook voice app for notify nodes.\n",
            "example": "control"
          },
          "next": {
            "type": [
              "string",
              "null"
            ],
            "description": "In `notify` mode, the always-taken continuation. In `control` mode,\nthe fallback on dispatch failure (null = terminate call).\n",
            "example": "voicemail"
          }
        }
      },
      "HangUpNodeConfig": {
        "type": "object",
        "description": "Configuration for `hang_up` nodes. Terminates the call with normal\nclearing. Zero-config; the canonical wire form is the empty object.\n",
        "additionalProperties": false
      },
      "CreateDialPlanRequest": {
        "type": "object",
        "description": "Request body for creating a new dial plan",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Display name for the dial plan",
            "example": "Main Line Routing"
          },
          "entry_node": {
            "type": "string",
            "description": "ID of the first node to execute (optional for draft dial plans)",
            "example": "check_hours"
          },
          "nodes": {
            "type": "array",
            "description": "All nodes in the dial plan graph",
            "items": {
              "$ref": "#/components/schemas/DialPlanNode"
            }
          }
        },
        "required": [
          "name"
        ]
      },
      "UpdateDialPlanRequest": {
        "type": "object",
        "description": "Request body for updating a dial plan. All fields are optional.\nWhen `nodes` is provided, it fully replaces all nodes (not a partial node update).\n",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Display name for the dial plan",
            "example": "Updated Main Line Routing"
          },
          "entry_node": {
            "type": "string",
            "description": "ID of the first node to execute",
            "example": "check_hours"
          },
          "nodes": {
            "type": "array",
            "description": "All nodes in the dial plan graph (full replacement)",
            "items": {
              "$ref": "#/components/schemas/DialPlanNode"
            }
          }
        }
      },
      "RingGroup": {
        "type": "object",
        "description": "A ring group for parallel dialing (call forking)",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "Ring group identifier",
                "example": "rg_01h2xcejqtf2nbrexx3vqjhp51"
              }
            ]
          },
          "name": {
            "type": "string",
            "description": "Display name",
            "example": "Sales Team"
          },
          "timeout_seconds": {
            "type": "integer",
            "minimum": 5,
            "maximum": 300,
            "description": "How long to ring members before giving up (seconds)",
            "example": 30
          },
          "ignore_forwarding": {
            "type": "boolean",
            "description": "When true, ignores SIP 302 redirects (call forwarding) from devices",
            "example": false
          },
          "confirm_external": {
            "type": "boolean",
            "description": "When true, requires external (phone number) members to press a key before being connected",
            "example": false
          },
          "timeout_action": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "ring_user",
              "voicemail",
              "queue",
              null
            ],
            "description": "Action to take when the ring group times out:\n* `ring_user` — ring the fallback user.\n* `voicemail` — send to voicemail (the user's box or a shared box, determined by `timeout_target`).\n* `queue` — overflow the caller into a queue.\n",
            "example": "voicemail"
          },
          "timeout_target": {
            "type": [
              "string",
              "null"
            ],
            "description": "ID of the timeout target — a user, shared voicemail box, or queue, paired with `timeout_action`.\nRequired when `timeout_action` is set.\n",
            "example": "user_01h2xcejqtf2nbrexx3vqjhp42"
          },
          "extensions": {
            "description": "List of extensions assigned to this ring group. Only included when `expand[]=extensions` is requested.\n",
            "type": "object",
            "properties": {
              "object": {
                "type": "string",
                "enum": [
                  "list"
                ]
              },
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Extension"
                }
              }
            }
          },
          "members": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RingGroupMember"
            },
            "description": "List of members in this ring group"
          },
          "created_at": {
            "$ref": "#/components/schemas/CreatedAt"
          },
          "updated_at": {
            "$ref": "#/components/schemas/UpdatedAt"
          }
        },
        "required": [
          "id",
          "name",
          "timeout_seconds",
          "ignore_forwarding",
          "confirm_external",
          "members",
          "created_at",
          "updated_at"
        ]
      },
      "RingGroupMember": {
        "type": "object",
        "description": "A member of a ring group (either an extension or phone number)",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "Member identifier",
                "example": "rgm_01h2xcejqtf2nbrexx3vqjhp52"
              }
            ]
          },
          "ring_group": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "Parent ring group"
              }
            ]
          },
          "extension": {
            "type": [
              "string",
              "null"
            ],
            "description": "ID of a routing target",
            "example": "user_01h2xcejqtf2nbrexx3vqjhp42"
          },
          "phone_number": {
            "type": [
              "string",
              "null"
            ],
            "description": "Dial string (E.164, local number, extension, 911, etc.)",
            "example": "+14155551234"
          },
          "created_at": {
            "$ref": "#/components/schemas/CreatedAt"
          }
        },
        "required": [
          "id",
          "ring_group",
          "created_at"
        ]
      },
      "CreateRingGroupRequest": {
        "type": "object",
        "description": "Request body for creating a ring group",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Display name for the ring group",
            "example": "Sales Team"
          },
          "timeout_seconds": {
            "type": "integer",
            "minimum": 5,
            "maximum": 300,
            "description": "How long to ring members (defaults to 20)",
            "example": 30
          },
          "ignore_forwarding": {
            "type": "boolean",
            "description": "Ignore SIP 302 redirects from devices",
            "example": false
          },
          "confirm_external": {
            "type": "boolean",
            "description": "Require external (phone number) members to press a key before being connected",
            "example": false
          },
          "timeout_action": {
            "type": "string",
            "enum": [
              "ring_user",
              "voicemail",
              "queue"
            ],
            "description": "Action to take when the ring group times out:\n* `ring_user` — ring the fallback user.\n* `voicemail` — send to voicemail (the user's box or a shared box, determined by `timeout_target`).\n* `queue` — overflow the caller into a queue.\n",
            "example": "voicemail"
          },
          "timeout_target": {
            "type": "string",
            "description": "ID of the timeout target — a user, shared voicemail box, or queue, paired with `timeout_action`.\nRequired when `timeout_action` is set.\n",
            "example": "user_01h2xcejqtf2nbrexx3vqjhp42"
          }
        },
        "required": [
          "name"
        ]
      },
      "UpdateRingGroupRequest": {
        "type": "object",
        "description": "Request body for updating a ring group (all fields optional).\nTo clear the timeout behavior, send `timeout_action` and `timeout_target` as `null`.\n",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "New display name",
            "example": "Support Team"
          },
          "timeout_seconds": {
            "type": "integer",
            "minimum": 5,
            "maximum": 300,
            "description": "New timeout value",
            "example": 45
          },
          "ignore_forwarding": {
            "type": "boolean",
            "description": "New ignore_forwarding setting",
            "example": true
          },
          "confirm_external": {
            "type": "boolean",
            "description": "New confirm_external setting",
            "example": true
          },
          "timeout_action": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "ring_user",
              "voicemail",
              "queue",
              null
            ],
            "description": "Action to take when the ring group times out:\n* `ring_user` — ring the fallback user.\n* `voicemail` — send to voicemail (the user's box or a shared box, determined by `timeout_target`).\n* `queue` — overflow the caller into a queue.\n\nSend `null` together with a `null` `timeout_target` to clear the timeout configuration.\n",
            "example": "voicemail"
          },
          "timeout_target": {
            "type": [
              "string",
              "null"
            ],
            "description": "ID of the timeout target — a user, shared voicemail box, or queue, paired with `timeout_action`.\nRequired when `timeout_action` is set.\n",
            "example": "user_01h2xcejqtf2nbrexx3vqjhp42"
          }
        }
      },
      "AddRingGroupMemberRequest": {
        "type": "object",
        "description": "Request body for adding a member (exactly one of extension or phone_number required)",
        "properties": {
          "extension": {
            "type": "string",
            "description": "ID of a routing target",
            "example": "user_01h2xcejqtf2nbrexx3vqjhp42"
          },
          "phone_number": {
            "type": "string",
            "description": "Dial string (E.164, local number, extension, 911, etc.)",
            "example": "+14155551234"
          }
        }
      },
      "QueueStrategy": {
        "type": "string",
        "enum": [
          "ringall",
          "linear",
          "rrmemory",
          "leastrecent",
          "fewestcalls",
          "random",
          "wrandom"
        ],
        "description": "Dispatch strategy for selecting which agent to ring next.\n* `ringall` — ring every available agent in parallel; first to answer wins.\n* `linear` — ring agents in `position` order, lowest first.\n* `rrmemory` — round-robin with memory; resumes after the last agent dialed.\n* `leastrecent` — ring the agent who has not taken a call for the longest time.\n* `fewestcalls` — ring the agent with the fewest calls taken in the current window.\n* `random` — pick uniformly at random from available agents.\n* `wrandom` — weighted random; lower `penalty` is more likely to be picked.\n"
      },
      "QueueEmptyPolicy": {
        "type": "string",
        "enum": [
          "strict",
          "no_agents_online",
          "no_agents_available"
        ],
        "description": "Policy used by `join_empty` and `leave_when_empty`.\n* `strict` — apply the policy whenever no agents exist on the queue.\n* `no_agents_online` — apply when no agents are logged in.\n* `no_agents_available` — apply when no agents are available (logged in and not paused / in-call / wrapping up).\n"
      },
      "QueueRingUserTimeout": {
        "type": "object",
        "description": "Ring a fallback user when `timeout_seconds` elapses.",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "ring_user"
            ]
          },
          "user": {
            "type": "string",
            "description": "ID of the user to ring.",
            "example": "user_01h2xcejqtf2nbrexx3vqjhp42"
          }
        },
        "required": [
          "type",
          "user"
        ]
      },
      "QueueVoicemailTimeout": {
        "type": "object",
        "description": "Send the caller to voicemail when `timeout_seconds` elapses. The\ntarget may be either a user (delivers to their personal voicemail)\nor a shared voicemail box.\n",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "voicemail"
            ]
          },
          "voicemail": {
            "type": "string",
            "description": "ID of the user or shared voicemail box that receives the message.",
            "example": "svm_01h2xcejqtf2nbrexx3vqjhp60"
          }
        },
        "required": [
          "type",
          "voicemail"
        ]
      },
      "QueueTimeout": {
        "description": "Discriminated configuration for what happens when a caller waits past\n`timeout_seconds`. Exactly one target field is set, matching `type`.\n\nSend `null` (instead of an object) on update to clear the timeout\nconfiguration.\n",
        "oneOf": [
          {
            "$ref": "#/components/schemas/QueueRingUserTimeout"
          },
          {
            "$ref": "#/components/schemas/QueueVoicemailTimeout"
          }
        ],
        "discriminator": {
          "propertyName": "type",
          "mapping": {
            "ring_user": "#/components/schemas/QueueRingUserTimeout",
            "voicemail": "#/components/schemas/QueueVoicemailTimeout"
          }
        }
      },
      "QueueCallbackConfig": {
        "type": "object",
        "description": "Press-1 callback configuration on a queue. Setting the `callback`\nfield on a Queue to this object enables callbacks; setting it to\n`null` disables them. `offer_after_seconds` controls the delay\nbefore the first press-1 offer; `outbound_did` is the optional\nper-queue outbound caller ID for callback originates (when null,\nthe dispatcher falls back to the captured inbound DID, then to the\naccount default outbound DID).\n",
        "properties": {
          "offer_after_seconds": {
            "type": "integer",
            "minimum": 0,
            "maximum": 3600,
            "description": "Delay before the first callback offer (seconds; 0 = immediate)",
            "example": 60
          },
          "outbound_did": {
            "type": [
              "string",
              "null"
            ],
            "description": "Per-queue callback outbound caller ID; null = fall back to inbound DID then account default",
            "example": "did_01h2xcejqtf2nbrexx3vqjhp44"
          }
        },
        "required": [
          "offer_after_seconds",
          "outbound_did"
        ]
      },
      "QueueCallbackConfigInput": {
        "type": "object",
        "description": "Request shape for configuring press-1 callbacks on a queue. Providing\nthe `callback` object enables callbacks; passing `callback: null`\ndisables them. Fields inside the object are optional: on create,\n`offer_after_seconds` defaults to 60 and omitted `outbound_did`\nmeans use the captured inbound DID, then the account default outbound\nDID. On update, omitted fields leave the current values unchanged, while\nexplicit `outbound_did: null` clears the per-queue outbound caller ID.\n",
        "properties": {
          "offer_after_seconds": {
            "type": "integer",
            "minimum": 0,
            "maximum": 3600,
            "description": "Delay before the first callback offer (seconds; 0 = immediate)",
            "example": 60
          },
          "outbound_did": {
            "type": [
              "string",
              "null"
            ],
            "description": "Per-queue callback outbound caller ID; null = fall back to inbound DID then account default",
            "example": "did_01h2xcejqtf2nbrexx3vqjhp44"
          }
        }
      },
      "QueueAnnouncementsConfig": {
        "type": "object",
        "description": "Periodic \"you are caller number N\" announcement configuration on a\nqueue. Setting the `announcements` field on a Queue to this object\nenables announcements; setting it to `null` disables them.\n",
        "properties": {
          "frequency_seconds": {
            "type": "integer",
            "minimum": 10,
            "maximum": 600,
            "description": "Cadence for position announcements (seconds).",
            "example": 30
          }
        },
        "required": [
          "frequency_seconds"
        ]
      },
      "QueueAnnouncementsConfigInput": {
        "type": "object",
        "description": "Request shape for configuring position announcements on a queue.\nProviding the `announcements` object enables announcements; passing\n`announcements: null` disables them. `frequency_seconds` is optional:\non create it defaults to 30, on update an omitted field leaves the\ncurrent value unchanged.\n",
        "properties": {
          "frequency_seconds": {
            "type": "integer",
            "minimum": 10,
            "maximum": 600,
            "description": "Cadence for position announcements (seconds).",
            "example": 30
          }
        }
      },
      "EmbeddedQueueMembers": {
        "type": "object",
        "description": "Sub-collection of queue members embedded on the parent queue.\nCapped at 10 entries; use `next_page_url` (or `GET /v1/queues/{queue_id}/members`)\nto page through the rest.\n",
        "properties": {
          "object": {
            "$ref": "#/components/schemas/ListObject"
          },
          "url": {
            "$ref": "#/components/schemas/ListUrl"
          },
          "next_page_url": {
            "$ref": "#/components/schemas/NextPageUrl"
          },
          "previous_page_url": {
            "$ref": "#/components/schemas/PreviousPageUrl"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/QueueMember"
            }
          },
          "total_count": {
            "type": "integer",
            "description": "Total number of members on the queue (not just the embedded page).",
            "example": 12
          }
        },
        "required": [
          "object",
          "url",
          "data",
          "total_count"
        ]
      },
      "Queue": {
        "type": "object",
        "description": "A call queue. Callers reaching the queue are placed on hold and dispatched\nto a member (agent) according to the configured `strategy`. Members are\nusers; an agent's availability is tracked separately via\n`GET /v1/users/{user_id}/queue-agent`.\n",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "Queue identifier",
                "example": "qu_01h2xcejqtf2nbrexx3vqjhp61"
              }
            ]
          },
          "name": {
            "type": "string",
            "description": "Display name",
            "example": "Support"
          },
          "strategy": {
            "$ref": "#/components/schemas/QueueStrategy"
          },
          "timeout_seconds": {
            "type": "integer",
            "minimum": 0,
            "maximum": 3600,
            "description": "How long a caller waits before the `timeout` action fires. `0` means\nno timeout — callers wait until an agent answers or they hang up.\n",
            "example": 120
          },
          "wrap_up_seconds": {
            "type": "integer",
            "minimum": 0,
            "maximum": 600,
            "description": "Cool-down per agent after each call ends, during which the agent is\nnot eligible for dispatch. `0` disables wrap-up.\n",
            "example": 15
          },
          "announcements": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/QueueAnnouncementsConfig"
              },
              {
                "type": "null"
              }
            ],
            "description": "Position-announcement configuration; null when announcements are disabled."
          },
          "callback": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/QueueCallbackConfig"
              },
              {
                "type": "null"
              }
            ],
            "description": "Press-1 callback configuration; null when callbacks are disabled"
          },
          "timeout": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/QueueTimeout"
              },
              {
                "type": "null"
              }
            ],
            "description": "Fallback action when `timeout_seconds` elapses. `null` means\n\"hang up the caller\" — the timer still fires when\n`timeout_seconds > 0`. To opt out of any timeout entirely\n(callers wait until an agent picks up or they hang up), set\n`timeout_seconds` to `0`; `timeout` is then irrelevant.\n"
          },
          "max_queue_length": {
            "type": "integer",
            "minimum": 0,
            "description": "Maximum number of callers waiting at once. `0` means unlimited.\nWhen the limit is reached, external callers hear a \"queue full\"\nannouncement and are hung up; internal callers receive `486 Busy`.\n",
            "example": 50
          },
          "join_empty": {
            "$ref": "#/components/schemas/QueueEmptyPolicy"
          },
          "leave_when_empty": {
            "$ref": "#/components/schemas/QueueEmptyPolicy"
          },
          "members": {
            "$ref": "#/components/schemas/EmbeddedQueueMembers"
          },
          "extensions": {
            "description": "Extensions assigned to this queue. Only included when `expand[]=extensions`\nis requested.\n",
            "type": "object",
            "properties": {
              "object": {
                "type": "string",
                "enum": [
                  "list"
                ]
              },
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Extension"
                }
              }
            }
          },
          "created_at": {
            "$ref": "#/components/schemas/CreatedAt"
          },
          "updated_at": {
            "$ref": "#/components/schemas/UpdatedAt"
          }
        },
        "required": [
          "id",
          "name",
          "strategy",
          "timeout_seconds",
          "wrap_up_seconds",
          "announcements",
          "callback",
          "timeout",
          "max_queue_length",
          "join_empty",
          "leave_when_empty",
          "members",
          "created_at",
          "updated_at"
        ]
      },
      "QueueMember": {
        "type": "object",
        "description": "A user agent assigned to a call queue.",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "Queue member identifier",
                "example": "qum_01h2xcejqtf2nbrexx3vqjhp62"
              }
            ]
          },
          "queue": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "Parent queue",
                "example": "qu_01h2xcejqtf2nbrexx3vqjhp61"
              }
            ]
          },
          "user": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "User who acts as the agent",
                "example": "user_01h2xcejqtf2nbrexx3vqjhp42"
              }
            ]
          },
          "penalty": {
            "type": "integer",
            "minimum": 0,
            "description": "Strategy hint. Lower-penalty agents are preferred by `linear`,\n`wrandom`, and tie-breakers in other strategies. Defaults to `0`.\n",
            "example": 0
          },
          "position": {
            "type": "integer",
            "minimum": 1,
            "description": "1-based ordering within the queue, used by `linear` and `rrmemory`\nfor deterministic rotation. Members default to the next free\nposition; pass an explicit `position` to insert mid-list.\n",
            "example": 3
          },
          "created_at": {
            "$ref": "#/components/schemas/CreatedAt"
          }
        },
        "required": [
          "id",
          "queue",
          "user",
          "penalty",
          "position",
          "created_at"
        ]
      },
      "CreateQueueRequest": {
        "type": "object",
        "description": "Request body for creating a queue.",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Display name for the queue.",
            "example": "Support"
          },
          "strategy": {
            "allOf": [
              {
                "$ref": "#/components/schemas/QueueStrategy"
              }
            ],
            "description": "Dispatch strategy. Defaults to `ringall`."
          },
          "timeout_seconds": {
            "type": "integer",
            "minimum": 0,
            "maximum": 3600,
            "default": 300,
            "description": "Caller wait limit before `timeout` fires. Defaults to `300`\n(5 minutes) so a caller can't sit forever if every eligible\nagent goes offline. When the timer fires, `timeout` decides\nwhat happens — `null`/omitted means hang up. Pass `0` to opt\nout of any timeout entirely (callers wait indefinitely until\nan agent picks up or they hang up).\n",
            "example": 120
          },
          "wrap_up_seconds": {
            "type": "integer",
            "minimum": 0,
            "maximum": 600,
            "description": "Per-agent cool-down after each call. Defaults to `0`.",
            "example": 15
          },
          "announcements": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/QueueAnnouncementsConfigInput"
              },
              {
                "type": "null"
              }
            ],
            "description": "Position-announcement config. Pass an object (with any subset of\nfields) to enable announcements; omit or pass null to disable.\n"
          },
          "callback": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/QueueCallbackConfigInput"
              },
              {
                "type": "null"
              }
            ],
            "description": "Press-1 callback config. Pass an object (with any subset of\nfields) to enable callbacks; omit or pass null to disable.\n"
          },
          "timeout": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/QueueTimeout"
              },
              {
                "type": "null"
              }
            ],
            "description": "Fallback action when `timeout_seconds` elapses. Omitting or\nsending `null` means \"hang up\" — the timer still fires\nbecause `timeout_seconds` defaults to `300`. To opt out of\nany timer, set `timeout_seconds: 0`; `timeout` is then\nignored.\n"
          },
          "max_queue_length": {
            "type": "integer",
            "minimum": 0,
            "description": "Maximum number of waiting callers. `0` = unlimited (default).",
            "example": 50
          },
          "join_empty": {
            "$ref": "#/components/schemas/QueueEmptyPolicy"
          },
          "leave_when_empty": {
            "$ref": "#/components/schemas/QueueEmptyPolicy"
          }
        },
        "required": [
          "name"
        ]
      },
      "UpdateQueueRequest": {
        "type": "object",
        "description": "Request body for updating a queue. All fields are optional.\n\nSending `{\"callback\": null}` disables callbacks; sending\n`{\"callback\": {...}}` enables and applies the provided fields. Within\nthe callback object, omitting `outbound_did` leaves the existing\nDID untouched, while sending an explicit `null` clears it. The same\npattern applies to `timeout` at the top level — send `null` to clear,\nomit to leave unchanged.\n",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255
          },
          "strategy": {
            "$ref": "#/components/schemas/QueueStrategy"
          },
          "timeout_seconds": {
            "type": "integer",
            "minimum": 0,
            "maximum": 3600
          },
          "wrap_up_seconds": {
            "type": "integer",
            "minimum": 0,
            "maximum": 600
          },
          "announcements": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/QueueAnnouncementsConfigInput"
              },
              {
                "type": "null"
              }
            ],
            "description": "Position-announcement config. Pass null to disable; pass an object\nto enable/update. Omitted leaves the existing value untouched.\n"
          },
          "callback": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/QueueCallbackConfigInput"
              },
              {
                "type": "null"
              }
            ],
            "description": "Press-1 callback config. Pass null to disable; pass an object to\nenable/update. Omitted leaves the existing value untouched.\n"
          },
          "timeout": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/QueueTimeout"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send `null` to clear timeout behavior; omit to leave unchanged."
          },
          "max_queue_length": {
            "type": "integer",
            "minimum": 0
          },
          "join_empty": {
            "$ref": "#/components/schemas/QueueEmptyPolicy"
          },
          "leave_when_empty": {
            "$ref": "#/components/schemas/QueueEmptyPolicy"
          }
        }
      },
      "AddQueueMemberRequest": {
        "type": "object",
        "description": "Request body for adding a user agent to a queue.",
        "properties": {
          "user": {
            "type": "string",
            "description": "User TypeID (`user_...`) of the agent to add.",
            "example": "user_01h2xcejqtf2nbrexx3vqjhp42"
          },
          "penalty": {
            "type": "integer",
            "minimum": 0,
            "description": "Strategy hint. Defaults to `0`.",
            "example": 0
          },
          "position": {
            "type": "integer",
            "minimum": 1,
            "description": "1-based insertion position. Defaults to the end of the queue.",
            "example": 3
          }
        },
        "required": [
          "user"
        ]
      },
      "File": {
        "type": "object",
        "description": "An uploaded file scoped to an account. Returned inline when a resource\nthat references a file is expanded (e.g. a fax under `expand[]=file`).\n",
        "properties": {
          "object": {
            "type": "string",
            "enum": [
              "file"
            ],
            "description": "String representing the object's type."
          },
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "File identifier."
              }
            ]
          },
          "purpose": {
            "type": "string",
            "description": "What the file is used for (e.g. `fax_source`).",
            "example": "fax_source"
          },
          "filename": {
            "type": [
              "string",
              "null"
            ],
            "description": "Original uploaded filename, if known.",
            "example": "invoice.pdf"
          },
          "type": {
            "type": [
              "string",
              "null"
            ],
            "description": "Short type derived from the MIME type (e.g. `pdf`), or null when unrecognized.",
            "example": "pdf"
          },
          "mime_type": {
            "type": "string",
            "description": "Detected or declared content type.",
            "example": "application/pdf"
          },
          "size": {
            "type": "integer",
            "description": "File size in bytes.",
            "example": 51234
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "description": "A time-limited signed URL for the file's bytes, populated at\nresponse time only. Null unless the file was returned via an expand.\n"
          },
          "created_at": {
            "$ref": "#/components/schemas/CreatedAt"
          },
          "updated_at": {
            "$ref": "#/components/schemas/UpdatedAt"
          }
        },
        "required": [
          "object",
          "id",
          "purpose",
          "filename",
          "type",
          "mime_type",
          "size",
          "url",
          "created_at",
          "updated_at"
        ]
      },
      "Fax": {
        "type": "object",
        "description": "A fax record. Outbound faxes progress `pending` → `delivered`/`failed`;\ninbound faxes are stored as `received`. The fax document is the `file`,\nreachable as a signed URL via `expand[]=file`.\n",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "Fax identifier"
              }
            ]
          },
          "direction": {
            "type": "string",
            "enum": [
              "inbound",
              "outbound"
            ],
            "description": "Whether the fax was sent or received."
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "delivered",
              "failed",
              "received"
            ],
            "description": "Lifecycle state of the fax."
          },
          "file": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "$ref": "#/components/schemas/File"
              },
              {
                "type": "null"
              }
            ],
            "description": "The fax document. The file's id by default; the full File object\ncarrying a time-limited signed `url` when `expand[]=file` is\nrequested; null until the document exists (an inbound row before\nreceipt, or a failed fax).\n"
          },
          "did": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "$ref": "#/components/schemas/DIDSummary"
              }
            ],
            "description": "Your own number on the fax — the source DID for outbound, the\nterminating DID for inbound. The DID's id by default; the\nDIDSummary object when `expand[]=did` is requested.\n"
          },
          "from_number": {
            "type": [
              "string",
              "null"
            ],
            "description": "Sender's number in E.164. Null on inbound when the caller ID was withheld.",
            "example": "+14155551234"
          },
          "to_number": {
            "type": [
              "string",
              "null"
            ],
            "description": "Recipient's number in E.164.",
            "example": "+14155559876"
          },
          "call_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "ID of the call leg that carried the fax, if any."
          },
          "pages": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Number of pages transmitted, once known.",
            "example": 3
          },
          "source_pages": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Page count of the source document (outbound only). Null on inbound\nand until known. Pair with `pages` to show progress while sending,\ne.g. \"15 of 30 sent\".\n",
            "example": 30
          },
          "transport": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "t38",
              "g711",
              null
            ],
            "description": "Transport the leg negotiated. Null while pending or if the fax failed before negotiation."
          },
          "error_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "Error code when the fax failed."
          },
          "attempts": {
            "type": "integer",
            "description": "Number of delivery attempts made.",
            "example": 1
          },
          "read_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the fax was marked read, or null if unread. Read state is the\nnull-ness of this field; applies to inbound (received) faxes.\n"
          },
          "submitted_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the fax was submitted to the carrier."
          },
          "completed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the fax reached a terminal state."
          },
          "created_at": {
            "$ref": "#/components/schemas/CreatedAt"
          },
          "updated_at": {
            "$ref": "#/components/schemas/UpdatedAt"
          }
        },
        "required": [
          "id",
          "direction",
          "status",
          "file",
          "did",
          "from_number",
          "to_number",
          "call_id",
          "pages",
          "source_pages",
          "transport",
          "error_code",
          "attempts",
          "read_at",
          "submitted_at",
          "completed_at",
          "created_at",
          "updated_at"
        ]
      },
      "AudioClip": {
        "type": "object",
        "description": "An uploaded audio file for hold music, IVR prompts, or other audio playback",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "Audio clip identifier"
              }
            ]
          },
          "name": {
            "type": "string",
            "description": "Display name (unique per account)",
            "example": "Hold Music"
          },
          "url": {
            "type": "string",
            "description": "Signed URL for downloading the audio file (expires after 5 minutes)",
            "example": "https://cdn.example.com/audio-clips/clip.wav?Expires=..."
          },
          "mime_type": {
            "type": "string",
            "description": "MIME type of the stored audio file",
            "example": "audio/wav"
          },
          "duration_ms": {
            "type": "integer",
            "description": "Duration of the audio clip in milliseconds",
            "example": 30000
          },
          "size_bytes": {
            "type": "integer",
            "format": "int64",
            "description": "Size of the stored audio file in bytes",
            "example": 240000
          },
          "source_sha256": {
            "type": [
              "string",
              "null"
            ],
            "description": "SHA-256 hash of the original uploaded file (before transcoding)",
            "example": "113a95dbbfd24492fb4e527b58d64aece235d6a5057ea671dbf2fe980a9cf6a3"
          },
          "created_at": {
            "$ref": "#/components/schemas/CreatedAt"
          },
          "updated_at": {
            "$ref": "#/components/schemas/UpdatedAt"
          }
        },
        "required": [
          "id",
          "name",
          "url",
          "mime_type",
          "duration_ms",
          "size_bytes",
          "created_at",
          "updated_at"
        ]
      },
      "UpdateAudioClipRequest": {
        "type": "object",
        "description": "Request body for updating an audio clip (all fields optional)",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "New display name",
            "example": "Updated Hold Music"
          }
        }
      },
      "SharedVoicemailBox": {
        "type": "object",
        "description": "A shared voicemail box for team or departmental voicemail",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "Shared voicemail box identifier",
                "example": "svm_01h2xcejqtf2nbrexx3vqjhp60"
              }
            ]
          },
          "name": {
            "type": "string",
            "description": "Display name",
            "example": "Sales Voicemail"
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "description": "Email address to send voicemail notifications to",
            "example": "sales@example.com"
          },
          "pin": {
            "type": [
              "string",
              "null"
            ],
            "description": "PIN code for accessing the voicemail box (4-10 digits)",
            "example": "1234"
          },
          "email_attach_audio": {
            "type": "boolean",
            "description": "Whether to attach the audio recording to notification emails",
            "example": true
          },
          "email_include_summary": {
            "type": "boolean",
            "description": "Whether to include a summary in notification emails",
            "example": true
          },
          "email_include_transcript": {
            "type": "boolean",
            "description": "Whether to include a transcript in notification emails",
            "example": true
          },
          "delete_after_email": {
            "type": "boolean",
            "description": "Whether to delete the voicemail after sending the email notification",
            "example": true
          },
          "extensions": {
            "description": "List of extensions assigned to this shared voicemail box. Only included when `expand[]=extensions` is requested.\n",
            "type": "object",
            "properties": {
              "object": {
                "type": "string",
                "enum": [
                  "list"
                ]
              },
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Extension"
                }
              }
            }
          },
          "created_at": {
            "$ref": "#/components/schemas/CreatedAt"
          },
          "updated_at": {
            "$ref": "#/components/schemas/UpdatedAt"
          }
        },
        "required": [
          "id",
          "name",
          "email_attach_audio",
          "email_include_summary",
          "email_include_transcript",
          "delete_after_email",
          "created_at",
          "updated_at"
        ]
      },
      "CreateSharedVoicemailBoxRequest": {
        "type": "object",
        "description": "Request body for creating a shared voicemail box",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Display name for the shared voicemail box",
            "example": "Sales Voicemail"
          },
          "email": {
            "type": "string",
            "description": "Email address to send voicemail notifications to",
            "example": "sales@example.com"
          },
          "pin": {
            "type": "string",
            "pattern": "^\\d{4,10}$",
            "description": "PIN code for accessing the voicemail box (4-10 digits)",
            "example": "1234"
          },
          "email_attach_audio": {
            "type": "boolean",
            "description": "Whether to attach the audio recording to notification emails (defaults to true)",
            "example": true
          },
          "email_include_summary": {
            "type": "boolean",
            "description": "Whether to include a summary in notification emails (defaults to true)",
            "example": true
          },
          "email_include_transcript": {
            "type": "boolean",
            "description": "Whether to include a transcript in notification emails (defaults to true)",
            "example": true
          },
          "delete_after_email": {
            "type": "boolean",
            "description": "Whether to delete the voicemail after sending the email notification (defaults to true)",
            "example": true
          }
        },
        "required": [
          "name"
        ]
      },
      "UpdateSharedVoicemailBoxRequest": {
        "type": "object",
        "description": "Request body for updating a shared voicemail box (all fields optional).\nTo clear optional fields, send them as `null`.\n",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "New display name",
            "example": "Support Voicemail"
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "description": "Email address to send voicemail notifications to",
            "example": "support@example.com"
          },
          "pin": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^\\d{4,10}$",
            "description": "PIN code for accessing the voicemail box (4-10 digits)",
            "example": "5678"
          },
          "email_attach_audio": {
            "type": "boolean",
            "description": "Whether to attach the audio recording to notification emails",
            "example": false
          },
          "email_include_summary": {
            "type": "boolean",
            "description": "Whether to include a summary in notification emails",
            "example": false
          },
          "email_include_transcript": {
            "type": "boolean",
            "description": "Whether to include a transcript in notification emails",
            "example": false
          },
          "delete_after_email": {
            "type": "boolean",
            "description": "Whether to delete the voicemail after sending the email notification",
            "example": false
          }
        }
      },
      "AssignUserToDeviceRequest": {
        "type": "object",
        "description": "Request body for assigning a user to a device",
        "properties": {
          "user": {
            "type": "string",
            "description": "The user to assign to the deskphone",
            "example": "01h2xcejqtf2nbrexx3vqjhp42"
          }
        },
        "required": [
          "user"
        ]
      },
      "DeviceUserAssignment": {
        "type": "object",
        "description": "A user assigned to a device",
        "properties": {
          "user": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "The assigned user",
                "example": "01h2xcejqtf2nbrexx3vqjhp42"
              }
            ]
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "The device",
                "example": "01h2xcejqtf2nbrexx3vqjhp50"
              }
            ]
          },
          "line_number": {
            "type": "integer",
            "minimum": 1,
            "maximum": 24,
            "description": "Physical line key number assigned to this user",
            "example": 1
          },
          "created_at": {
            "$ref": "#/components/schemas/CreatedAt"
          }
        },
        "required": [
          "user",
          "device",
          "created_at"
        ]
      },
      "DeviceLine": {
        "type": "object",
        "description": "A SIP line assignment on a provisioned device, mapping a line key to a SIP endpoint",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "Device line identifier",
                "example": "dln_01h2xcejqtf2nbrexx3vqjhp55"
              }
            ]
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "Parent device",
                "example": "dev_01h2xcejqtf2nbrexx3vqjhp50"
              }
            ]
          },
          "endpoint": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "The SIP endpoint assigned to this line",
                "example": "ep_01h2xcejqtf2nbrexx3vqjhp43"
              }
            ]
          },
          "line_number": {
            "type": "integer",
            "minimum": 1,
            "maximum": 24,
            "description": "Physical line key number on the device",
            "example": 1
          },
          "created_at": {
            "$ref": "#/components/schemas/CreatedAt"
          },
          "updated_at": {
            "$ref": "#/components/schemas/UpdatedAt"
          }
        },
        "required": [
          "id",
          "device",
          "endpoint",
          "line_number",
          "created_at",
          "updated_at"
        ]
      },
      "CreateDeviceLineRequest": {
        "type": "object",
        "description": "Request body for creating a device line",
        "properties": {
          "endpoint": {
            "type": "string",
            "description": "ID of the SIP endpoint to assign to this line",
            "example": "ep_01h2xcejqtf2nbrexx3vqjhp43"
          }
        },
        "required": [
          "endpoint"
        ]
      },
      "UpdateDeviceLineRequest": {
        "type": "object",
        "description": "Request body for reassigning a device line to a different endpoint",
        "properties": {
          "endpoint": {
            "type": "string",
            "description": "ID of the new SIP endpoint to assign to this line",
            "example": "ep_01h2xcejqtf2nbrexx3vqjhp44"
          }
        },
        "required": [
          "endpoint"
        ]
      },
      "ButtonType": {
        "type": "string",
        "enum": [
          "line",
          "blf_extension",
          "blf_park",
          "blf_voicemail_shared",
          "blf_queue_agent",
          "blf_queue_depth",
          "speed_dial",
          "dtmf",
          "voicemail",
          "url",
          "multicast",
          "conference",
          "transfer",
          "forward",
          "park",
          "intercom",
          "dnd",
          "record_toggle"
        ],
        "description": "Programmable key behavior discriminator."
      },
      "ButtonTarget": {
        "type": "object",
        "description": "Type-specific button payload. Examples include `{\"user\":\"user_...\"}`,\n`{\"queue\":\"qu_...\"}`, `{\"destination\":\"+14155551234\"}`,\n`{\"slot\":1}`, or `{}` depending on `type`.\n",
        "additionalProperties": true,
        "example": {
          "user": "user_01h2xcejqtf2nbrexx3vqjhp42"
        }
      },
      "ButtonCompatibilityVerdict": {
        "type": "object",
        "properties": {
          "supported": {
            "type": "boolean",
            "description": "Whether this device can render the button."
          },
          "reason": {
            "type": "string",
            "description": "Stable reason when unsupported.",
            "enum": [
              "vendor_does_not_support_type",
              "position_out_of_range_for_model",
              "device_has_no_owning_user"
            ]
          }
        },
        "required": [
          "supported"
        ]
      },
      "ButtonCompatibilitySummary": {
        "type": "object",
        "properties": {
          "device": {
            "type": "object",
            "properties": {
              "vendor": {
                "type": "string",
                "example": "snom"
              },
              "model": {
                "type": "string",
                "example": "D785"
              },
              "kind": {
                "type": "string",
                "enum": [
                  "deskphone",
                  "dect_base",
                  "dect_handset"
                ]
              },
              "max_position": {
                "type": "integer",
                "description": "Highest programmable key position known for this device model."
              }
            },
            "required": [
              "vendor",
              "model",
              "kind",
              "max_position"
            ]
          },
          "supported_count": {
            "type": "integer",
            "description": "Number of buttons supported by this device."
          },
          "unsupported": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "template_button": {
                  "type": "string",
                  "example": "btn_01h2xcejqtf2nbrexx3vqjhp71"
                },
                "override": {
                  "type": "string",
                  "example": "devbtn_01h2xcejqtf2nbrexx3vqjhp72"
                },
                "position": {
                  "type": "integer",
                  "minimum": 1
                },
                "type": {
                  "$ref": "#/components/schemas/ButtonType"
                },
                "reason": {
                  "type": "string",
                  "enum": [
                    "vendor_does_not_support_type",
                    "position_out_of_range_for_model",
                    "device_has_no_owning_user"
                  ]
                }
              },
              "required": [
                "position",
                "type",
                "reason"
              ]
            }
          }
        },
        "required": [
          "device",
          "supported_count",
          "unsupported"
        ]
      },
      "ButtonTemplate": {
        "type": "object",
        "description": "Reusable account-scoped programmable-key template.",
        "properties": {
          "id": {
            "type": "string",
            "example": "btpl_01h2xcejqtf2nbrexx3vqjhp70"
          },
          "name": {
            "type": "string",
            "example": "Front Desk"
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "example": "Shared front desk programmable keys"
          },
          "created_at": {
            "$ref": "#/components/schemas/CreatedAt"
          },
          "updated_at": {
            "$ref": "#/components/schemas/UpdatedAt"
          }
        },
        "required": [
          "id",
          "name",
          "created_at",
          "updated_at"
        ]
      },
      "TemplateButton": {
        "type": "object",
        "description": "Button row defined on a reusable template.",
        "properties": {
          "id": {
            "type": "string",
            "example": "btn_01h2xcejqtf2nbrexx3vqjhp71"
          },
          "template": {
            "type": "string",
            "example": "btpl_01h2xcejqtf2nbrexx3vqjhp70"
          },
          "position": {
            "type": "integer",
            "minimum": 1,
            "example": 2
          },
          "label": {
            "type": "string",
            "example": "Alice"
          },
          "type": {
            "$ref": "#/components/schemas/ButtonType"
          },
          "target": {
            "$ref": "#/components/schemas/ButtonTarget"
          },
          "created_at": {
            "$ref": "#/components/schemas/CreatedAt"
          }
        },
        "required": [
          "id",
          "template",
          "position",
          "label",
          "type",
          "target",
          "created_at"
        ]
      },
      "DeviceButtonOverride": {
        "type": "object",
        "description": "Per-device button override or suppression tombstone.",
        "properties": {
          "id": {
            "type": "string",
            "example": "devbtn_01h2xcejqtf2nbrexx3vqjhp72"
          },
          "device": {
            "type": "string",
            "example": "dev_01h2xcejqtf2nbrexx3vqjhp50"
          },
          "position": {
            "type": "integer",
            "minimum": 1
          },
          "suppressed": {
            "type": "boolean",
            "description": "When true, hides any template button at this position."
          },
          "label": {
            "type": [
              "string",
              "null"
            ]
          },
          "type": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ButtonType"
              },
              {
                "type": "null"
              }
            ]
          },
          "target": {
            "$ref": "#/components/schemas/ButtonTarget"
          },
          "created_at": {
            "$ref": "#/components/schemas/CreatedAt"
          }
        },
        "required": [
          "id",
          "device",
          "position",
          "suppressed",
          "created_at"
        ]
      },
      "MaterializedButton": {
        "type": "object",
        "description": "Effective button after template rows and per-device overrides are merged.",
        "properties": {
          "position": {
            "type": "integer",
            "minimum": 1
          },
          "label": {
            "type": "string"
          },
          "type": {
            "$ref": "#/components/schemas/ButtonType"
          },
          "target": {
            "$ref": "#/components/schemas/ButtonTarget"
          },
          "source": {
            "type": "string",
            "description": "Where the button came from. `model_default` is a button the device model gets for free because its hardware has no other way to reach the function; it is stored nowhere, so it carries neither `template_button` nor `override`, but a device override at the same position shadows or suppresses it like any other row.",
            "enum": [
              "template",
              "override",
              "template_overridden",
              "model_default"
            ]
          },
          "template_button": {
            "type": [
              "string",
              "null"
            ]
          },
          "override": {
            "type": [
              "string",
              "null"
            ]
          },
          "compatibility": {
            "$ref": "#/components/schemas/ButtonCompatibilityVerdict"
          }
        },
        "required": [
          "position",
          "label",
          "type",
          "target",
          "source",
          "compatibility"
        ]
      },
      "CreateButtonTemplateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "example": "Front Desk"
          },
          "description": {
            "type": "string",
            "example": "Shared front desk programmable keys"
          }
        },
        "required": [
          "name"
        ]
      },
      "UpdateButtonTemplateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Send null to clear the description."
          }
        }
      },
      "CreateTemplateButtonRequest": {
        "type": "object",
        "properties": {
          "position": {
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          },
          "label": {
            "type": "string",
            "minLength": 1
          },
          "type": {
            "$ref": "#/components/schemas/ButtonType"
          },
          "target": {
            "$ref": "#/components/schemas/ButtonTarget"
          }
        },
        "required": [
          "position",
          "label",
          "type",
          "target"
        ]
      },
      "UpdateTemplateButtonRequest": {
        "type": "object",
        "properties": {
          "position": {
            "type": "integer",
            "minimum": 1,
            "maximum": 1000,
            "description": "New position for the button."
          }
        },
        "required": [
          "position"
        ]
      },
      "CreateDeviceButtonOverrideRequest": {
        "type": "object",
        "description": "Create a device-specific button override. For suppression rows, send\n`suppressed: true` and omit `label`, `type`, and `target`.\n",
        "properties": {
          "position": {
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          },
          "suppressed": {
            "type": "boolean",
            "default": false
          },
          "label": {
            "type": "string"
          },
          "type": {
            "$ref": "#/components/schemas/ButtonType"
          },
          "target": {
            "$ref": "#/components/schemas/ButtonTarget"
          }
        },
        "required": [
          "position",
          "suppressed"
        ]
      },
      "DeviceSettings": {
        "type": [
          "object",
          "null"
        ],
        "description": "Device settings with vendor-agnostic abstractions. All fields are optional —\nomitted fields inherit from the parent configuration layer\n(Global defaults → Platform → Account → Device).\n\nThis schema evolves as new hardware capabilities are supported.\n",
        "properties": {
          "abstractions": {
            "$ref": "#/components/schemas/AbstractSettings"
          }
        }
      },
      "AbstractSettings": {
        "type": "object",
        "description": "Vendor-agnostic device configuration settings",
        "properties": {
          "audio": {
            "$ref": "#/components/schemas/AudioSettings"
          },
          "display": {
            "$ref": "#/components/schemas/DisplaySettings"
          },
          "regional": {
            "$ref": "#/components/schemas/RegionalSettings"
          },
          "network": {
            "$ref": "#/components/schemas/NetworkSettings"
          },
          "features": {
            "$ref": "#/components/schemas/FeatureSettings"
          },
          "provisioning": {
            "$ref": "#/components/schemas/ProvisioningSettings"
          }
        }
      },
      "AudioSettings": {
        "type": "object",
        "description": "Audio codec and processing settings",
        "properties": {
          "codecs": {
            "type": "array",
            "description": "Ordered list of preferred audio codecs",
            "items": {
              "type": "string",
              "enum": [
                "PCMU",
                "PCMA"
              ]
            },
            "example": [
              "PCMU",
              "PCMA"
            ]
          },
          "vad_enabled": {
            "type": "boolean",
            "description": "Voice Activity Detection — suppresses silence packets to save bandwidth"
          },
          "echo_cancellation": {
            "type": "boolean",
            "description": "Acoustic echo cancellation"
          },
          "jitter_buffer": {
            "$ref": "#/components/schemas/JitterBuffer"
          }
        }
      },
      "JitterBuffer": {
        "type": "object",
        "description": "Jitter buffer configuration for smoothing network packet timing variations",
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "adaptive",
              "fixed"
            ],
            "description": "Buffer mode — adaptive adjusts to network conditions"
          },
          "min_ms": {
            "type": "integer",
            "description": "Minimum buffer size in milliseconds",
            "example": 40
          },
          "max_ms": {
            "type": "integer",
            "description": "Maximum buffer size in milliseconds",
            "example": 200
          }
        }
      },
      "DisplaySettings": {
        "type": "object",
        "description": "Screen display preferences",
        "properties": {
          "time_format": {
            "type": "string",
            "enum": [
              "12h",
              "24h"
            ],
            "description": "Clock display format"
          },
          "date_format": {
            "type": "string",
            "enum": [
              "M/D/Y",
              "D/M/Y",
              "Y-M-D"
            ],
            "description": "Date display format"
          },
          "backlight_timeout": {
            "type": "integer",
            "description": "Backlight auto-off delay in seconds",
            "example": 30
          },
          "backlight_level": {
            "type": "string",
            "enum": [
              "low",
              "medium",
              "high"
            ],
            "description": "Screen backlight brightness"
          }
        }
      },
      "RegionalSettings": {
        "type": "object",
        "description": "Localization and regional preferences",
        "properties": {
          "timezone": {
            "type": "string",
            "description": "IANA timezone identifier",
            "example": "America/New_York"
          },
          "language": {
            "type": "string",
            "description": "BCP 47 language code",
            "example": "en-US"
          },
          "tone_scheme": {
            "type": "string",
            "description": "ISO country code for dial/ring tone patterns",
            "example": "us"
          }
        }
      },
      "NetworkSettings": {
        "type": "object",
        "description": "Network and QoS configuration",
        "properties": {
          "vlan_id": {
            "type": "integer",
            "description": "VLAN tag for voice traffic"
          },
          "qos_dscp_sip": {
            "type": "integer",
            "description": "DSCP value for SIP signaling packets",
            "example": 26
          },
          "qos_dscp_rtp": {
            "type": "integer",
            "description": "DSCP value for RTP media packets",
            "example": 46
          },
          "rtcp_enabled": {
            "type": "boolean",
            "description": "Enable RTCP for call quality reporting"
          },
          "sip_transport": {
            "type": "string",
            "enum": [
              "udp",
              "tcp"
            ],
            "description": "SIP signaling transport the phone uses to reach the registrar. When omitted, the platform default applies. Settable at any configuration layer (platform, account, or device)."
          }
        }
      },
      "FeatureSettings": {
        "type": "object",
        "description": "Phone feature toggles",
        "properties": {
          "dnd_enabled": {
            "type": "boolean",
            "description": "Do Not Disturb"
          },
          "call_waiting_enabled": {
            "type": "boolean",
            "description": "Call waiting notification"
          },
          "call_forward_enabled": {
            "type": "boolean",
            "description": "Call forwarding controls"
          },
          "auto_answer_enabled": {
            "type": "boolean",
            "description": "Automatically answer incoming calls (e.g., for intercom)"
          },
          "srtp_enabled": {
            "type": "boolean",
            "description": "Secure RTP for encrypted media"
          },
          "call_waiting_dialtone_enabled": {
            "type": "boolean",
            "description": "Play a dial tone on the handset while a call is on hold, as a cue that a second number can be dialled. Heard only by the phone's own user, never by the held party. Disabled by default; honoured on Snom desk phones."
          }
        }
      },
      "ProvisioningSettings": {
        "type": "object",
        "description": "Automatic resync and firmware update settings",
        "properties": {
          "resync_time": {
            "type": "string",
            "description": "Time of day to resync configuration (HH:MM in 24-hour format)",
            "example": "02:00"
          },
          "resync_mode": {
            "type": "string",
            "enum": [
              "config_and_firmware",
              "configuration",
              "firmware"
            ],
            "description": "What to resync — configuration, firmware, or both"
          },
          "bootup_check_enabled": {
            "type": "boolean",
            "description": "Check for configuration updates on device boot"
          }
        }
      },
      "ProvisioningEvent": {
        "type": "object",
        "description": "An audit log entry for a device provisioning request",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "Provisioning event identifier"
              }
            ]
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "The device that triggered this event"
              }
            ]
          },
          "event_type": {
            "type": "string",
            "enum": [
              "config_fetch_success",
              "config_fetch_failure",
              "registration",
              "error",
              "mac_detected",
              "vendor_detected"
            ],
            "description": "Type of provisioning event:\n- `config_fetch_success` — device successfully fetched its configuration\n- `config_fetch_failure` — device failed to fetch its configuration\n- `registration` — device registered with the SIP server\n- `error` — a provisioning error occurred\n- `mac_detected` — MAC address detected from provisioning request\n- `vendor_detected` — vendor identified from MAC or User-Agent\n"
          },
          "source_ip": {
            "type": [
              "string",
              "null"
            ],
            "description": "IP address of the device making the request",
            "example": "192.168.1.100"
          },
          "user_agent": {
            "type": "string",
            "description": "HTTP User-Agent header from the device",
            "example": "snom D785/10.1.91"
          },
          "details": {
            "type": "object",
            "description": "Additional event metadata (error messages, vendor-specific info)",
            "additionalProperties": true
          },
          "created_at": {
            "$ref": "#/components/schemas/CreatedAt"
          }
        },
        "required": [
          "id",
          "device",
          "event_type",
          "created_at"
        ]
      },
      "Device": {
        "type": "object",
        "description": "A provisioned device (desk phone, DECT base station, or DECT handset).\nThe `type` field indicates the device kind, and type-specific fields are only present\nfor the corresponding type.\n",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "Device identifier"
              }
            ]
          },
          "type": {
            "type": "string",
            "enum": [
              "deskphone",
              "dect_base",
              "dect_handset"
            ],
            "description": "The kind of device"
          },
          "mac_address": {
            "type": "string",
            "description": "Hardware MAC address",
            "example": "00:04:13:aa:bb:cc"
          },
          "vendor": {
            "type": "string",
            "description": "Device vendor (auto-detected from MAC address)",
            "example": "snom"
          },
          "model": {
            "type": [
              "string",
              "null"
            ],
            "description": "Device model",
            "example": "D785"
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Human-friendly label for the device. Set by admins on deskphones,\nDECT bases, and DECT handsets; `null` when unassigned. Handset\nresponses also expose this value as `display_name` for backwards\ncompatibility with older clients.\n"
          },
          "location": {
            "type": [
              "string",
              "null"
            ],
            "description": "Physical E911 location for this device. Set on deskphones and\nDECT bases; `null` when unassigned. DECT handsets have no\n`location` of their own — they inherit from the paired base\nand the handset response carries `null` here. See the E911\nguide for the dispatch resolution rules.\n"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending-sync",
              "provisioned"
            ],
            "description": "Current provisioning status"
          },
          "overrides": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DeviceSettings"
              }
            ],
            "description": "Device-specific settings overrides"
          },
          "current_ip_address": {
            "type": [
              "string",
              "null"
            ],
            "description": "Last known IP address of the device",
            "example": "192.168.1.100"
          },
          "last_provisioned_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the device last fetched its configuration"
          },
          "registration_status": {
            "type": "string",
            "enum": [
              "registered",
              "not_registered"
            ],
            "description": "Whether the device is currently reachable (online). Derived live from the device's assigned lines; distinct from `status`, which only reflects whether the device has fetched its configuration. A device with no assigned lines reports `not_registered`."
          },
          "last_registered_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the device's reachability was last confirmed. Null when the device is not currently reachable."
          },
          "last_call_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the device last placed or received a call (the latest call attempt involving the device, regardless of outcome). Null until the device's first call. Its presence indicates the device has carried a call; its recency indicates whether it is still in use."
          },
          "created_at": {
            "$ref": "#/components/schemas/CreatedAt"
          },
          "updated_at": {
            "$ref": "#/components/schemas/UpdatedAt"
          },
          "primary_line": {
            "type": [
              "string",
              "null"
            ],
            "description": "Primary SIP line (deskphone only)"
          },
          "lines": {
            "type": "array",
            "description": "SIP line assignments (deskphone only)",
            "items": {
              "$ref": "#/components/schemas/DeviceLine"
            }
          },
          "multicell_role": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "single",
              "data_master",
              "secondary",
              null
            ],
            "description": "Role in a multicell deployment (DECT base only)"
          },
          "max_handsets": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Maximum number of handsets supported (DECT base only)",
            "example": 30
          },
          "firmware_version": {
            "type": [
              "string",
              "null"
            ],
            "description": "Current firmware version (DECT bases and handsets)"
          },
          "handsets": {
            "type": "array",
            "description": "Paired handsets (DECT base only)",
            "items": {
              "$ref": "#/components/schemas/DECTHandset"
            }
          },
          "base": {
            "type": [
              "string",
              "null"
            ],
            "description": "Parent DECT base station (DECT handset only)"
          },
          "ipei": {
            "type": [
              "string",
              "null"
            ],
            "description": "DECT handset IPEI (DECT handset only)"
          },
          "display_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Optional display name (DECT handset only)"
          },
          "slot_number": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Slot number on the base station (DECT handset only)"
          },
          "registered_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the handset registered with the base (DECT handset only)"
          },
          "extensions": {
            "type": "array",
            "description": "SIP line assignments on this handset (DECT handset only)",
            "items": {
              "$ref": "#/components/schemas/HandsetLine"
            }
          },
          "assignments": {
            "type": "array",
            "description": "User assignments. Only included when `expand[]=users` is requested.",
            "items": {
              "$ref": "#/components/schemas/DeviceUserAssignment"
            }
          },
          "compatibility": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ButtonCompatibilitySummary"
              }
            ],
            "description": "Programmable-key compatibility for the current effective button set."
          },
          "button_template_id": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "type": "null"
              }
            ],
            "description": "ID of the reusable programmable-key template bound to this device.\nNull when no template is bound.\n"
          },
          "button_template": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ButtonTemplate"
              },
              {
                "type": "null"
              }
            ],
            "description": "The full programmable-key template object. Included only when\n`expand[]=button_template` is requested (the id is always available\nas `button_template_id`).\n"
          }
        },
        "required": [
          "id",
          "type",
          "mac_address",
          "vendor",
          "status",
          "registration_status",
          "last_registered_at",
          "last_call_at",
          "created_at",
          "updated_at"
        ]
      },
      "UpdateDeviceRequest": {
        "type": "object",
        "description": "Request body for updating a device",
        "properties": {
          "model": {
            "type": "string",
            "description": "Device model"
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Human-friendly label for the device (deskphone, DECT base, or\nDECT handset). Send `null` to clear.\n"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending-sync",
              "provisioned"
            ],
            "description": "Provisioning status for deskphones and DECT bases"
          },
          "overrides": {
            "$ref": "#/components/schemas/DeviceSettings"
          },
          "ipei": {
            "type": "string",
            "description": "DECT handset IPEI"
          },
          "display_name": {
            "type": "string",
            "deprecated": true,
            "description": "Deprecated alias of `name` for DECT handset updates. Send `name`\ninstead. If both are present, `name` wins.\n"
          },
          "location": {
            "type": [
              "string",
              "null"
            ],
            "description": "Physical E911 location (deskphone or DECT base only). Tri-state:\nomit for no change, send a `loc_…` ID to set, or send explicit\nJSON `null` to clear the device's dispatch location.\n"
          },
          "base": {
            "type": [
              "string",
              "null"
            ],
            "description": "Paired DECT base (DECT handset only). Tri-state: omit for no\nchange, send a `dectb_…` ID to re-pair to a different base on\nthe same account, or send explicit JSON `null` to unpair the\nhandset (it remains in inventory and can be paired later).\n"
          },
          "button_template": {
            "type": [
              "string",
              "null"
            ],
            "description": "Reusable programmable-key template. Tri-state: omit for no\nchange, send a button template ID to bind, or send explicit\nJSON `null` to unbind.\n"
          }
        }
      },
      "CreateDeviceRequest": {
        "type": "object",
        "description": "Request body for creating a device",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "deskphone",
              "dect_base",
              "dect_handset"
            ],
            "description": "The kind of device to create. Optional for MAC-addressable devices:\nwhen omitted, the type is detected from `mac_address` via the vendor\nproduct catalog. If the catalog cannot classify the MAC, the request\nis rejected and you must supply `type`. When you do supply `type` and\nit contradicts a positive catalog match, the request is rejected\nrather than silently corrected. `dect_handset` is IPEI-identified and\nmust always be supplied explicitly.\n"
          },
          "mac_address": {
            "type": "string",
            "description": "Hardware MAC address (required for deskphones and DECT bases)",
            "example": "00:04:13:aa:bb:cc"
          },
          "model": {
            "type": "string",
            "description": "Device model (optional)",
            "example": "D785"
          },
          "name": {
            "type": "string",
            "description": "Human-friendly label for the device (deskphone, DECT base, or DECT handset)."
          },
          "overrides": {
            "$ref": "#/components/schemas/DeviceSettings"
          },
          "multicell_role": {
            "type": "string",
            "enum": [
              "single",
              "data_master",
              "secondary"
            ],
            "description": "Multicell deployment role (DECT base only, defaults to single)"
          },
          "location": {
            "type": "string",
            "description": "Physical E911 location to assign at creation (deskphone or DECT\nbase only). Can be set later via update.\n",
            "example": "loc_01h2xcejqtf2nbrexx3vqjhp40"
          },
          "base": {
            "type": "string",
            "description": "Parent DECT base identifier (DECT handset only). Optional —\nomit to stock the handset as unpaired; pair it later by\nupdating the handset with a `base`.\n",
            "example": "dectb_01h2xcejqtf2nbrexx3vqjhp50"
          },
          "ipei": {
            "type": "string",
            "description": "DECT handset IPEI (required for DECT handsets)",
            "example": "123456789012345"
          },
          "display_name": {
            "type": "string",
            "deprecated": true,
            "description": "Deprecated alias of `name` for DECT handset creates. Send `name`\ninstead. If both are present, `name` wins.\n"
          }
        }
      },
      "CreateDeviceResponse": {
        "type": "object",
        "description": "Minimal response returned after creating a device",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "Identifier of the created device"
              }
            ]
          },
          "type": {
            "type": "string",
            "enum": [
              "deskphone",
              "dect_base",
              "dect_handset"
            ],
            "description": "The kind of device that was created"
          }
        },
        "required": [
          "id",
          "type"
        ]
      },
      "ProvisionedDevice": {
        "type": "object",
        "description": "A provisioned deskphone.",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "Device identifier"
              }
            ]
          },
          "mac_address": {
            "type": "string",
            "description": "Hardware MAC address",
            "example": "00:04:13:aa:bb:cc"
          },
          "vendor": {
            "type": "string",
            "description": "Device vendor (auto-detected from MAC address)",
            "example": "snom"
          },
          "model": {
            "type": [
              "string",
              "null"
            ],
            "description": "Device model",
            "example": "D785"
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Human-friendly label for the device. `null` when unassigned."
          },
          "location": {
            "type": [
              "string",
              "null"
            ],
            "description": "Physical E911 location for this deskphone. `null` when unassigned.\nSee the E911 guide for the dispatch resolution rules.\n"
          },
          "button_template": {
            "type": [
              "string",
              "null"
            ],
            "description": "Reusable programmable-key template bound to this deskphone."
          },
          "status": {
            "type": "string",
            "enum": [
              "pending-sync",
              "provisioned"
            ],
            "description": "Current provisioning status"
          },
          "overrides": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DeviceSettings"
              }
            ],
            "description": "Device-specific settings overrides"
          },
          "current_ip_address": {
            "type": [
              "string",
              "null"
            ],
            "description": "Last known IP address of the device",
            "example": "192.168.1.100"
          },
          "last_provisioned_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the device last fetched its configuration"
          },
          "created_at": {
            "$ref": "#/components/schemas/CreatedAt"
          },
          "updated_at": {
            "$ref": "#/components/schemas/UpdatedAt"
          },
          "primary_line": {
            "type": [
              "string",
              "null"
            ],
            "description": "Primary SIP line"
          },
          "lines": {
            "type": "array",
            "description": "SIP line assignments",
            "items": {
              "$ref": "#/components/schemas/DeviceLine"
            }
          }
        },
        "required": [
          "id",
          "mac_address",
          "vendor",
          "status",
          "created_at",
          "updated_at"
        ]
      },
      "CreateDeskphoneRequest": {
        "type": "object",
        "description": "Request body for creating a deskphone",
        "properties": {
          "mac_address": {
            "type": "string",
            "description": "Hardware MAC address (vendor is auto-detected)",
            "example": "00:04:13:aa:bb:cc"
          },
          "model": {
            "type": "string",
            "description": "Device model (optional)",
            "example": "D785"
          },
          "overrides": {
            "$ref": "#/components/schemas/DeviceSettings"
          }
        },
        "required": [
          "mac_address"
        ]
      },
      "UpdateDeskphoneRequest": {
        "type": "object",
        "description": "Request body for updating a deskphone",
        "properties": {
          "model": {
            "type": "string",
            "description": "Device model"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending-sync",
              "provisioned"
            ],
            "description": "Device status"
          },
          "overrides": {
            "$ref": "#/components/schemas/DeviceSettings"
          }
        }
      },
      "DECTHandset": {
        "type": "object",
        "description": "A DECT handset paired with a base station",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "Handset identifier"
              }
            ]
          },
          "base": {
            "type": [
              "string",
              "null"
            ],
            "description": "Parent DECT base station. `null` when the handset is stocked\nbut not yet paired with a base — pair later by updating this\nfield with a base ID.\n"
          },
          "ipei": {
            "type": "string",
            "description": "International Portable Equipment Identity",
            "example": "0328A0000F"
          },
          "status": {
            "type": "string",
            "enum": [
              "unpaired",
              "pending-sync",
              "registered",
              "provisioned"
            ],
            "description": "Current handset status"
          },
          "display_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Optional display name"
          },
          "slot_number": {
            "type": "integer",
            "description": "Slot number on the base station",
            "example": 1
          },
          "model": {
            "type": [
              "string",
              "null"
            ],
            "description": "Handset model"
          },
          "firmware_version": {
            "type": [
              "string",
              "null"
            ],
            "description": "Current firmware version"
          },
          "registered_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the handset was registered with the base"
          },
          "extensions": {
            "type": "array",
            "description": "SIP line assignments on this handset",
            "items": {
              "$ref": "#/components/schemas/HandsetLine"
            }
          },
          "created_at": {
            "$ref": "#/components/schemas/CreatedAt"
          },
          "updated_at": {
            "$ref": "#/components/schemas/UpdatedAt"
          }
        },
        "required": [
          "id",
          "ipei",
          "status",
          "slot_number",
          "created_at",
          "updated_at"
        ]
      },
      "CreateHandsetRequest": {
        "type": "object",
        "description": "Request body for creating a DECT handset",
        "properties": {
          "ipei": {
            "type": "string",
            "description": "International Portable Equipment Identity",
            "example": "0328A0000F"
          },
          "display_name": {
            "type": "string",
            "description": "Optional display name"
          },
          "model": {
            "type": "string",
            "description": "Handset model"
          }
        },
        "required": [
          "ipei"
        ]
      },
      "UpdateHandsetRequest": {
        "type": "object",
        "description": "Request body for updating a DECT handset",
        "properties": {
          "ipei": {
            "type": "string",
            "description": "International Portable Equipment Identity"
          },
          "display_name": {
            "type": "string",
            "description": "Display name"
          },
          "model": {
            "type": "string",
            "description": "Handset model (e.g. `M55`, `M58`). Handsets never provision — the\nbase fetches config and pushes it over DECT — so the model can't be\nauto-detected and must be set here. It gates programmable-button\n(template) support.\n"
          }
        }
      },
      "HandsetLine": {
        "type": "object",
        "description": "A SIP line assignment on a DECT handset",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "Handset line identifier"
              }
            ]
          },
          "handset": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "Parent handset"
              }
            ]
          },
          "display_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Optional display name override"
          },
          "endpoint_id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "ID of the SIP endpoint assigned to this line."
              }
            ]
          },
          "endpoint": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "id": {
                    "allOf": [
                      {
                        "$ref": "#/components/schemas/EntityId"
                      },
                      {
                        "description": "Endpoint identifier"
                      }
                    ]
                  },
                  "user": {
                    "allOf": [
                      {
                        "$ref": "#/components/schemas/EntityId"
                      },
                      {
                        "description": "Owning user"
                      }
                    ]
                  },
                  "name": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Endpoint display name"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "online",
                      "offline"
                    ],
                    "description": "Registration status"
                  },
                  "created_at": {
                    "$ref": "#/components/schemas/CreatedAt"
                  },
                  "updated_at": {
                    "$ref": "#/components/schemas/UpdatedAt"
                  }
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "The full SIP endpoint object assigned to this line. Included on list\nresponses; the id is always available as `endpoint_id`.\n"
          },
          "created_at": {
            "$ref": "#/components/schemas/CreatedAt"
          },
          "updated_at": {
            "$ref": "#/components/schemas/UpdatedAt"
          }
        },
        "required": [
          "id",
          "handset",
          "endpoint_id",
          "created_at",
          "updated_at"
        ]
      },
      "CreateHandsetLineRequest": {
        "type": "object",
        "description": "Request body for creating a handset line",
        "properties": {
          "endpoint": {
            "type": "string",
            "description": "ID of the SIP endpoint to assign"
          },
          "display_name": {
            "type": "string",
            "description": "Optional display name override"
          }
        },
        "required": [
          "endpoint"
        ]
      },
      "DECTBase": {
        "type": "object",
        "description": "A DECT base station with paired wireless handsets",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              },
              {
                "description": "DECT base station identifier"
              }
            ]
          },
          "mac_address": {
            "type": "string",
            "description": "Hardware MAC address",
            "example": "00:04:13:bb:cc:dd"
          },
          "vendor": {
            "type": "string",
            "description": "Device vendor (auto-detected from MAC address)",
            "example": "snom"
          },
          "model": {
            "type": [
              "string",
              "null"
            ],
            "description": "Base station model",
            "example": "M500"
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Human-friendly label for the base. `null` when unassigned."
          },
          "status": {
            "type": "string",
            "enum": [
              "pending-sync",
              "provisioned"
            ],
            "description": "Current provisioning status"
          },
          "multicell_role": {
            "type": "string",
            "enum": [
              "single",
              "data_master",
              "secondary"
            ],
            "description": "Role in a multicell deployment:\n- `single` — standalone base station (default)\n- `data_master` — primary base that distributes configuration\n- `secondary` — subordinate base that receives configuration from the data master\n"
          },
          "max_handsets": {
            "type": "integer",
            "description": "Maximum number of handsets this base supports",
            "example": 30
          },
          "firmware_version": {
            "type": [
              "string",
              "null"
            ],
            "description": "Current firmware version"
          },
          "overrides": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DeviceSettings"
              }
            ],
            "description": "Device-specific settings overrides"
          },
          "current_ip_address": {
            "type": [
              "string",
              "null"
            ],
            "description": "Last known IP address of the base station",
            "example": "192.168.1.101"
          },
          "last_provisioned_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the base last fetched its configuration"
          },
          "location": {
            "type": [
              "string",
              "null"
            ],
            "description": "Physical location used as the emergency-services dispatch address\nwhen any handset on this base places a call. All handsets paired\nwith this base share the same location.\n"
          },
          "handsets": {
            "type": "array",
            "description": "Paired wireless handsets",
            "items": {
              "$ref": "#/components/schemas/DECTHandset"
            }
          },
          "created_at": {
            "$ref": "#/components/schemas/CreatedAt"
          },
          "updated_at": {
            "$ref": "#/components/schemas/UpdatedAt"
          }
        },
        "required": [
          "id",
          "mac_address",
          "vendor",
          "status",
          "multicell_role",
          "max_handsets",
          "created_at",
          "updated_at"
        ]
      },
      "CreateDECTBaseRequest": {
        "type": "object",
        "description": "Request body for creating a DECT base station via the legacy\n`/v1/dect-bases` path. To set or clear the base's E911 dispatch\nlocation, use the unified `/v1/devices` endpoint instead — it\nsupports tri-state `location` (omit / `loc_…` / `null`).\n",
        "properties": {
          "mac_address": {
            "type": "string",
            "description": "Hardware MAC address (vendor is auto-detected)",
            "example": "00:04:13:bb:cc:dd"
          },
          "model": {
            "type": "string",
            "description": "Base station model (optional, can be auto-detected)",
            "example": "M500"
          },
          "multicell_role": {
            "type": "string",
            "enum": [
              "single",
              "data_master",
              "secondary"
            ],
            "description": "Role in multicell deployment (defaults to single)"
          },
          "overrides": {
            "$ref": "#/components/schemas/DeviceSettings"
          }
        },
        "required": [
          "mac_address"
        ]
      },
      "UpdateDECTBaseRequest": {
        "type": "object",
        "description": "Request body for updating a DECT base station via the legacy\n`/v1/dect-bases/{id}` path. See CreateDECTBaseRequest for the\nrationale on the missing `location` field.\n",
        "properties": {
          "model": {
            "type": "string",
            "description": "Base station model"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending-sync",
              "provisioned"
            ],
            "description": "Device status"
          },
          "multicell_role": {
            "type": "string",
            "enum": [
              "single",
              "data_master",
              "secondary"
            ],
            "description": "Role in multicell deployment"
          },
          "overrides": {
            "$ref": "#/components/schemas/DeviceSettings"
          }
        }
      },
      "CreateCallRequest": {
        "type": "object",
        "description": "Request to initiate an outbound call",
        "properties": {
          "user": {
            "type": "string",
            "description": "The user whose endpoints will ring first. When the user answers, the destination is dialed.",
            "example": "user_01h2xcejqtf2nbrexx3vqjhp42"
          },
          "dial_string": {
            "type": "string",
            "description": "The destination to dial after the user answers.\nCan be a phone number (E.164 or local format), an extension, or an emergency number.\n",
            "example": "+15551234567"
          }
        },
        "required": [
          "user",
          "dial_string"
        ]
      },
      "CreateTestCallRequest": {
        "type": "object",
        "description": "Request to trigger a simulated call in test mode. Available only with a\ntest key (`sk_test_...`); a live key receives `400`. Used for inbound\n(screen pop) and custom-scenario simulations that a dialed number\ncannot select. See the \"Testing your integration\" guide.\n",
        "properties": {
          "user": {
            "type": "string",
            "description": "The user to terminate the simulated call at, bypassing the account's\ninbound routing. Currently required (the endpoint returns `400`\nwithout it) because routing simulation is not yet supported; once it\nis, this becomes an optional shortcut for forcing a target when\nrouting is not what you are testing.\n",
            "example": "user_01h2xcejqtf2nbrexx3vqjhp42"
          },
          "direction": {
            "type": "string",
            "enum": [
              "inbound",
              "outbound"
            ],
            "default": "inbound",
            "description": "`inbound` simulates a call arriving at the account; `outbound` simulates a device-originated call."
          },
          "from_number": {
            "type": "string",
            "description": "Caller number for inbound calls; set it to a known contact's number to exercise caller-ID matching. Must be E.164. Ignored for outbound.",
            "example": "+15551234567"
          },
          "from_name": {
            "type": "string",
            "description": "Optional caller display name."
          },
          "to_number": {
            "type": "string",
            "description": "Dialed number for outbound; its magic-number value selects the scenario when no explicit `scenario` is given."
          },
          "scenario": {
            "$ref": "#/components/schemas/TestScenarioOverride"
          }
        }
      },
      "TestScenarioOverride": {
        "type": "object",
        "description": "Explicitly scripts a simulated call's outcome and timing, complementing the magic-number convention.",
        "properties": {
          "outcome": {
            "type": "string",
            "enum": [
              "answered",
              "no-answer",
              "busy",
              "voicemail"
            ],
            "description": "Terminal disposition. An unrecognized value returns 400."
          },
          "ring_seconds": {
            "type": "integer",
            "description": "Seconds the destination rings. Clamped to 0-120."
          },
          "talk_seconds": {
            "type": "integer",
            "description": "Answered conversation length in seconds. Clamped to 0-120."
          },
          "recording": {
            "type": "boolean",
            "description": "Whether an answered call produces a recording."
          },
          "voicemail_seconds": {
            "type": "integer",
            "description": "Deposited voicemail length in seconds. Clamped to 0-120."
          }
        }
      },
      "TestCallResponse": {
        "type": "object",
        "description": "The started simulated call. Returned so a test harness can assert on the call id (poll the CDR, correlate webhooks).",
        "properties": {
          "id": {
            "type": "string",
            "description": "Identifier of the started call.",
            "example": "call_01h2xcejqtf2nbrexx3vqjhp45"
          },
          "scenario": {
            "type": "string",
            "description": "Name of the scenario that will play out (e.g. answered, no-answer, custom).",
            "example": "answered"
          }
        },
        "required": [
          "id",
          "scenario"
        ]
      },
      "TestEventResponse": {
        "type": "object",
        "description": "Echoes the emitted event type.",
        "properties": {
          "event": {
            "type": "string",
            "example": "queue.call.answered"
          }
        },
        "required": [
          "event"
        ]
      },
      "ComponentConfig": {
        "type": "object",
        "description": "Configuration for a single component",
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Whether this component is enabled for the session"
          }
        },
        "required": [
          "enabled"
        ]
      },
      "CreateAccountSessionRequest": {
        "type": "object",
        "description": "Request body for creating an account session",
        "properties": {
          "account": {
            "type": "string",
            "description": "Account identifier",
            "example": "acct_01h2xcejqtf2nbrexx3vqjhp41"
          },
          "components": {
            "type": "object",
            "description": "Components to enable for this session. At least one component must have `enabled: true`.\nEach key is a component name and the value configures that component.\n",
            "additionalProperties": {
              "$ref": "#/components/schemas/ComponentConfig"
            },
            "properties": {
              "call_logs": {
                "$ref": "#/components/schemas/ComponentConfig"
              },
              "voicemails": {
                "$ref": "#/components/schemas/ComponentConfig"
              },
              "call_history": {
                "$ref": "#/components/schemas/ComponentConfig"
              },
              "phone_number_ordering": {
                "$ref": "#/components/schemas/ComponentConfig"
              },
              "phone_numbers": {
                "$ref": "#/components/schemas/ComponentConfig"
              },
              "account_onboarding": {
                "$ref": "#/components/schemas/ComponentConfig"
              },
              "dial_plan_viewer": {
                "$ref": "#/components/schemas/ComponentConfig"
              }
            },
            "example": {
              "call_logs": {
                "enabled": true
              },
              "voicemails": {
                "enabled": true
              }
            }
          }
        },
        "required": [
          "account",
          "components"
        ]
      },
      "CreateSessionResponse": {
        "type": "object",
        "properties": {
          "account": {
            "type": "string",
            "description": "Account identifier for the created session",
            "example": "acct_01h2xcejqtf2nbrexx3vqjhp41"
          },
          "client_secret": {
            "$ref": "#/components/schemas/ClientSecret"
          },
          "expires_at": {
            "$ref": "#/components/schemas/SessionExpiresAt"
          }
        },
        "required": [
          "account",
          "client_secret",
          "expires_at"
        ]
      },
      "CreateUserSessionRequest": {
        "type": "object",
        "description": "Request body for creating a user session",
        "properties": {
          "user": {
            "type": "string",
            "maxLength": 255,
            "description": "Identifier of the DialStack user this token will authenticate as.\nThe user must already be provisioned via `POST /v1/users` and belong\nto an account owned by the calling platform.\n",
            "example": "user_01h2xcejqtf2nbrexx3vqjhp42"
          },
          "ttl_seconds": {
            "type": "integer",
            "minimum": 0,
            "maximum": 604800,
            "description": "Requested token lifetime in seconds. Defaults to 86400 (24 hours)\nwhen omitted or zero. Values above 604800 (7 days) are rejected.\n",
            "example": 86400
          }
        },
        "required": [
          "user"
        ]
      },
      "CreateUserSessionResponse": {
        "type": "object",
        "properties": {
          "user": {
            "type": "string",
            "description": "Identifier of the user the session token authenticates as",
            "example": "user_01h2xcejqtf2nbrexx3vqjhp42"
          },
          "account": {
            "type": "string",
            "description": "Identifier of the account that owns the user",
            "example": "acct_01h2xcejqtf2nbrexx3vqjhp41"
          },
          "client_secret": {
            "$ref": "#/components/schemas/ClientSecret"
          },
          "expires_at": {
            "$ref": "#/components/schemas/SessionExpiresAt"
          }
        },
        "required": [
          "user",
          "account",
          "client_secret",
          "expires_at"
        ]
      },
      "RevokeUserSessionsResponse": {
        "type": "object",
        "properties": {
          "user": {
            "type": "string",
            "description": "Identifier of the user whose sessions were revoked",
            "example": "user_01h2xcejqtf2nbrexx3vqjhp42"
          },
          "sessions_revoked_at": {
            "type": "string",
            "format": "date-time",
            "description": "The revocation cutoff. Every user-session token minted before this\ninstant is invalid; tokens minted afterwards work normally.\n",
            "example": "2026-06-07T12:00:00Z"
          }
        },
        "required": [
          "user",
          "sessions_revoked_at"
        ]
      },
      "Extension": {
        "type": "object",
        "description": "An extension maps a short dial code (e.g., \"105\") to a routing target.\nExtensions provide a simple way for internal users to reach each other or\nfor callers to be routed through dial plans.\n",
        "properties": {
          "number": {
            "type": "string",
            "minLength": 1,
            "maxLength": 32,
            "description": "The extension number (dial code)",
            "example": "105"
          },
          "target": {
            "type": "string",
            "maxLength": 255,
            "description": "ID of the routing target",
            "example": "user_01h2xcejqtf2nbrexx3vqjhp42"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "inactive"
            ],
            "description": "Extension status",
            "example": "active"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the extension was created",
            "example": "2025-10-18T10:00:00Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the extension was last modified",
            "example": "2025-10-18T10:00:00Z"
          }
        },
        "required": [
          "number",
          "target",
          "status",
          "created_at",
          "updated_at"
        ]
      },
      "CreateExtensionRequest": {
        "type": "object",
        "description": "Request body for creating a new extension",
        "properties": {
          "number": {
            "type": "string",
            "minLength": 1,
            "maxLength": 32,
            "description": "The extension number (dial code)",
            "example": "105"
          },
          "target": {
            "type": "string",
            "maxLength": 255,
            "description": "ID of the routing target",
            "example": "user_01h2xcejqtf2nbrexx3vqjhp42"
          }
        },
        "required": [
          "number",
          "target"
        ]
      },
      "UpdateExtensionRequest": {
        "type": "object",
        "description": "Request body for updating an extension (all fields optional)",
        "properties": {
          "target": {
            "type": "string",
            "maxLength": 255,
            "description": "ID of the new routing target",
            "example": "user_01h2xcejqtf2nbrexx3vqjhp43"
          },
          "number": {
            "type": "string",
            "pattern": "^[0-9]{1,20}$",
            "description": "New extension number. When provided, the extension is renamed to this number. Must be unique within the account (a collision returns 409).\n",
            "example": "1200"
          }
        }
      },
      "CreateNumberOrderRequest": {
        "type": "object",
        "description": "Request body for ordering phone numbers",
        "properties": {
          "phone_numbers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "maxItems": 100,
            "description": "Phone numbers to order (E.164 format)",
            "example": [
              "+19195551234",
              "+19195555678"
            ]
          },
          "partial_allowed": {
            "type": "boolean",
            "default": false,
            "description": "When true, the order may partially complete — available numbers are provisioned and unavailable ones are marked as failed. When false (default), the entire order fails if any number is unavailable.\n"
          }
        },
        "required": [
          "phone_numbers"
        ]
      },
      "Address": {
        "type": "object",
        "description": "A validated, normalized physical address (embedded value object)",
        "properties": {
          "place_id": {
            "type": "string",
            "description": "Geocoding place identifier"
          },
          "address_number": {
            "type": "string",
            "description": "House or building number"
          },
          "street": {
            "type": "string",
            "description": "Street name"
          },
          "unit": {
            "type": "string",
            "description": "Unit, suite, or apartment number"
          },
          "city": {
            "type": "string",
            "description": "City or locality",
            "example": "New York"
          },
          "state": {
            "type": "string",
            "description": "State or province code",
            "example": "NY"
          },
          "postal_code": {
            "type": "string",
            "description": "Postal or ZIP code",
            "example": "10001"
          },
          "country": {
            "type": "string",
            "description": "Two-letter country code",
            "example": "US"
          },
          "latitude": {
            "type": "number",
            "format": "double",
            "description": "WGS 84 latitude"
          },
          "longitude": {
            "type": "number",
            "format": "double",
            "description": "WGS 84 longitude"
          },
          "formatted_address": {
            "type": "string",
            "description": "Computed formatted address string",
            "example": "123 Main St, New York, NY 10001, US"
          }
        },
        "required": [
          "city",
          "state",
          "postal_code",
          "country",
          "formatted_address"
        ]
      },
      "Location": {
        "type": "object",
        "description": "A business location with a validated physical address",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              }
            ]
          },
          "name": {
            "type": "string",
            "maxLength": 255,
            "description": "Display name of the location",
            "example": "Main Office"
          },
          "address": {
            "$ref": "#/components/schemas/Address"
          },
          "primary_did": {
            "type": [
              "string",
              "null"
            ],
            "deprecated": true,
            "description": "Deprecated. Historical main phone number for the location. This\nfield does not affect E911 provisioning or emergency dispatch.\n"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "inactive"
            ],
            "deprecated": true,
            "description": "Deprecated. The operational-status field was retired; the API\nalways returns `active`. Do not branch on this value.\n",
            "example": "active"
          },
          "e911_status": {
            "type": "string",
            "enum": [
              "none",
              "pending",
              "binding",
              "provisioned",
              "failed"
            ],
            "description": "E911 provisioning status for this location. Managed by the provider; read-only.",
            "readOnly": true,
            "example": "none"
          },
          "config": {
            "$ref": "#/components/schemas/LocationConfig"
          },
          "created_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CreatedAt"
              }
            ]
          },
          "updated_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/UpdatedAt"
              }
            ]
          }
        },
        "required": [
          "id",
          "name",
          "address",
          "status",
          "e911_status",
          "created_at",
          "updated_at"
        ]
      },
      "E911ValidationResponse": {
        "type": "object",
        "description": "Result of E911 address validation",
        "properties": {
          "adjusted": {
            "type": "boolean",
            "description": "Whether the address was adjusted during geocoding"
          },
          "address": {
            "type": "object",
            "description": "The geocoded address used for E911 registration",
            "properties": {
              "house_number": {
                "type": "string",
                "description": "House or building number"
              },
              "street_name": {
                "type": "string",
                "description": "Street name"
              },
              "pre_directional": {
                "type": "string",
                "description": "Street name pre-directional (e.g., N, S, E, W)"
              },
              "street_suffix": {
                "type": "string",
                "description": "Street type suffix (e.g., ST, AVE)"
              },
              "post_directional": {
                "type": "string",
                "description": "Street name post-directional (e.g., N, S, E, W)"
              },
              "address_line_2": {
                "type": "string",
                "description": "Secondary address line (e.g., Suite, Apt, Floor)"
              },
              "city": {
                "type": "string",
                "description": "City name"
              },
              "state_code": {
                "type": "string",
                "description": "Two-letter state code"
              },
              "zip": {
                "type": "string",
                "description": "ZIP code"
              },
              "plus_four": {
                "type": "string",
                "description": "ZIP+4 extension"
              },
              "county": {
                "type": "string",
                "description": "County name"
              },
              "country": {
                "type": "string",
                "description": "Country code"
              }
            }
          }
        },
        "required": [
          "adjusted"
        ]
      },
      "AddressInput": {
        "type": "object",
        "description": "Address fields for creating or updating a location",
        "properties": {
          "address_number": {
            "type": "string",
            "maxLength": 255,
            "description": "House or building number",
            "example": "1600"
          },
          "street": {
            "type": "string",
            "maxLength": 255,
            "description": "Street name",
            "example": "Pennsylvania Avenue NW"
          },
          "unit": {
            "type": "string",
            "maxLength": 255,
            "description": "Unit, suite, or apartment number",
            "example": "Suite 200"
          },
          "city": {
            "type": "string",
            "maxLength": 255,
            "description": "City or locality",
            "example": "New York"
          },
          "state": {
            "type": "string",
            "description": "State or province code",
            "example": "NY"
          },
          "postal_code": {
            "type": "string",
            "description": "Postal or ZIP code",
            "example": "10001"
          },
          "country": {
            "type": "string",
            "enum": [
              "US",
              "CA",
              "MX"
            ],
            "description": "Two-letter country code",
            "example": "US"
          }
        },
        "required": [
          "street",
          "city",
          "state",
          "postal_code",
          "country"
        ]
      },
      "CreateLocationRequest": {
        "type": "object",
        "description": "Request body for creating a location",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "description": "Display name of the location",
            "example": "Main Office"
          },
          "address": {
            "$ref": "#/components/schemas/AddressInput"
          },
          "primary_did": {
            "type": "string",
            "deprecated": true,
            "description": "Deprecated. Historical main phone number for the location. This\nfield does not affect E911 provisioning or emergency dispatch.\n"
          }
        },
        "required": [
          "name",
          "address"
        ]
      },
      "UpdateLocationRequest": {
        "type": "object",
        "description": "Request body for updating a location (all fields optional)",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "description": "Display name of the location",
            "example": "Updated Office"
          },
          "address": {
            "$ref": "#/components/schemas/AddressInput"
          },
          "primary_did": {
            "type": [
              "string",
              "null"
            ],
            "deprecated": true,
            "description": "Deprecated. Historical main phone number for the location. This\nfield does not affect E911 provisioning or emergency dispatch.\n"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "inactive"
            ],
            "deprecated": true,
            "description": "Deprecated. The operational-status field was retired; the value is\naccepted for backwards compatibility but ignored.\n"
          },
          "config": {
            "$ref": "#/components/schemas/LocationConfig"
          }
        }
      },
      "PortOrder": {
        "type": "object",
        "description": "A port order tracks the process of transferring (porting) existing phone numbers\nfrom another carrier to DialStack. Port orders follow a draft-based\nworkflow: create a draft, have the customer approve the order, then submit\nfor processing.\n\n## Status Lifecycle\n\n```\ndraft → approved → submitted → foc (scheduled) → complete\n                              → exception → (update + resubmit) → submitted\n                              → cancelled\ndraft → cancelled\napproved → cancelled\n```\n\n- `draft` — Order created, not yet approved\n- `approved` — Customer has approved the order, ready to submit\n- `submitted` — Sent to the carrier, awaiting processing\n- `exception` — Rejected by the carrier (can be corrected and resubmitted)\n- `foc` — The port is scheduled (a Firm Order Commitment has been received from the carrier confirming the completion date)\n- `complete` — Numbers successfully ported and active\n- `cancelled` — Order was cancelled\n",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              }
            ],
            "example": "por_01h2xcejqtf2nbrexx3vqjhp53"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "approved",
              "submitted",
              "exception",
              "foc",
              "complete",
              "cancelled"
            ],
            "description": "Current status of the port order",
            "example": "draft"
          },
          "details": {
            "$ref": "#/components/schemas/PortOrderDetails"
          },
          "submitted_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the order was submitted for processing",
            "example": "2026-02-15T14:30:00Z"
          },
          "created_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CreatedAt"
              }
            ]
          },
          "updated_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/UpdatedAt"
              }
            ]
          }
        },
        "required": [
          "id",
          "status",
          "details",
          "created_at",
          "updated_at"
        ]
      },
      "PortOrderDetails": {
        "type": "object",
        "description": "Details of the port order including phone numbers, subscriber information, and document metadata",
        "properties": {
          "phone_numbers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Phone numbers to port (E.164 format)",
            "example": [
              "+12025551234"
            ]
          },
          "subscriber": {
            "$ref": "#/components/schemas/PortSubscriber"
          },
          "requested_foc_date": {
            "type": "string",
            "format": "date",
            "description": "Requested date for the port to complete (YYYY-MM-DD). Must be at least 5 business days and no more than 30 calendar days from today. \"FOC\" stands for Firm Order Commitment.",
            "example": "2026-03-01"
          },
          "requested_foc_time": {
            "type": [
              "string",
              "null"
            ],
            "description": "Requested time for the port to complete, in HH:MM format (08:00-20:00 Eastern). Optional.",
            "example": "10:00"
          },
          "actual_foc_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Actual scheduled date/time confirmed by the carrier",
            "example": "2026-03-01T10:00:00Z"
          },
          "losing_carrier": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PortCarrier"
              },
              {
                "type": "null"
              }
            ],
            "description": "Losing carrier information (populated after submission)"
          },
          "approval": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PortApproval"
              },
              {
                "type": "null"
              }
            ],
            "description": "Customer approval details (populated when the order is approved)"
          },
          "rejection": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PortRejection"
              },
              {
                "type": "null"
              }
            ],
            "description": "Rejection details (populated when status is exception)"
          },
          "loa": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PortDocumentMeta"
              },
              {
                "type": "null"
              }
            ],
            "description": "Authorization document metadata (generated automatically on submission)"
          },
          "csr": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PortDocumentMeta"
              },
              {
                "type": "null"
              }
            ],
            "description": "Customer Service Record document metadata"
          },
          "bill_copy": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PortDocumentMeta"
              },
              {
                "type": "null"
              }
            ],
            "description": "Bill copy document metadata"
          }
        },
        "required": [
          "phone_numbers"
        ]
      },
      "PortSubscriber": {
        "type": "object",
        "description": "Subscriber and authorization information for the port request",
        "properties": {
          "btn": {
            "type": "string",
            "description": "Billing Telephone Number (E.164 format)",
            "example": "+12025551234"
          },
          "business_name": {
            "type": "string",
            "description": "Business or account name as it appears on the invoice from the current service provider",
            "example": "Doe Enterprises"
          },
          "approver_name": {
            "type": "string",
            "description": "Full name of the person who will approve the port order",
            "example": "John Doe"
          },
          "account_number": {
            "type": [
              "string",
              "null"
            ],
            "description": "Account number with the losing carrier. Required for some wireless ports — check the `account_number_required` field in the eligibility response.",
            "example": "123456789"
          },
          "pin": {
            "type": [
              "string",
              "null"
            ],
            "description": "PIN or password for the losing carrier account. Often required alongside `account_number` for wireless ports.",
            "example": "1234"
          },
          "address": {
            "$ref": "#/components/schemas/PortAddress"
          }
        },
        "required": [
          "btn",
          "business_name",
          "approver_name",
          "address"
        ]
      },
      "PortAddress": {
        "type": "object",
        "description": "Service address for the port request",
        "properties": {
          "house_number": {
            "type": "string",
            "description": "House or building number",
            "example": "123"
          },
          "street_name": {
            "type": "string",
            "description": "Street name (without house number)",
            "example": "Main St"
          },
          "line2": {
            "type": [
              "string",
              "null"
            ],
            "description": "Apartment, suite, unit, etc. (optional)",
            "example": "Suite 200"
          },
          "city": {
            "type": "string",
            "description": "City",
            "example": "Anytown"
          },
          "state": {
            "type": "string",
            "minLength": 2,
            "maxLength": 2,
            "description": "Two-letter state code (auto-uppercased)",
            "example": "VA"
          },
          "zip": {
            "type": "string",
            "description": "ZIP code",
            "example": "22030"
          }
        },
        "required": [
          "house_number",
          "street_name",
          "city",
          "state",
          "zip"
        ]
      },
      "PortCarrier": {
        "type": "object",
        "description": "Losing carrier information",
        "properties": {
          "name": {
            "type": "string",
            "description": "Carrier name",
            "example": "Verizon"
          },
          "spid": {
            "type": "string",
            "description": "Carrier SPID",
            "example": "1234"
          },
          "port_type": {
            "type": "string",
            "description": "Port type (e.g., automated, manual)",
            "example": "automated"
          }
        }
      },
      "PortRejection": {
        "type": "object",
        "description": "Rejection details from the carrier",
        "properties": {
          "code": {
            "type": "string",
            "description": "Rejection reason code",
            "enum": [
              "address_mismatch",
              "account_number_invalid",
              "name_mismatch",
              "business_name_mismatch",
              "btn_mismatch",
              "pin_required",
              "pin_invalid",
              "port_date_invalid",
              "mixed_carrier",
              "pending_order",
              "tn_not_portable",
              "carrier_freeze",
              "type_of_service_mismatch",
              "carrier_system_error",
              "unknown"
            ],
            "example": "address_mismatch"
          },
          "message": {
            "type": "string",
            "description": "Human-readable rejection message",
            "example": "Service address mismatch"
          }
        }
      },
      "PortApproval": {
        "type": "object",
        "description": "Customer approval details for a port order",
        "properties": {
          "signature": {
            "type": "string",
            "description": "Electronic signature (the customer's typed name)",
            "example": "Jane Smith"
          },
          "ip": {
            "type": "string",
            "description": "IP address of the customer at the time of approval",
            "example": "203.0.113.42"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "When the approval was given",
            "example": "2026-02-15T14:02:00Z"
          }
        },
        "required": [
          "signature",
          "ip",
          "timestamp"
        ]
      },
      "ApprovePortOrderRequest": {
        "type": "object",
        "description": "Request body for approving a port order",
        "properties": {
          "signature": {
            "type": "string",
            "description": "Electronic signature (the customer's typed name authorizing the port)",
            "example": "Jane Smith"
          },
          "ip": {
            "type": "string",
            "description": "IP address of the customer approving the order",
            "example": "203.0.113.42"
          }
        },
        "required": [
          "signature",
          "ip"
        ]
      },
      "PortDocumentMeta": {
        "type": "object",
        "description": "Metadata about a port order document",
        "properties": {
          "content_type": {
            "type": "string",
            "description": "MIME type of the document",
            "example": "application/pdf"
          },
          "file_size": {
            "type": "integer",
            "description": "File size in bytes",
            "example": 123456
          }
        },
        "required": [
          "content_type",
          "file_size"
        ]
      },
      "PortOrderEvent": {
        "type": "object",
        "description": "An audit event recording a status change on a port order",
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              }
            ],
            "example": "poe_01h2xcejqtf2nbrexx3vqjhp54"
          },
          "port_order": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityId"
              }
            ],
            "example": "por_01h2xcejqtf2nbrexx3vqjhp53"
          },
          "old_status": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "draft",
              "approved",
              "submitted",
              "exception",
              "foc",
              "complete",
              "cancelled",
              null
            ],
            "description": "Previous status (null for the initial creation event)"
          },
          "new_status": {
            "type": "string",
            "enum": [
              "draft",
              "approved",
              "submitted",
              "exception",
              "foc",
              "complete",
              "cancelled"
            ],
            "description": "New status after this event"
          },
          "bandwidth_status": {
            "type": [
              "string",
              "null"
            ],
            "description": "Raw status string from the carrier (if applicable)"
          },
          "message": {
            "type": [
              "string",
              "null"
            ],
            "description": "Human-readable event message"
          },
          "reason_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "Raw upstream carrier error code for debugging (if applicable). The mapped rejection reason is in the order's `details.rejection.code` field."
          },
          "created_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CreatedAt"
              }
            ]
          }
        },
        "required": [
          "id",
          "port_order",
          "new_status",
          "created_at"
        ]
      },
      "CreatePortOrderRequest": {
        "type": "object",
        "description": "Request body for creating a draft port order",
        "properties": {
          "phone_numbers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "maxItems": 100,
            "description": "US phone numbers to port (E.164 format, no toll-free)",
            "example": [
              "+12025551234"
            ]
          },
          "subscriber": {
            "$ref": "#/components/schemas/PortSubscriber"
          },
          "requested_foc_date": {
            "type": "string",
            "format": "date",
            "description": "Requested date for the port to complete (YYYY-MM-DD). Must be at least 5 business days and no more than 30 calendar days from today (excludes weekends and US federal holidays).",
            "example": "2026-03-01"
          },
          "requested_foc_time": {
            "type": "string",
            "description": "Requested time for the port to complete, in HH:MM format (08:00-20:00 Eastern). Optional.",
            "example": "10:00"
          }
        },
        "required": [
          "phone_numbers",
          "subscriber",
          "requested_foc_date"
        ]
      },
      "UpdatePortOrderRequest": {
        "type": "object",
        "description": "Request body for updating a port order in `draft`, `approved`, or `exception` status.\nAll fields are optional — only provided fields are updated.\nUpdating an approved order clears the approval and reverts the status to `draft`.\nFor exception orders, setting `resubmit: true` clears the rejection and re-submits.\n",
        "properties": {
          "phone_numbers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "maxItems": 100,
            "description": "Updated phone numbers (E.164 format, no toll-free)",
            "example": [
              "+12025551234"
            ]
          },
          "subscriber": {
            "$ref": "#/components/schemas/PortSubscriber"
          },
          "requested_foc_date": {
            "type": "string",
            "format": "date",
            "description": "Updated requested completion date (YYYY-MM-DD). Must be at least 5 business days and no more than 30 calendar days from today.",
            "example": "2026-03-15"
          },
          "requested_foc_time": {
            "type": "string",
            "description": "Updated requested completion time in HH:MM format (08:00-20:00 Eastern)",
            "example": "10:00"
          },
          "resubmit": {
            "type": "boolean",
            "description": "When true and the order is in `exception` status, clears the rejection and re-submits to the carrier.",
            "default": false
          }
        }
      },
      "PortInEligibilityRequest": {
        "type": "object",
        "description": "Request body for checking port-in eligibility",
        "properties": {
          "phone_numbers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "maxItems": 100,
            "description": "US phone numbers to check (E.164 format, no toll-free)",
            "example": [
              "+12025551234",
              "+14155559876"
            ]
          }
        },
        "required": [
          "phone_numbers"
        ]
      },
      "PortInEligibilityResult": {
        "type": "object",
        "description": "Port-in eligibility check result",
        "required": [
          "portable_numbers",
          "non_portable_numbers"
        ],
        "properties": {
          "portable_numbers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PortableNumber"
            },
            "description": "Numbers that can be ported"
          },
          "non_portable_numbers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NonPortableNumber"
            },
            "description": "Numbers that cannot be ported"
          }
        }
      },
      "PortableNumber": {
        "type": "object",
        "description": "A phone number that is eligible for porting",
        "properties": {
          "phone_number": {
            "type": "string",
            "description": "Phone number in E.164 format",
            "example": "+14155559876"
          },
          "losing_carrier_name": {
            "type": "string",
            "description": "Name of the current carrier",
            "example": "T-Mobile US-SVR-10X/2"
          },
          "losing_carrier_spid": {
            "type": "string",
            "description": "Carrier SPID",
            "example": "6529"
          },
          "is_wireless": {
            "type": "boolean",
            "description": "Whether this is a wireless number",
            "example": true
          },
          "account_number_required": {
            "type": "boolean",
            "description": "Whether the losing carrier requires an account number for porting. When true, include `account_number` (and typically `pin`) in the port order subscriber details.",
            "example": false
          }
        },
        "required": [
          "phone_number",
          "is_wireless",
          "account_number_required"
        ]
      },
      "NonPortableNumber": {
        "type": "object",
        "description": "A phone number that cannot be ported",
        "properties": {
          "phone_number": {
            "type": "string",
            "description": "Phone number in E.164 format",
            "example": "+12025559999"
          },
          "rate_center": {
            "type": "string",
            "description": "Rate center where the number is located",
            "example": "WASHINGT DC"
          },
          "city": {
            "type": "string",
            "description": "City",
            "example": "Washington"
          },
          "state": {
            "type": "string",
            "description": "State",
            "example": "DC"
          }
        },
        "required": [
          "phone_number"
        ]
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable error message",
            "example": "Invalid request body"
          },
          "code": {
            "type": "string",
            "description": "Machine-readable error code",
            "example": "validation_error"
          },
          "details": {
            "type": "object",
            "additionalProperties": true,
            "description": "Additional error context (field-specific validation errors, etc.)"
          }
        },
        "required": [
          "error"
        ]
      },
      "PhoneNumberOrderConflictResponse": {
        "type": "object",
        "description": "409 response when an order cannot be placed for the numbers requested.\n\nExtends Error with a stable `code` so the reason can be handled\nprogrammatically without matching on the human-readable `error` string.\nThe `code` is the machine-readable contract. Nothing else is added\nunless the caller cannot work it out for itself, which rules out the\nnumbers they sent, the endpoint they called, and their own cap.\n\n`phone_numbers_already_claimed` is the one code that carries a `details`\nobject, because which of the submitted numbers conflicted — and which of\nthose are in service on another account — appears in no response the\ncaller can fetch. It holds those two arrays and nothing else; the wording\nshown to a customer belongs to the client.\n\n| `code` | Meaning |\n| --- | --- |\n| `phone_number_limit_exceeded` | The account is at its phone number limit. Its cap is `config.max_phone_numbers` on the account. Raise the cap and retry; the request is not resized automatically. |\n| `phone_numbers_already_claimed` | One or more of the requested numbers are already in service and cannot be ordered. The `error` string names them, and distinguishes numbers already on this account (take them off the request) from numbers in service on another account (an intra-carrier transfer, arranged by support — there is no port to run). |\n",
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable error message",
            "example": "phone number(s) already claimed — already on this account: +17702126011; already in service on another account, so they need an intra-carrier transfer rather than a port: +14045551212"
          },
          "code": {
            "type": "string",
            "enum": [
              "phone_number_limit_exceeded",
              "phone_numbers_already_claimed"
            ],
            "description": "Machine-readable error code",
            "example": "phone_numbers_already_claimed"
          },
          "details": {
            "$ref": "#/components/schemas/AlreadyClaimedDetails"
          }
        },
        "required": [
          "error",
          "code"
        ]
      },
      "AlreadyClaimedDetails": {
        "type": "object",
        "description": "Present only on `phone_numbers_already_claimed`, and only ever holding\nthese two arrays.\n\nThey say which of the numbers you sent are unavailable and which\nsituation each is in, so the entry can be flagged where the customer\ntyped it rather than asking them to compare the list by hand. Nothing\nhere is wording — how it reads to a customer is yours to write.\n\nBoth keys are always present. An empty group is `[]`, never `null` and\nnever omitted.\n",
        "properties": {
          "already_on_account": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Numbers this account already holds. They do not need ordering again —\ntake them off the request and retry.\n",
            "example": [
              "+17702126011"
            ]
          },
          "in_service_elsewhere": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Numbers in service on another account. They are with the same carrier\nalready, so there is no port to run: moving one is an intra-carrier\ntransfer arranged by support, and retrying will not help.\n",
            "example": [
              "+14045551212"
            ]
          }
        },
        "required": [
          "already_on_account",
          "in_service_elsewhere"
        ]
      },
      "PortOrderUpdateConflictResponse": {
        "type": "object",
        "description": "409 response when a port order cannot be edited as requested.\n\nExtends Error with a stable `code` so the reason can be handled\nprogrammatically without matching on the human-readable `error` string.\nThe `code` is the machine-readable contract. Nothing else is added\nunless the caller cannot work it out for itself, which rules out the\nnumbers they sent, the endpoint they called, and their own cap.\n\n`phone_numbers_already_claimed` is the one code that carries a `details`\nobject, because which of the submitted numbers conflicted — and which of\nthose are in service on another account — appears in no response the\ncaller can fetch. It holds those two arrays and nothing else; the wording\nshown to a customer belongs to the client.\n\n| `code` | Meaning |\n| --- | --- |\n| `phone_number_limit_exceeded` | The account is at its phone number limit. Its cap is `config.max_phone_numbers` on the account. Raise the cap and retry; the request is not resized automatically. |\n| `phone_numbers_already_claimed` | One or more of the requested numbers are already in service and cannot be ordered. The `error` string names them, and distinguishes numbers already on this account (take them off the request) from numbers in service on another account (an intra-carrier transfer, arranged by support — there is no port to run). |\n| `port_order_invalid_state` | The order's current status does not allow the action. The message names both the status and the attempted action. |\n",
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable error message",
            "example": "port order is in \"submitted\" status, cannot update"
          },
          "code": {
            "type": "string",
            "enum": [
              "phone_number_limit_exceeded",
              "phone_numbers_already_claimed",
              "port_order_invalid_state"
            ],
            "description": "Machine-readable error code",
            "example": "port_order_invalid_state"
          },
          "details": {
            "$ref": "#/components/schemas/AlreadyClaimedDetails"
          }
        },
        "required": [
          "error",
          "code"
        ]
      },
      "PortOrderStateConflictResponse": {
        "type": "object",
        "description": "409 response when the action does not fit the port order's current status.\n\nExtends Error with a stable `code` so the reason can be handled\nprogrammatically without matching on the human-readable `error` string.\nThe `code` is the machine-readable contract. Nothing else is added\nunless the caller cannot work it out for itself, which rules out the\nnumbers they sent, the endpoint they called, and their own cap.\n\n`phone_numbers_already_claimed` is the one code that carries a `details`\nobject, because which of the submitted numbers conflicted — and which of\nthose are in service on another account — appears in no response the\ncaller can fetch. It holds those two arrays and nothing else; the wording\nshown to a customer belongs to the client.\n\n| `code` | Meaning |\n| --- | --- |\n| `port_order_invalid_state` | The order's current status does not allow the action. The message names both the status and the attempted action. |\n",
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable error message",
            "example": "port order is in \"draft\" status, cannot submit"
          },
          "code": {
            "type": "string",
            "enum": [
              "port_order_invalid_state"
            ],
            "description": "Machine-readable error code",
            "example": "port_order_invalid_state"
          }
        },
        "required": [
          "error",
          "code"
        ]
      },
      "DeviceUserConflictResponse": {
        "type": "object",
        "description": "409 response for `POST /v1/devices/{id}/users` when the assignment\nviolates the at-most-one-device-per-user rule. Extends Error with\na stable `code` and, when applicable, the ID of the device the\ntarget user is already assigned to. The admin UI uses\n`existing_device` to drive its reassign-confirm flow without\nstring-matching on `error`.\n",
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable error message",
            "example": "user is already assigned to another device"
          },
          "code": {
            "type": "string",
            "enum": [
              "user_already_assigned",
              "user_already_has_device",
              "user_already_has_endpoint",
              "handset_already_assigned",
              "device_full",
              "base_full"
            ],
            "description": "Machine-readable error code",
            "example": "user_already_has_device"
          },
          "existing_device": {
            "type": "string",
            "description": "Identifier of the device the user is already assigned to.\nPresent on `user_already_has_device`; omitted on other codes.\n",
            "example": "dev_01h2xcejqtf2nbrexx3vqjhp40"
          }
        },
        "required": [
          "error",
          "code"
        ]
      }
    }
  },
  "paths": {
    "/v1/accounts": {
      "post": {
        "summary": "Create a new account",
        "description": "Creates a new account (customer organization) within the platform.\nAccounts represent individual customer organizations (e.g., Jones Chiropractic)\nthat use the vSaaS platform.\n\nThe provided `address` becomes the account's main location — the default\nlocation used for E911 and for tax and fee jurisdiction — created\natomically with the account, so a single-site account is immediately set\nup for 911 and taxes and fees with no separate step.\n\nThe account's mode is determined by the key you authenticate with: a\nlive key (`sk_live_`) creates a live account, a test key (`sk_test_`)\ncreates a sandbox account. Creating a live account requires live mode to\nbe enabled on your platform; if it is not, the request is rejected with\n`403`. Sandbox accounts are unaffected.\n",
        "operationId": "createAccount",
        "tags": [
          "Accounts"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAccountRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Basic account creation",
                  "value": {
                    "email": "contact@example.com",
                    "primary_contact_name": "Jane Doe",
                    "address": {
                      "street": "123 Main St",
                      "city": "New York",
                      "state": "NY",
                      "postal_code": "10001",
                      "country": "US"
                    },
                    "pricing": {
                      "per_user_rate": 1999,
                      "per_did_rate": 299,
                      "per_voiceai_location_rate": 4999
                    }
                  }
                },
                "with_config": {
                  "summary": "Account with configuration",
                  "value": {
                    "email": "contact@example.com",
                    "primary_contact_name": "Jane Doe",
                    "config": {
                      "region": "US",
                      "timezone": "America/New_York",
                      "extension_length": 4
                    },
                    "address": {
                      "street": "123 Main St",
                      "city": "New York",
                      "state": "NY",
                      "postal_code": "10001",
                      "country": "US"
                    },
                    "pricing": {
                      "per_user_rate": 1999,
                      "per_did_rate": 299,
                      "per_voiceai_location_rate": 4999
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Account created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                },
                "examples": {
                  "success": {
                    "summary": "Successful account creation",
                    "value": {
                      "id": "acct_01h2xcejqtf2nbrexx3vqjhp41",
                      "email": "contact@example.com",
                      "config": {},
                      "created_at": "2025-10-18T10:00:00Z",
                      "updated_at": "2025-10-18T10:00:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Live mode is not enabled for this platform, so live accounts cannot be created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/accounts \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'content-type: application/json' \\\n  -d '{\"email\":\"contact@example.com\",\"name\":\"Acme Corp\",\"phone\":\"+12125550100\",\"primary_contact_name\":\"Jane Doe\",\"config\":{\"region\":\"US\",\"extension_length\":4,\"transcription_enabled\":true,\"recording_enabled\":true,\"redaction_enabled\":false,\"timezone\":\"America/New_York\",\"max_phone_numbers\":25,\"parking_timeout_seconds\":300,\"fax_inbound_per_hour\":25,\"fax_outbound_per_hour\":25,\"default_agent_visible\":false,\"e911_notification\":{\"emails\":[\"security@example.com\",\"frontdesk@example.com\"]}},\"address\":{\"address_number\":\"1600\",\"street\":\"Pennsylvania Avenue NW\",\"unit\":\"Suite 200\",\"city\":\"New York\",\"state\":\"NY\",\"postal_code\":\"10001\",\"country\":\"US\"},\"billing_address\":{\"address_number\":\"1600\",\"street\":\"Pennsylvania Avenue NW\",\"unit\":\"Suite 200\",\"city\":\"New York\",\"state\":\"NY\",\"postal_code\":\"10001\",\"country\":\"US\"},\"pricing\":{\"per_user_rate\":1000000,\"per_did_rate\":1000000,\"per_voiceai_location_rate\":1000000}}'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.accounts.create(/* body params */);"
          }
        ]
      },
      "get": {
        "summary": "List all accounts",
        "operationId": "listAccounts",
        "tags": [
          "Accounts"
        ],
        "description": "List all accounts for the authenticated platform. Results are returned\nin reverse chronological order (newest first).\n\nEvery account carries its subscription-agreement (SSA/TOS) coverage as\n`tos_status` (and `tos_accepted_at`), so callers can build an\nagreement-coverage view — e.g. surfacing the live accounts still blocked\nfrom PSTN (`tos_status: \"unsigned\"`) until they accept.\n",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "List of accounts",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Account"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                },
                "examples": {
                  "list": {
                    "summary": "Account list response",
                    "value": {
                      "object": "list",
                      "url": "/v1/accounts",
                      "next_page_url": null,
                      "previous_page_url": null,
                      "data": [
                        {
                          "id": "acct_01h2xcejqtf2nbrexx3vqjhp41",
                          "email": "contact@example.com",
                          "config": {},
                          "created_at": "2025-10-18T10:00:00Z",
                          "updated_at": "2025-10-18T10:00:00Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/accounts?limit=10' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.accounts.list();"
          }
        ]
      }
    },
    "/v1/accounts/{account_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/AccountId"
        }
      ],
      "get": {
        "summary": "Get account details",
        "operationId": "getAccount",
        "tags": [
          "Accounts"
        ],
        "description": "Retrieve a specific account by ID. The response carries the account's\nsubscription-agreement coverage as `tos_status` / `tos_accepted_at`; the\nfull agreement document is on `GET /v1/accounts/{account_id}/tos`.\n",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Account details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/AccountNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/accounts/acct_01h2xcejqtf2nbrexx3vqjhp41 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.accounts.retrieve('account_...');"
          }
        ]
      },
      "post": {
        "summary": "Update account",
        "description": "Update account details.\n",
        "operationId": "updateAccount",
        "tags": [
          "Accounts"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAccountRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Account updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/AccountNotFound"
          },
          "409": {
            "description": "Returned when the supplied `main_location` or\n`default_button_template` was modified or deleted in a concurrent\nrequest. Retry with another active resource.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/accounts/acct_01h2xcejqtf2nbrexx3vqjhp41 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'content-type: application/json' \\\n  -d '{\"email\":\"contact@example.com\",\"name\":\"Acme Corp\",\"phone\":\"+12125550100\",\"primary_contact_name\":\"Jane Doe\",\"config\":{\"region\":\"US\",\"extension_length\":4,\"transcription_enabled\":true,\"recording_enabled\":true,\"redaction_enabled\":false,\"timezone\":\"America/New_York\",\"max_phone_numbers\":25,\"parking_timeout_seconds\":300,\"fax_inbound_per_hour\":25,\"fax_outbound_per_hour\":25,\"default_agent_visible\":false,\"e911_notification\":{\"emails\":[\"security@example.com\",\"frontdesk@example.com\"]}},\"default_outbound_did\":\"string\",\"hold_music_clip\":\"string\",\"main_location\":\"string\",\"default_button_template\":\"string\",\"billing_address\":{\"address_number\":\"1600\",\"street\":\"Pennsylvania Avenue NW\",\"unit\":\"Suite 200\",\"city\":\"New York\",\"state\":\"NY\",\"postal_code\":\"10001\",\"country\":\"US\"}}'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.accounts.update('account_...', /* body params */);"
          }
        ]
      },
      "delete": {
        "summary": "Delete account",
        "description": "Delete an account and all associated users, endpoints, and call logs.\nThis operation is irreversible. Active calls will be terminated.\n",
        "operationId": "deleteAccount",
        "tags": [
          "Accounts"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/AccountDeleted"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/AccountNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/accounts/acct_01h2xcejqtf2nbrexx3vqjhp41 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.accounts.del('account_...');"
          }
        ]
      }
    },
    "/v1/accounts/{account_id}/pricing": {
      "parameters": [
        {
          "$ref": "#/components/parameters/AccountId"
        }
      ],
      "get": {
        "summary": "Get agreed pricing",
        "description": "Retrieve the agreed retail pricing for an account. Rates are the\nplatform's retail prices in cents, per month.\n",
        "operationId": "getAccountPricing",
        "tags": [
          "Accounts"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Agreed pricing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountPricing"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/AccountNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/accounts/acct_01h2xcejqtf2nbrexx3vqjhp41/pricing \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/accounts/{account_id}/pricing`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Set agreed pricing",
        "description": "Create or replace the agreed retail pricing for an account. All three\nrates are required, in cents.\n",
        "operationId": "upsertAccountPricing",
        "tags": [
          "Accounts"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AccountPricingRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Agreed pricing set",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountPricing"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/AccountNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/accounts/acct_01h2xcejqtf2nbrexx3vqjhp41/pricing \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'content-type: application/json' \\\n  -d '{\"per_user_rate\":1000000,\"per_did_rate\":1000000,\"per_voiceai_location_rate\":1000000}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/accounts/{account_id}/pricing`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/accounts/{account_id}/tos": {
      "parameters": [
        {
          "$ref": "#/components/parameters/AccountId"
        }
      ],
      "get": {
        "summary": "Get the subscription agreement",
        "description": "Returns the account's subscription-agreement resource: the current\nagreement document and the account's acceptance state (null until\naccepted). Pass `expand[]=pricing` to also include the account's agreed\npricing (what the customer is accepting).\n",
        "operationId": "getAccountTos",
        "tags": [
          "Accounts"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "expand[]",
            "in": "query",
            "required": false,
            "description": "Related resources to expand. Supports `pricing`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "pricing"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Agreement resource",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Tos"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/AccountNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/accounts/acct_01h2xcejqtf2nbrexx3vqjhp41/tos?expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/accounts/{account_id}/tos`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Accept the subscription agreement",
        "description": "Record the account's acceptance of the subscription agreement and\nreturn the updated agreement resource. Acceptance may be recorded either\nby the account owner accepting in-portal (an account session) or by the\nplatform on the owner's behalf using its secret API key — by calling\nthis endpoint with your API key you assert that you presented the\nagreement to the account owner and the owner accepted. Any other\ncredential is rejected (403). The submitted version must match the\ncurrent agreement (409 otherwise). The account's pricing must be set\nfirst, since the agreement embeds it (422 otherwise); the accepted\npricing is snapshotted onto the acceptance record. Re-accepting the same\nversion is idempotent.\n",
        "operationId": "acceptAccountTos",
        "tags": [
          "Accounts"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TosAcceptanceRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Acceptance recorded (or unchanged, when the same version was already accepted)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Tos"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The presented credential is not permitted to accept the agreement (only an account session or the platform's secret API key may accept)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/AccountNotFound"
          },
          "409": {
            "description": "Agreement version is out of date; re-fetch and accept the current version",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Account pricing must be set before the agreement can be accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/accounts/acct_01h2xcejqtf2nbrexx3vqjhp41/tos \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'content-type: application/json' \\\n  -d '{\"version\":\"string\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/accounts/{account_id}/tos`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/account_sessions": {
      "post": {
        "summary": "Create an account session",
        "description": "Creates a session with account-scoped access. Sessions expire after 1 hour.\nThe session token is scoped to the specified components — it can only access\nAPI endpoints required by those components.\n\nThe account and components are specified in the request body.\n",
        "operationId": "createAccountSession",
        "tags": [
          "Sessions"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAccountSessionRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Session created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateSessionResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/AccountNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/account_sessions \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'content-type: application/json' \\\n  -d '{\"account\":\"acct_01h2xcejqtf2nbrexx3vqjhp41\",\"components\":{\"call_logs\":{\"enabled\":true},\"voicemails\":{\"enabled\":true}}}'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.accountSessions.create(/* body params */);"
          }
        ]
      }
    },
    "/v1/user_sessions": {
      "post": {
        "summary": "Create a user session",
        "description": "Mints a short-lived JWT scoped to a single DialStack user. The returned\n`client_secret` is used by the WebRTC client SDK to authenticate to the\nsignalling WebSocket and user-scoped REST routes such as\n`/v1/me/emergency-addresses`. (The broader `/v1/me/*` surface — profile,\ncall history, presence — is documented ahead of release and not yet\navailable.)\n\nSessions default to a 24-hour lifetime and may not exceed 7 days. The\nuser must already exist under an account owned by the calling platform.\nOutstanding sessions can be invalidated at any time with\n`POST /v1/users/{user_id}/revoke_sessions`.\n",
        "operationId": "createUserSession",
        "tags": [
          "Sessions"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateUserSessionRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "User session created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateUserSessionResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/UserNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/user_sessions \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'content-type: application/json' \\\n  -d '{\"user\":\"user_01h2xcejqtf2nbrexx3vqjhp42\",\"ttl_seconds\":86400}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/user_sessions`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/users/{user_id}/revoke_sessions": {
      "post": {
        "summary": "Revoke a user's sessions",
        "description": "Invalidates every outstanding user-session token for the user, all at\nonce. Tokens minted before this call stop working immediately on REST\nroutes and at WebRTC connection time; active WebRTC connections are\ntorn down at their next call event (placing or receiving a call).\n\nUse this as the server-side kill switch when a user must be cut off\nbefore their tokens expire (offboarding, compromised device, abuse).\nNew sessions can be minted for the user immediately afterwards.\n",
        "operationId": "revokeUserSessions",
        "tags": [
          "Sessions"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "user_id",
            "in": "path",
            "required": true,
            "description": "Identifier of the user whose sessions to revoke",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sessions revoked successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RevokeUserSessionsResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/UserNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/users/%7Buser_id%7D/revoke_sessions \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/users/{user_id}/revoke_sessions`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/audit-logs": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "get": {
        "summary": "List audit logs",
        "description": "List audit log entries for an account with optional filtering.\nResults are returned in reverse chronological order (newest first).\n",
        "operationId": "listAuditLogs",
        "tags": [
          "Audit Logs"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "event",
            "in": "query",
            "description": "Filter by event type (e.g., `user.create`, `auth.denied`). Supports comma-separated values.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "resource",
            "in": "query",
            "description": "Filter by resource ID (exact match)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "actor",
            "in": "query",
            "description": "Filter by actor ID (exact match)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "outcome",
            "in": "query",
            "description": "Filter by outcome",
            "schema": {
              "type": "string",
              "enum": [
                "success",
                "failure",
                "denied"
              ]
            }
          },
          {
            "name": "ip_address",
            "in": "query",
            "description": "Filter by IP address",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "created_after",
            "in": "query",
            "description": "Filter events created at or after this time (ISO 8601)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_before",
            "in": "query",
            "description": "Filter events created at or before this time (ISO 8601)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A paginated list of audit log entries",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AuditLogEntry"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/audit-logs?limit=10&event=SOME_STRING_VALUE&resource=SOME_STRING_VALUE&actor=SOME_STRING_VALUE&outcome=SOME_STRING_VALUE&ip_address=SOME_STRING_VALUE&created_after=SOME_STRING_VALUE&created_before=SOME_STRING_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/audit-logs`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/users": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "post": {
        "summary": "Create a new user",
        "description": "Create a new user within the account. Users represent people who have phone service.\nEach user can have multiple endpoints (devices).\n",
        "operationId": "createUser",
        "tags": [
          "Users"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateUserRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Basic user",
                  "value": {
                    "name": "Dr. Alice Smith",
                    "email": "alice@spineline.dev"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "User created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                },
                "examples": {
                  "success": {
                    "summary": "Successful user creation",
                    "value": {
                      "id": "user_01h2xcejqtf2nbrexx3vqjhp42",
                      "name": "Dr. Alice Smith",
                      "email": "alice@spineline.dev",
                      "created_at": "2025-10-18T10:00:00Z",
                      "updated_at": "2025-10-18T10:00:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/users \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"name\":\"Spineline\",\"email\":\"bob@spineline.dev\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.users.create(/* body params */, { dialstackAccount: 'acct_...' });"
          }
        ]
      },
      "get": {
        "summary": "List all users",
        "description": "List all users for the account.\nResults are returned in reverse chronological order (newest first).\n\n**Expandable fields:** `extensions` — includes the list of extensions assigned to each user.\n",
        "operationId": "listUsers",
        "tags": [
          "Users"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "search",
            "in": "query",
            "description": "Filter users by name or email (case-insensitive partial match)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `extensions`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "extensions"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of users",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/User"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                },
                "examples": {
                  "list": {
                    "summary": "User list response",
                    "value": {
                      "object": "list",
                      "url": "/v1/users",
                      "next_page_url": null,
                      "previous_page_url": null,
                      "data": [
                        {
                          "id": "user_01h2xcejqtf2nbrexx3vqjhp42",
                          "name": "Dr. Alice Smith",
                          "email": "alice@spineline.dev",
                          "created_at": "2025-10-18T10:00:00Z",
                          "updated_at": "2025-10-18T10:00:00Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/users?limit=10&search=SOME_STRING_VALUE&expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.users.list({ dialstackAccount: 'acct_...' });"
          }
        ]
      }
    },
    "/v1/users/{user_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/UserId"
        }
      ],
      "get": {
        "summary": "Get user details",
        "description": "Retrieve a specific user by ID.\n\n**Expandable fields:** `extensions` — includes the list of extensions assigned to this user.\n",
        "operationId": "getUser",
        "parameters": [
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `extensions`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "extensions"
                ]
              }
            }
          }
        ],
        "tags": [
          "Users"
        ],
        "responses": {
          "200": {
            "description": "User details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                },
                "examples": {
                  "success": {
                    "summary": "User details",
                    "value": {
                      "id": "user_01h2xcejqtf2nbrexx3vqjhp42",
                      "name": "Dr. Alice Smith",
                      "email": "alice@spineline.dev",
                      "created_at": "2025-10-18T10:00:00Z",
                      "updated_at": "2025-10-18T10:00:00Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/UserNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/users/user_01h2xcejqtf2nbrexx3vqjhp42?expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.users.retrieve('user_...', { dialstackAccount: 'acct_...' });"
          }
        ]
      },
      "post": {
        "summary": "Update user",
        "description": "Update user details (name, email, etc.)\n",
        "operationId": "updateUser",
        "tags": [
          "Users"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateUserRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "User updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                },
                "examples": {
                  "success": {
                    "summary": "User updated successfully",
                    "value": {
                      "id": "user_01h2xcejqtf2nbrexx3vqjhp42",
                      "name": "Dr. Alice Smith",
                      "email": "alice@spineline.dev",
                      "created_at": "2025-10-18T10:00:00Z",
                      "updated_at": "2025-10-18T10:00:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/UserNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/users/user_01h2xcejqtf2nbrexx3vqjhp42 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"name\":\"Spineline\",\"email\":\"bob@spineline.dev\",\"outbound_caller_id_did\":\"string\",\"voicemail_pin\":\"1234\",\"do_not_disturb\":true,\"config\":{\"voicemail_notifications\":{\"enabled\":false,\"attach_audio\":true,\"include_summary\":true,\"include_transcript\":true,\"delete_after_email\":false},\"find_me_follow_me\":{\"steps\":[{\"targets\":[{\"type\":\"external\",\"number\":\"+15551234567\",\"id\":\"string\"}],\"timeout\":1}],\"fallback\":\"voicemail\",\"fallback_target\":\"string\"},\"mobile_push_wakeup\":true}}'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.users.update('user_...', /* body params */, { dialstackAccount: 'acct_...' });"
          }
        ]
      },
      "delete": {
        "summary": "Delete user",
        "description": "Delete a user and all associated endpoints. This operation is irreversible.\nActive calls will be terminated.\n",
        "operationId": "deleteUser",
        "tags": [
          "Users"
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/UserDeleted"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/UserNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/users/user_01h2xcejqtf2nbrexx3vqjhp42 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.users.del('user_...', { dialstackAccount: 'acct_...' });"
          }
        ]
      }
    },
    "/v1/admin/users": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "get": {
        "summary": "List admin portal users",
        "description": "Returns a paginated list of the people who can administer this account\nin the admin portal.\n\nThe order is stable across pages but is not `created_at` order: entries\nare ordered by administrator identity, while `created_at` is the\ntimestamp of the role grant on this account. Do not rely on the first\nentry being the most recently granted one.\n\nThis is a different population from `GET /v1/users`, which lists voice\nusers. An administrator need not have phone service — an account owner\ntypically has none — so anyone listed here may be absent from\n`/v1/users`, and most voice users are absent from here. Together the two\ncollections cover everyone associated with the account. Use the `user`\nfield, rather than matching on email yourself, to link the two.\n\nOnly explicit role grants on this account are listed. Someone with\nplatform-wide access but no grant on this account does not appear.\n\nNote that a role can be granted before the person has accepted their\ninvitation to the portal, so an administrator listed here may not yet\nhave signed in.\n\nThis collection is read-only; roles are granted in the admin portal.\n\n**Expandable fields:** `user` — replaces the voice user's id with the\nfull User object.\n",
        "operationId": "listAdminUsers",
        "tags": [
          "Admin Portal Users"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `user`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "user"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of admin portal users",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AdminUser"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "An owner with no phone service, and an administrator who also has it",
                    "value": {
                      "object": "list",
                      "url": "/v1/admin/users",
                      "next_page_url": null,
                      "previous_page_url": null,
                      "data": [
                        {
                          "id": "admin_user_01h2xcejqtf2nbrexx3vqjhp44",
                          "name": "Sam Okafor",
                          "email": "sam@example.com",
                          "role": "owner",
                          "user": null,
                          "created_at": "2026-06-02T11:04:12Z"
                        },
                        {
                          "id": "admin_user_01h2xcejqtf2nbrexx3vqjhp43",
                          "name": "Jane Rosen",
                          "email": "jane@example.com",
                          "role": "account_admin",
                          "user": "user_01h2xcejqtf2nbrexx3vqjhp42",
                          "created_at": "2026-07-14T19:30:51Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/admin/users?limit=10&expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/admin/users`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/admin/users/{admin_user}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/AdminUserId"
        }
      ],
      "get": {
        "summary": "Get an admin portal user",
        "description": "Retrieve one of this account's admin portal users.\n\nReturns `404` when no such person administers this account — whether\nbecause the identifier is unknown or because they administer a different\naccount.\n\n**Expandable fields:** `user` — replaces the voice user's id with the\nfull User object.\n",
        "operationId": "getAdminUser",
        "tags": [
          "Admin Portal Users"
        ],
        "parameters": [
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `user`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "user"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Admin portal user details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminUser"
                },
                "examples": {
                  "default": {
                    "summary": "An administrator who also has phone service",
                    "value": {
                      "id": "admin_user_01h2xcejqtf2nbrexx3vqjhp43",
                      "name": "Jane Rosen",
                      "email": "jane@example.com",
                      "role": "account_admin",
                      "user": "user_01h2xcejqtf2nbrexx3vqjhp42",
                      "created_at": "2026-07-14T19:30:51Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/admin/users/admin_user_01h2xcejqtf2nbrexx3vqjhp43?expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/admin/users/{admin_user}`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/voicemails": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "get": {
        "summary": "List voicemails",
        "description": "List voicemails visible to the authenticated account, across both\nper-user mailboxes and shared voicemail boxes.\n\nResults are returned in reverse chronological order (newest first).\nUse `owner` (a user ID or shared voicemail box ID) to scope results\nto a single owner.\n",
        "operationId": "listVoicemails",
        "tags": [
          "Voicemails"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "owner",
            "in": "query",
            "description": "Filter to voicemails belonging to a specific owner (a user ID or a shared voicemail box ID).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "is_read",
            "in": "query",
            "description": "Filter by read status.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "from_date",
            "in": "query",
            "description": "Return voicemails created on or after this date (ISO 8601).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `call`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "call"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of voicemails",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Voicemail"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/voicemails?limit=10&owner=SOME_STRING_VALUE&is_read=SOME_BOOLEAN_VALUE&from_date=SOME_STRING_VALUE&expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/voicemails`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/voicemails/{voicemail_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/VoicemailId"
        }
      ],
      "get": {
        "summary": "Get a voicemail",
        "description": "Retrieve a specific voicemail by ID, including the `audio_url` for\nplayback. Voicemail IDs are globally unique, so no owner context is\nrequired in the URL.\n",
        "operationId": "getVoicemail",
        "tags": [
          "Voicemails"
        ],
        "parameters": [
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `call`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "call"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Voicemail details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Voicemail"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/VoicemailNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/voicemails/vm_01h2xcejqtf2nbrexx3vqjhp44?expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/voicemails/{voicemail_id}`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Update a voicemail",
        "description": "Update voicemail status (mark as read/unread).\n",
        "operationId": "updateVoicemail",
        "tags": [
          "Voicemails"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateVoicemailRequest"
              },
              "examples": {
                "mark_read": {
                  "summary": "Mark as read",
                  "value": {
                    "is_read": true
                  }
                },
                "mark_unread": {
                  "summary": "Mark as unread",
                  "value": {
                    "is_read": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Voicemail updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Voicemail"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/VoicemailNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/voicemails/vm_01h2xcejqtf2nbrexx3vqjhp44 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"is_read\":true}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/voicemails/{voicemail_id}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "delete": {
        "summary": "Delete a voicemail",
        "description": "Permanently delete a voicemail and its audio recording.\nThis operation is irreversible.\n",
        "operationId": "deleteVoicemail",
        "tags": [
          "Voicemails"
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/VoicemailDeleted"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/VoicemailNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/voicemails/vm_01h2xcejqtf2nbrexx3vqjhp44 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/voicemails/{voicemail_id}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/voicemails/{voicemail_id}/transcript": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/VoicemailId"
        }
      ],
      "get": {
        "summary": "Get a voicemail transcript",
        "description": "Retrieve the transcript for a specific voicemail.\n\n**Transcription Status:**\n- `pending`: The voicemail has been saved but transcription has not started\n- `processing`: Transcription is currently in progress\n- `completed`: Transcription is complete and text is available\n- `failed`: Transcription failed (text will be null)\n\nVoicemails are automatically transcribed after being saved.\n",
        "operationId": "getVoicemailTranscript",
        "tags": [
          "Voicemails"
        ],
        "responses": {
          "200": {
            "description": "Voicemail transcript",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VoicemailTranscript"
                },
                "examples": {
                  "completed": {
                    "summary": "Completed transcription",
                    "value": {
                      "voicemail": "vm_01h2xcejqtf2nbrexx3vqjhp45",
                      "status": "completed",
                      "text": "Hi, this is John Smith calling about my appointment tomorrow..."
                    }
                  },
                  "pending": {
                    "summary": "Pending transcription",
                    "value": {
                      "voicemail": "vm_01h2xcejqtf2nbrexx3vqjhp45",
                      "status": "pending",
                      "text": null
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/VoicemailNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/voicemails/vm_01h2xcejqtf2nbrexx3vqjhp44/transcript \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/voicemails/{voicemail_id}/transcript`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/voicemail_greetings/{owner}/{type}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "name": "owner",
          "in": "path",
          "required": true,
          "description": "ID of the mailbox owner — either a user or a shared voicemail box.",
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "type",
          "in": "path",
          "required": true,
          "description": "The greeting variant to operate on. Today only `unavailable` is\nsupported.\n",
          "schema": {
            "type": "string",
            "enum": [
              "unavailable"
            ]
          }
        }
      ],
      "post": {
        "summary": "Upload a voicemail greeting",
        "description": "Uploads (or replaces) a custom greeting for a user mailbox or a\nshared voicemail box.\n\nAccepts a multipart form with a `file` field containing the audio.\nThe audio is validated and transcoded server-side to the storage\nformat (mono µ-law 8 kHz WAV).\n\n- Maximum file size: 5 MB.\n- Maximum duration: 90 seconds.\n- Supported input formats: WAV (PCM s16 / µ-law / A-law), MP3, AAC, Ogg Vorbis, Opus.\n\nRe-uploading for the same `(owner, type)` overwrites the existing\ngreeting.\n",
        "operationId": "uploadVoicemailGreeting",
        "tags": [
          "Voicemails"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Audio file to upload."
                  }
                },
                "required": [
                  "file"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Greeting uploaded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VoicemailGreetingResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Owner not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "File size exceeds the 5 MB limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/voicemail_greetings/%7Bowner%7D/%7Btype%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: multipart/form-data' \\\n  --form file=string"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/voicemail_greetings/{owner}/{type}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "get": {
        "summary": "Get a voicemail greeting",
        "description": "Returns the current custom greeting for a mailbox owner, including a\nshort-lived signed URL for audio playback.\n",
        "operationId": "getVoicemailGreeting",
        "tags": [
          "Voicemails"
        ],
        "responses": {
          "200": {
            "description": "Greeting details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VoicemailGreetingResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No custom greeting is set for this (owner, type)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/voicemail_greetings/%7Bowner%7D/%7Btype%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/voicemail_greetings/{owner}/{type}`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "delete": {
        "summary": "Delete a voicemail greeting",
        "description": "Removes the custom greeting for a mailbox owner. The mailbox reverts\nto the system-default prompts.\n\nThis operation is idempotent — returns `204 No Content` whether or\nnot a greeting was previously set.\n",
        "operationId": "deleteVoicemailGreeting",
        "tags": [
          "Voicemails"
        ],
        "responses": {
          "204": {
            "description": "Greeting removed (or was already absent)"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/voicemail_greetings/%7Bowner%7D/%7Btype%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/voicemail_greetings/{owner}/{type}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/test_helpers/calls": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "post": {
        "summary": "Trigger a simulated call (test mode only)",
        "description": "Triggers a simulated call in test mode, for exercising the event-driven\nsurface (webhooks and SSE) without placing a real phone call. Primarily\nfor inbound (screen pop) and custom-scenario simulations that a dialed\nnumber cannot select.\n\nAvailable only with a test key (`sk_test_...`); a live key receives a\n`400` naming the mistake. Asynchronous: a `200` indicates the simulation\nwas started (its id + scenario are returned), not completed. See the\n\"Testing your integration\" guide.\n",
        "operationId": "createTestCall",
        "tags": [
          "Calls"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTestCallRequest"
              },
              "examples": {
                "inbound_screen_pop": {
                  "summary": "Inbound call for screen-pop testing",
                  "value": {
                    "user": "user_01h2xcejqtf2nbrexx3vqjhp42",
                    "from_number": "+15551234567"
                  }
                },
                "custom_voicemail": {
                  "summary": "Inbound call that lands in voicemail",
                  "value": {
                    "user": "user_01h2xcejqtf2nbrexx3vqjhp42",
                    "from_number": "+15551234567",
                    "from_name": "Sarah Johnson",
                    "scenario": {
                      "outcome": "voicemail",
                      "ring_seconds": 15,
                      "voicemail_seconds": 12
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Simulation started",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TestCallResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/test_helpers/calls \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"user\":\"user_01h2xcejqtf2nbrexx3vqjhp42\",\"direction\":\"inbound\",\"from_number\":\"+15551234567\",\"from_name\":\"string\",\"to_number\":\"string\",\"scenario\":{\"outcome\":\"answered\",\"ring_seconds\":0,\"talk_seconds\":0,\"recording\":true,\"voicemail_seconds\":0}}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/test_helpers/calls`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/test_helpers/events": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "post": {
        "summary": "Emit a canned webhook event (test mode only)",
        "description": "Emits a single webhook event of the requested type with a\nrepresentative sample payload, through the normal webhook delivery\npath. Complements the behavioral call simulation by covering events\nfrom standalone subsystems so you can exercise your handler for every\nproduction webhook.\n\nSupported types are the `fax.*` and `queue.*` webhook events plus\n`recording.failed` and `call.mobile_push_wakeup`. An unrecognized type\nreturns `400` with the current supported list. Available only with a\ntest key (`sk_test_...`); a live key receives a `400`.\n",
        "operationId": "createTestEvent",
        "tags": [
          "Webhook Endpoints"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "event": {
                    "type": "string",
                    "description": "Webhook event type to emit.",
                    "example": "queue.call.answered"
                  }
                },
                "required": [
                  "event"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Event emitted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TestEventResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/test_helpers/events \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"event\":\"queue.call.answered\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/test_helpers/events`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/calls": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "post": {
        "summary": "Initiate a call",
        "description": "Initiates an outbound call to a destination by first establishing a connection\nwith the specified user.\n\n**Call Flow:**\n1. The system rings all of the user's registered devices simultaneously\n2. When the user answers on any device, the system dials the destination\n3. Both legs are bridged together into a single call\n\nThe `dial_string` can be:\n- A phone number in E.164 format (e.g., `+15551234567`)\n- A local phone number (normalized based on account region)\n- An internal extension\n- An emergency number (e.g., `911`)\n\nThis is an asynchronous operation. A `202 Accepted` response indicates the call\nrequest was queued successfully, not that the call has completed or even started.\n",
        "operationId": "createCall",
        "tags": [
          "Calls"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCallRequest"
              },
              "examples": {
                "pstn": {
                  "summary": "Call a phone number",
                  "value": {
                    "user": "user_01h2xcejqtf2nbrexx3vqjhp42",
                    "dial_string": "+15551234567"
                  }
                },
                "local": {
                  "summary": "Call a local number",
                  "value": {
                    "user": "user_01h2xcejqtf2nbrexx3vqjhp42",
                    "dial_string": "5551234567"
                  }
                },
                "extension": {
                  "summary": "Call an extension",
                  "value": {
                    "user": "user_01h2xcejqtf2nbrexx3vqjhp42",
                    "dial_string": "1001"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Call initiated successfully (queued for processing)"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/UserNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/calls \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"user\":\"user_01h2xcejqtf2nbrexx3vqjhp42\",\"dial_string\":\"+15551234567\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.calls.create(/* body params */, { dialstackAccount: 'acct_...' });"
          }
        ]
      },
      "get": {
        "summary": "List call logs",
        "description": "List call history for an account with optional filtering.\nResults are returned in reverse chronological order (newest first).\n",
        "operationId": "listCallLogs",
        "tags": [
          "Calls"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "user_id",
            "in": "query",
            "description": "Filter by specific user",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "did",
            "in": "query",
            "description": "Filter by the phone number (DID) associated with the call, by its ID",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "description": "Filter by call direction",
            "schema": {
              "type": "string",
              "enum": [
                "inbound",
                "outbound",
                "internal"
              ]
            }
          },
          {
            "name": "from_number",
            "in": "query",
            "description": "Filter by caller's phone number (exact match)",
            "schema": {
              "type": "string",
              "maxLength": 20
            }
          },
          {
            "name": "to_number",
            "in": "query",
            "description": "Filter by the call's destination (exact match). Matches either the number as dialed (an E.164 phone number for inbound calls) or the routed destination reported in the call's `to_number` (an extension number for calls that terminate inside the account).",
            "schema": {
              "type": "string",
              "maxLength": 20
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by call status",
            "schema": {
              "type": "string",
              "enum": [
                "completed",
                "no-answer",
                "busy",
                "failed",
                "voicemail"
              ]
            }
          },
          {
            "name": "from_date",
            "in": "query",
            "description": "Return calls started on or after this date (ISO 8601)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to_date",
            "in": "query",
            "description": "Return calls started before this date (ISO 8601)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `did`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "did"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of call logs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CallLog"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                },
                "examples": {
                  "list": {
                    "summary": "Call log list response",
                    "value": {
                      "object": "list",
                      "url": "/v1/calls",
                      "next_page_url": null,
                      "previous_page_url": null,
                      "data": [
                        {
                          "id": "call_01h2xcejqtf2nbrexx3vqjhp45",
                          "user": "user_01h2xcejqtf2nbrexx3vqjhp42",
                          "endpoint": "ep_01h2xcejqtf2nbrexx3vqjhp43",
                          "did": "did_01h2xcejqtf2nbrexx3vqjhp46",
                          "direction": "inbound",
                          "from_number": "+14155551234",
                          "to_number": "1002",
                          "started_at": "2025-10-18T14:30:00Z",
                          "answered_at": "2025-10-18T14:30:05Z",
                          "connected_at": "2025-10-18T14:31:02Z",
                          "ended_at": "2025-10-18T14:35:30Z",
                          "duration_seconds": 325,
                          "status": "completed"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "An invalid filter or pagination cursor. A supplied `from_date` /\n`to_date` that is not an RFC3339 timestamp is rejected rather than\nignored, so a malformed value cannot silently widen the query.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/calls?limit=10&user_id=SOME_STRING_VALUE&did=SOME_STRING_VALUE&direction=SOME_STRING_VALUE&from_number=SOME_STRING_VALUE&to_number=SOME_STRING_VALUE&status=SOME_STRING_VALUE&from_date=SOME_STRING_VALUE&to_date=SOME_STRING_VALUE&expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/calls`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/calls/{call_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/CallId"
        }
      ],
      "get": {
        "summary": "Get call log details",
        "description": "Retrieve a specific call log by ID.\n",
        "operationId": "getCallLog",
        "tags": [
          "Calls"
        ],
        "parameters": [
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `did`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "did"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Call log details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CallLog"
                },
                "examples": {
                  "completed_call": {
                    "summary": "Completed inbound call",
                    "value": {
                      "id": "call_01h2xcejqtf2nbrexx3vqjhp45",
                      "user": "user_01h2xcejqtf2nbrexx3vqjhp42",
                      "endpoint": "ep_01h2xcejqtf2nbrexx3vqjhp43",
                      "did": "did_01h2xcejqtf2nbrexx3vqjhp46",
                      "direction": "inbound",
                      "from_number": "+14155551234",
                      "to_number": "1002",
                      "started_at": "2025-10-18T14:30:00Z",
                      "answered_at": "2025-10-18T14:30:05Z",
                      "connected_at": "2025-10-18T14:31:02Z",
                      "ended_at": "2025-10-18T14:35:30Z",
                      "duration_seconds": 325,
                      "status": "completed"
                    }
                  },
                  "missed_call": {
                    "summary": "Missed call (no answer)",
                    "value": {
                      "id": "call_01h2xcejqtf2nbrexx3vqjhp47",
                      "user": "user_01h2xcejqtf2nbrexx3vqjhp42",
                      "did": "did_01h2xcejqtf2nbrexx3vqjhp46",
                      "direction": "inbound",
                      "from_number": "+14155551234",
                      "to_number": "1002",
                      "started_at": "2025-10-18T15:00:00Z",
                      "ended_at": "2025-10-18T15:00:30Z",
                      "status": "no-answer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/CallNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/calls/call_01h2xcejqtf2nbrexx3vqjhp45?expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/calls/{call_id}`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Control an active call",
        "description": "Send actions to control an active call. This is the central API for all call\ncontrol operations such as attaching audio streams or transferring calls.\n\nActions are processed sequentially. Each action may block processing or allow\nit to continue based on its outcome (see action descriptions for details).\n\n**Replacing actions:** If the call is currently executing actions and you send\na new update, the previous action list is completely replaced. Processing of\nthe current action is interrupted immediately, and processing resumes with the\nfirst action in the new list.\n\n**Example - Attach AI voice and fallback to human:**\n```json\n{\n  \"actions\": [\n    {\"type\": \"attach\", \"url\": \"wss://ai.example.com/voice\"},\n    {\"type\": \"transfer\", \"target\": \"100\"}\n  ]\n}\n```\nIn this example, the AI handles the call via WebSocket. When the WebSocket\ndisconnects, the call transfers to extension 100.\n",
        "operationId": "updateCall",
        "tags": [
          "Calls"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCallRequest"
              },
              "examples": {
                "attach_ai": {
                  "summary": "Attach AI voice session",
                  "value": {
                    "actions": [
                      {
                        "type": "attach",
                        "url": "wss://ai.platform.example.com/voice"
                      }
                    ]
                  }
                },
                "transfer": {
                  "summary": "Transfer to extension",
                  "value": {
                    "actions": [
                      {
                        "type": "transfer",
                        "target": "100"
                      }
                    ]
                  }
                },
                "attach_then_transfer": {
                  "summary": "AI with human fallback",
                  "value": {
                    "actions": [
                      {
                        "type": "attach",
                        "url": "wss://ai.platform.example.com/voice"
                      },
                      {
                        "type": "transfer",
                        "target": "100"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Actions accepted for processing"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/CallNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/calls/call_01h2xcejqtf2nbrexx3vqjhp45 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"actions\":[{\"type\":\"attach\",\"url\":\"wss://ai.platform.example.com/voice\",\"metadata\":{\"agent_id\":\"user_01h2xcejqtf2nbrexx3vqjhp42\",\"queue\":\"support\"}}]}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/calls/{call_id}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/calls/{call_id}/transcript": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/CallId"
        }
      ],
      "get": {
        "summary": "Get call transcript",
        "description": "Retrieve the transcript for a specific call.\n\n**Transcription Status:**\n- `pending`: The call has been recorded but transcription has not started\n- `processing`: Transcription is currently in progress\n- `completed`: Transcription is complete and text is available\n- `failed`: Transcription failed (text will be null)\n\n**Note:** Returns 404 if the call exists but has no recording, or if the call\ndoes not exist. Not all calls have recordings (depends on account configuration).\n",
        "operationId": "getCallTranscript",
        "tags": [
          "Calls"
        ],
        "responses": {
          "200": {
            "description": "Call transcript",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Transcript"
                },
                "examples": {
                  "completed": {
                    "summary": "Completed transcription",
                    "value": {
                      "call_id": "call_01h2xcejqtf2nbrexx3vqjhp45",
                      "status": "completed",
                      "text": "Hello, this is Dr. Smith calling..."
                    }
                  },
                  "pending": {
                    "summary": "Pending transcription",
                    "value": {
                      "call_id": "call_01h2xcejqtf2nbrexx3vqjhp45",
                      "status": "pending",
                      "text": null
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/TranscriptNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/calls/call_01h2xcejqtf2nbrexx3vqjhp45/transcript \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/calls/{call_id}/transcript`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/calls/{call_id}/recording": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/CallId"
        }
      ],
      "get": {
        "summary": "Get call recording",
        "description": "Retrieve the recording for a specific call. Returns metadata and a signed download URL.\n\nThe download URL is valid for 10 minutes. After expiration, request a new URL by calling this endpoint again.\n\n**Note:** Returns 404 if the call exists but has no recording, or if the call\ndoes not exist. Not all calls have recordings (depends on account configuration).\n",
        "operationId": "getCallRecording",
        "tags": [
          "Calls"
        ],
        "responses": {
          "200": {
            "description": "Call recording",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Recording"
                },
                "examples": {
                  "recording": {
                    "summary": "Recording with metadata",
                    "value": {
                      "call_id": "call_01h2xcejqtf2nbrexx3vqjhp45",
                      "duration_seconds": 185,
                      "file_size_bytes": 2960000,
                      "download_url": "https://cdn.example.com/recordings/2026-03-05/call.wav?Expires=1709654400&Signature=abc123",
                      "expires_at": "2026-03-05T15:40:00Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/RecordingNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/calls/call_01h2xcejqtf2nbrexx3vqjhp45/recording \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/calls/{call_id}/recording`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/calls/{call_id}/recording/pause": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/CallId"
        }
      ],
      "post": {
        "summary": "Pause call recording",
        "description": "Pause recording on an active call — for example, while an agent collects\na customer's payment card number so the sensitive audio is never captured.\n\nRecording stays paused (the recording file continues with silence for the\npaused span) until you call the resume endpoint or the call ends. Both\nparties hear a short confirmation tone. Resume with\n`POST /v1/calls/{call_id}/recording/resume`.\n\nThe request is accepted asynchronously (`202`). Returns `404` if the call\nis not active for the selected account. If the active call has no recording\nin progress, the command is a no-op.\n",
        "operationId": "pauseCallRecording",
        "tags": [
          "Calls"
        ],
        "responses": {
          "202": {
            "description": "Pause command accepted"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/calls/call_01h2xcejqtf2nbrexx3vqjhp45/recording/pause \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/calls/{call_id}/recording/pause`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/calls/{call_id}/recording/resume": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/CallId"
        }
      ],
      "post": {
        "summary": "Resume call recording",
        "description": "Resume a recording previously paused with\n`POST /v1/calls/{call_id}/recording/pause`. Both parties hear a short\nconfirmation tone.\n\nThe request is accepted asynchronously (`202`). Returns `404` if the call\nis not active for the selected account. If the active call has no recording\nin progress, the command is a no-op.\n",
        "operationId": "resumeCallRecording",
        "tags": [
          "Calls"
        ],
        "responses": {
          "202": {
            "description": "Resume command accepted"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/calls/call_01h2xcejqtf2nbrexx3vqjhp45/recording/resume \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/calls/{call_id}/recording/resume`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/calls/{call_id}/listeners": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/CallId"
        }
      ],
      "post": {
        "summary": "Create a listener",
        "description": "Start streaming real-time audio from an active call to a WebSocket URL.\n\nDialStack opens an outbound WebSocket connection to the specified URL and\nstreams audio unidirectionally (DialStack to your server). The call is not\naffected — both parties remain unaware of the listener.\n\nUse the `channel` parameter to select which audio to receive:\n- `caller` — audio from the party that initiated the call\n- `callee` — audio from the party that received the call\n- `both` — both channels, delivered as separate tagged messages\n\nThe listener automatically stops when the call ends. You can also stop it\nexplicitly with `DELETE /v1/calls/{call_id}/listeners/{listener_id}`.\n\nReturns `409 Conflict` if the call is not in a state that supports listeners\n(e.g., still ringing or already ended). Retry after the call is answered.\n\nSee the [WebSocket API](/websocket-api) for the listener message protocol.\n",
        "operationId": "createListener",
        "tags": [
          "Calls"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateListenerRequest"
              },
              "examples": {
                "both_channels": {
                  "summary": "Listen to both sides of the call",
                  "value": {
                    "url": "wss://your-server.example.com/audio",
                    "channel": "both"
                  }
                },
                "caller_only": {
                  "summary": "Listen to caller audio only",
                  "value": {
                    "url": "wss://your-server.example.com/audio",
                    "channel": "caller"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Listener created and WebSocket connection initiated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Listener"
                },
                "examples": {
                  "listener": {
                    "value": {
                      "id": "lstn_01h2xcejqtf2nbrexx3vqjhp50",
                      "call_id": "call_01h2xcejqtf2nbrexx3vqjhp45",
                      "url": "wss://your-server.example.com/audio",
                      "channel": "both",
                      "created_at": "2026-04-02T14:30:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/CallNotFound"
          },
          "409": {
            "$ref": "#/components/responses/CallNotActive"
          },
          "422": {
            "description": "Request body failed field validation. Examples:\n- `url is required` — the field was omitted or empty\n- `url must be a secure WebSocket URL (wss://)` — insecure scheme rejected\n- `channel must be one of caller, callee, both` — unsupported channel value\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/calls/call_01h2xcejqtf2nbrexx3vqjhp45/listeners \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"url\":\"wss://your-server.example.com/audio\",\"channel\":\"both\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/calls/{call_id}/listeners`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "get": {
        "summary": "List listeners",
        "description": "List the listeners currently attached to a call. Listeners exist\nonly for the duration of the call — once the call ends they no\nlonger exist, and this endpoint returns an empty list. Call IDs\nthat don't belong to the caller's account return 404.\n",
        "operationId": "listListeners",
        "tags": [
          "Calls"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "List of active listeners",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Listener"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/CallNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/calls/call_01h2xcejqtf2nbrexx3vqjhp45/listeners?limit=10' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/calls/{call_id}/listeners`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/calls/{call_id}/listeners/{listener_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/CallId"
        },
        {
          "$ref": "#/components/parameters/ListenerId"
        }
      ],
      "get": {
        "summary": "Get listener",
        "description": "Retrieve a listener. Listeners exist only for the duration of\nthe call; once the call ends the listener no longer exists and\nthis endpoint returns 404.\n",
        "operationId": "getListener",
        "tags": [
          "Calls"
        ],
        "responses": {
          "200": {
            "description": "Listener details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Listener"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/ListenerNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/calls/call_01h2xcejqtf2nbrexx3vqjhp45/listeners/lstn_01h2xcejqtf2nbrexx3vqjhp50 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/calls/{call_id}/listeners/{listener_id}`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "delete": {
        "summary": "Stop a listener",
        "description": "Stop streaming audio and close the WebSocket connection for this listener.\nThe call is not affected. Listeners exist only for the duration of\nthe call, so once the call has ended this endpoint returns 404.\n",
        "operationId": "deleteListener",
        "tags": [
          "Calls"
        ],
        "responses": {
          "204": {
            "description": "Listener stopped"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/ListenerNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/calls/call_01h2xcejqtf2nbrexx3vqjhp45/listeners/lstn_01h2xcejqtf2nbrexx3vqjhp50 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/calls/{call_id}/listeners/{listener_id}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/phone-numbers": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "get": {
        "summary": "List phone numbers",
        "description": "List all phone numbers assigned to the account.\nResults are returned in reverse chronological order (newest first).\n",
        "operationId": "listPhoneNumbers",
        "tags": [
          "Phone Numbers"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/PhoneNumberStatus"
          }
        ],
        "responses": {
          "200": {
            "description": "List of phone numbers",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PhoneNumber"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                },
                "examples": {
                  "list": {
                    "summary": "Phone number list response",
                    "value": {
                      "object": "list",
                      "url": "/v1/phone-numbers",
                      "next_page_url": null,
                      "previous_page_url": null,
                      "data": [
                        {
                          "id": "did_01h2xcejqtf2nbrexx3vqjhp46",
                          "phone_number": "+14155551234",
                          "status": "active",
                          "outbound_enabled": true,
                          "routing_target": null,
                          "created_at": "2025-10-18T10:00:00Z",
                          "updated_at": "2025-10-18T10:00:00Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/phone-numbers?limit=10&status=active' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.phoneNumbers.list({ dialstackAccount: 'acct_...' });"
          }
        ]
      }
    },
    "/v1/phone-numbers/{phone_number_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/PhoneNumberId"
        }
      ],
      "get": {
        "summary": "Get a phone number",
        "description": "Retrieve a phone number by ID.\n",
        "operationId": "getPhoneNumber",
        "tags": [
          "Phone Numbers"
        ],
        "responses": {
          "200": {
            "description": "Phone number details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhoneNumber"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/PhoneNumberNotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/phone-numbers/did_01h2xcejqtf2nbrexx3vqjhp46 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/phone-numbers/{phone_number_id}`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Update a phone number",
        "description": "Update properties of a phone number.\n",
        "operationId": "updatePhoneNumber",
        "tags": [
          "Phone Numbers"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "outbound_enabled": {
                    "type": "boolean",
                    "description": "Whether this phone number can be used for outbound calling"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "active",
                      "inactive"
                    ],
                    "description": "Set to `inactive` to stop routing inbound calls to this number, or `active` to resume routing. Setting to `active` on a released number triggers re-acquisition from the carrier; this fails with 409 if the number is no longer available."
                  },
                  "expires_at": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date-time",
                    "description": "Set to `null` to convert a temporary number into a permanent one (cancels the scheduled release). Extending the expiry is not supported."
                  },
                  "directory_listing_name": {
                    "type": "string",
                    "description": "Business name for the directory listing"
                  },
                  "directory_listing_type": {
                    "type": "string",
                    "enum": [
                      "listed",
                      "non_listed",
                      "non_published",
                      "non_registered"
                    ],
                    "description": "How the number appears in directory services. Setting to a non-registered type removes any existing listing. Setting to listed, non_listed, or non_published submits a directory listing order."
                  },
                  "directory_listing_location": {
                    "type": "string",
                    "description": "ID of the location whose address to use for the listing. Required when directory_listing_type is not non_registered."
                  },
                  "caller_id_name": {
                    "type": "string",
                    "maxLength": 15,
                    "description": "Caller ID (CNAM) display name. Max 15 ASCII characters per the CNAM standard. Submits an asynchronous order to the upstream provider. The phone number must be in `active` status.",
                    "example": "ACME Corp"
                  },
                  "caller_id_prefix": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 32,
                    "description": "Prefix added to the inbound caller's display name (e.g. `[Acme] John Smith`, or `[Acme] +14084806024` when the caller's name is unknown), for calls answered on behalf of a specific brand or business. Applies both to the device that answers and to calls forwarded out to an external number. Affects only the caller ID presented for inbound calls and does not change call records. Unlike `caller_id_name`, this is stored directly with no upstream order. Send `null` to clear.",
                    "example": "[Acme]"
                  },
                  "caller_id_visibility": {
                    "type": "string",
                    "enum": [
                      "PUBLIC",
                      "PRIVATE"
                    ],
                    "default": "PUBLIC",
                    "description": "Whether the caller ID name is publicly visible"
                  },
                  "fax_enabled": {
                    "type": "boolean",
                    "description": "Set to `true` to make this number fax-only on inbound: incoming calls are received as faxes and the inbound routing target is bypassed (preserved, and resumes when set back to `false`)."
                  },
                  "config": {
                    "allOf": [
                      {
                        "$ref": "#/components/schemas/DIDConfig"
                      }
                    ],
                    "description": "Per-number configuration. Replaces the whole config blob, so send the full `fax_notifications` object when updating recipients or `delete_documents`. Pass `null` to clear it."
                  }
                }
              },
              "examples": {
                "disable_outbound": {
                  "summary": "Disable outbound calling",
                  "value": {
                    "outbound_enabled": false
                  }
                },
                "enable_fax": {
                  "summary": "Enable fax with notification recipients",
                  "value": {
                    "fax_enabled": true,
                    "config": {
                      "fax_notifications": {
                        "recipients": [
                          "fax@example.com"
                        ],
                        "delete_documents": false
                      }
                    }
                  }
                },
                "deactivate": {
                  "summary": "Deactivate a phone number",
                  "value": {
                    "status": "inactive"
                  }
                },
                "keep_temp_number": {
                  "summary": "Convert a temporary number to permanent",
                  "value": {
                    "expires_at": null
                  }
                },
                "recover_released_number": {
                  "summary": "Recover a previously released number",
                  "value": {
                    "status": "active"
                  }
                },
                "set_caller_id": {
                  "summary": "Set caller ID display name",
                  "value": {
                    "caller_id_name": "ACME Corp"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated phone number",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhoneNumber"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/PhoneNumberNotFound"
          },
          "409": {
            "description": "The update conflicts with the number's current state. Four distinct\nsituations share this status:\n\n- a caller ID change is already being processed for this number\n- the account already has a directory listing on another number\n  (only one is allowed per account)\n- the number is not in a recoverable state, or cannot be recovered\n- restoring a released number would take the account past its phone\n  number limit\n\nOnly the last carries a `code`, because it is the one a caller can\nresolve without help: raise `config.max_phone_numbers` on the\naccount and retry. The others are described by `error` alone.\n\n| `code` | Meaning |\n| --- | --- |\n| `phone_number_limit_exceeded` | The account is at its phone number limit, and restoring this number would exceed it. |\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "caller_id_in_progress": {
                    "summary": "A caller ID change is already being processed",
                    "value": {
                      "error": "A Caller ID change is already being processed for this number"
                    }
                  },
                  "directory_listing_exists": {
                    "summary": "The account already has a directory listing",
                    "value": {
                      "error": "Only one directory listing is allowed per account. Remove the existing listing before adding a new one."
                    }
                  },
                  "phone_number_limit_exceeded": {
                    "summary": "Restoring the number would exceed the account's cap",
                    "value": {
                      "error": "phone number limit exceeded: account has 25 numbers (max 25), cannot add 1 more",
                      "code": "phone_number_limit_exceeded"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "The upstream provider rejected the caller ID or directory listing update",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          },
          "502": {
            "description": "Upstream provider error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Caller ID service is not configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/phone-numbers/did_01h2xcejqtf2nbrexx3vqjhp46 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"outbound_enabled\":true,\"status\":\"active\",\"expires_at\":\"2019-08-24T14:15:22Z\",\"directory_listing_name\":\"string\",\"directory_listing_type\":\"listed\",\"directory_listing_location\":\"string\",\"caller_id_name\":\"ACME Corp\",\"caller_id_prefix\":\"[Acme]\",\"caller_id_visibility\":\"PUBLIC\",\"fax_enabled\":true,\"config\":{\"fax_notifications\":{\"recipients\":[\"fax@example.com\"],\"delete_documents\":false,\"attach_pdf\":true}}}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/phone-numbers/{phone_number_id}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/available-phone-numbers": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "get": {
        "summary": "Search available phone numbers",
        "description": "Search for phone numbers available for purchase.\nAt least one search filter is required: `area_code`, `state`, `zip`, `npa_nxx`, or `city` combined with `state`.\nFilters can be combined to narrow results.\n\nA well-formed ZIP code may still be rejected if it is unknown or\nPO Box–only (for example `85001` or `22313`); this returns a `400`\nwith an actionable error message rather than an empty result list.\n",
        "operationId": "searchAvailablePhoneNumbers",
        "tags": [
          "Phone Numbers"
        ],
        "parameters": [
          {
            "name": "area_code",
            "in": "query",
            "required": false,
            "description": "Three-digit area code to search",
            "schema": {
              "type": "string",
              "pattern": "^\\d{3}$",
              "example": "919"
            }
          },
          {
            "name": "city",
            "in": "query",
            "required": false,
            "description": "City name (requires `state`)",
            "schema": {
              "type": "string",
              "example": "Raleigh"
            }
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "description": "Two-letter state abbreviation (can be used alone or with `city`)",
            "schema": {
              "type": "string",
              "pattern": "^[A-Z]{2}$",
              "example": "NC"
            }
          },
          {
            "name": "zip",
            "in": "query",
            "required": false,
            "description": "Five-digit US ZIP code",
            "schema": {
              "type": "string",
              "pattern": "^\\d{5}$",
              "example": "27601"
            }
          },
          {
            "name": "npa_nxx",
            "in": "query",
            "required": false,
            "description": "Six-digit NPA-NXX prefix (area code + exchange)",
            "schema": {
              "type": "string",
              "pattern": "^\\d{6}$",
              "example": "919555"
            }
          },
          {
            "name": "quantity",
            "in": "query",
            "required": false,
            "description": "Number of results to return (1-100, default 10)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of available phone numbers",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AvailablePhoneNumber"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "examples": {
                  "results": {
                    "summary": "Available numbers found",
                    "value": {
                      "data": [
                        {
                          "phone_number": "+19195551234",
                          "city": "RALEIGH",
                          "state": "NC",
                          "rate_center": "RALEIGH",
                          "lata": "422"
                        },
                        {
                          "phone_number": "+19195555678",
                          "city": "RALEIGH",
                          "state": "NC",
                          "rate_center": "RALEIGH",
                          "lata": "422"
                        }
                      ]
                    }
                  },
                  "empty": {
                    "summary": "No numbers available",
                    "value": {
                      "data": []
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/available-phone-numbers?area_code=919&city=Raleigh&state=NC&zip=27601&npa_nxx=919555&quantity=SOME_INTEGER_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/available-phone-numbers`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/phone-number-orders": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "post": {
        "summary": "Order new phone numbers",
        "description": "Order one or more new phone numbers. Numbers must have been found via the\nsearch endpoint (`GET /v1/available-phone-numbers`). This endpoint is for\nacquiring new numbers only — it does not support porting existing numbers\nfrom another provider.\n\nThe order is created in `pending` status and typically completes within\nseconds. Poll the order via `GET /v1/phone-number-orders/{order_id}` or\nconfigure a webhook to be notified when it reaches a terminal status\n(`complete`, `partial`, or `failed`).\n",
        "operationId": "createNumberOrder",
        "tags": [
          "Phone Numbers"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateNumberOrderRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Order two numbers",
                  "value": {
                    "phone_numbers": [
                      "+19195551234",
                      "+19195555678"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Order created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NumberOrder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "The order cannot be placed for the numbers requested.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhoneNumberOrderConflictResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/phone-number-orders \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"phone_numbers\":[\"+19195551234\",\"+19195555678\"],\"partial_allowed\":false}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/phone-number-orders`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "get": {
        "summary": "List phone number orders",
        "description": "Returns a paginated list of phone number orders for the account.\nIncludes both purchase and disconnect orders. Results are returned\nin reverse chronological order (newest first).\n",
        "operationId": "listNumberOrders",
        "tags": [
          "Phone Numbers"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/NumberOrderStatus"
          },
          {
            "$ref": "#/components/parameters/NumberOrderType"
          }
        ],
        "responses": {
          "200": {
            "description": "List of phone number orders",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/NumberOrder"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/phone-number-orders?limit=10&status=SOME_STRING_VALUE&order_type=SOME_STRING_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/phone-number-orders`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/phone-number-orders/{order_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/OrderId"
        }
      ],
      "get": {
        "summary": "Get a phone number order",
        "description": "Retrieves a phone number order by ID. If the order is still pending,\nthe status is refreshed from the provider before returning.\n",
        "operationId": "getNumberOrder",
        "tags": [
          "Phone Numbers"
        ],
        "responses": {
          "200": {
            "description": "Order details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NumberOrder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NumberOrderNotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/phone-number-orders/nord_01h2xcejqtf2nbrexx3vqjhp47 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/phone-number-orders/{order_id}`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/phone-numbers/{phone_number_id}/disconnect": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/PhoneNumberId"
        }
      ],
      "post": {
        "summary": "Disconnect a phone number",
        "description": "Release a phone number back to the provider. Creates a disconnect order\nthat transitions the phone number to `released` status on completion.\n",
        "operationId": "disconnectPhoneNumber",
        "tags": [
          "Phone Numbers"
        ],
        "responses": {
          "201": {
            "description": "Disconnect order created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NumberOrder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/PhoneNumberNotFound"
          },
          "409": {
            "description": "The number is still within its 30-day minimum hold and cannot be\ndisconnected yet. This conflict carries no `code`; read `error`.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "phone number cannot be disconnected within 30 days of acquisition"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/phone-numbers/did_01h2xcejqtf2nbrexx3vqjhp46/disconnect \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/phone-numbers/{phone_number_id}/disconnect`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/phone-numbers/{phone_number_id}/reassign": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/PhoneNumberId"
        }
      ],
      "post": {
        "summary": "Reassign a phone number",
        "description": "Move a phone number to a different account.\n\nOn reassignment, the routing target is cleared and outbound calling is disabled.\nThe phone number must be in `active` or `inactive` status.\n",
        "operationId": "reassignPhoneNumber",
        "tags": [
          "Phone Numbers"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "target_account": {
                    "type": "string",
                    "description": "ID of the account to reassign the phone number to"
                  }
                },
                "required": [
                  "target_account"
                ]
              },
              "examples": {
                "reassign": {
                  "summary": "Reassign to another account",
                  "value": {
                    "target_account": "acct_01h2xcejqtf2nbrexx3vqjhp47"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Reassigned phone number",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhoneNumber"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/PhoneNumberNotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/phone-numbers/did_01h2xcejqtf2nbrexx3vqjhp46/reassign \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"target_account\":\"string\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/phone-numbers/{phone_number_id}/reassign`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/phone-numbers/{phone_number_id}/route": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/PhoneNumberId"
        }
      ],
      "post": {
        "summary": "Update inbound routing",
        "description": "Set how inbound calls to a phone number are handled.\n\n- To route calls to a [routing target](#section/Routing-Targets), send\n  the target's ID in `routing_target`. Send `null` to clear it.\n- To deliberately stop inbound calls (no ring, no message), send\n  `inbound_routing: \"drop\"`. `routing_target` must be null or omitted;\n  sending a target alongside `drop` is rejected. Dropping is rejected on\n  a fax-enabled number (fax takes precedence) — disable fax first.\n\nOmitting `routing_target` in `default` mode returns the current phone\nnumber state unchanged.\n",
        "operationId": "updatePhoneNumberRouting",
        "tags": [
          "Phone Numbers"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "routing_target": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "ID of the target to route inbound calls to; null clears it. To deliberately stop inbound calls, use inbound_routing \"drop\" rather than clearing. Omit to leave routing unchanged."
                  },
                  "inbound_routing": {
                    "type": "string",
                    "enum": [
                      "default",
                      "drop"
                    ],
                    "description": "`default` follows `routing_target`; `drop` drops inbound calls. Defaults to `default` when omitted."
                  }
                }
              },
              "examples": {
                "set_target": {
                  "summary": "Route calls to a target",
                  "value": {
                    "routing_target": "user_01h2xcejqtf2nbrexx3vqjhp48"
                  }
                },
                "clear_target": {
                  "summary": "Clear the routing target",
                  "value": {
                    "routing_target": null
                  }
                },
                "drop": {
                  "summary": "Drop inbound calls",
                  "value": {
                    "inbound_routing": "drop"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated phone number",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhoneNumber"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/PhoneNumberNotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/phone-numbers/did_01h2xcejqtf2nbrexx3vqjhp46/route \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"routing_target\":\"string\",\"inbound_routing\":\"default\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/phone-numbers/{phone_number_id}/route`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/phone-numbers/{phone_number_id}/sms-port-out": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/PhoneNumberId"
        }
      ],
      "get": {
        "summary": "Get the SMS port-out window",
        "description": "Returns the number's SMS port-out window. While the window is open\n(`expires_at` is a future timestamp), an inbound SMS port-out (messaging\ntransfer) request for this number is authorized automatically; otherwise\nit is denied. `expires_at` is `null` when the window is locked.\n",
        "operationId": "getSmsPortOut",
        "tags": [
          "Phone Numbers"
        ],
        "responses": {
          "200": {
            "description": "The SMS port-out window",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SmsPortOutWindow"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/PhoneNumberNotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/phone-numbers/did_01h2xcejqtf2nbrexx3vqjhp46/sms-port-out \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/phone-numbers/{phone_number_id}/sms-port-out`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Open or lock the SMS port-out window",
        "description": "Set the number's SMS port-out window. Send a future `expires_at`\ntimestamp to open the window until that instant, or `null` to lock it.\n`expires_at` is required (there is no default); a timestamp in the past,\nor more than 365 days in the future, is rejected.\n",
        "operationId": "updateSmsPortOut",
        "tags": [
          "Phone Numbers"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SmsPortOutWindow"
              },
              "examples": {
                "open": {
                  "summary": "Open the window until a future instant",
                  "value": {
                    "expires_at": "2026-06-29T09:30:00Z"
                  }
                },
                "lock": {
                  "summary": "Lock the window",
                  "value": {
                    "expires_at": null
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated SMS port-out window",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SmsPortOutWindow"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/PhoneNumberNotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/phone-numbers/did_01h2xcejqtf2nbrexx3vqjhp46/sms-port-out \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"expires_at\":\"2019-08-24T14:15:22Z\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/phone-numbers/{phone_number_id}/sms-port-out`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/port-in-eligibility": {
      "post": {
        "summary": "Check port-in eligibility",
        "description": "Check whether phone numbers are eligible for porting to DialStack. Returns\ncarrier information for portable numbers and rate center details for\nnon-portable numbers.\n\nThis is a pre-purchase check and does not require an account context.\n",
        "operationId": "checkPortInEligibility",
        "tags": [
          "Number Porting"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PortInEligibilityRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Check two numbers",
                  "value": {
                    "phone_numbers": [
                      "+12025551234",
                      "+14155559876"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Eligibility check result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortInEligibilityResult"
                },
                "examples": {
                  "success": {
                    "summary": "Mixed eligibility result",
                    "value": {
                      "portable_numbers": [
                        {
                          "phone_number": "+14155559876",
                          "losing_carrier_name": "T-Mobile US-SVR-10X/2",
                          "losing_carrier_spid": "6529",
                          "is_wireless": true,
                          "account_number_required": true
                        }
                      ],
                      "non_portable_numbers": [
                        {
                          "phone_number": "+12025551234",
                          "rate_center": "WASHINGT DC",
                          "city": "Washington",
                          "state": "DC"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/port-in-eligibility \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'content-type: application/json' \\\n  -d '{\"phone_numbers\":[\"+12025551234\",\"+14155559876\"]}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/port-in-eligibility`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/port-orders": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "post": {
        "summary": "Create a draft port order",
        "description": "Create a new port order in `draft` status. After creating the draft, approve\nthe order with an electronic signature, then submit it to begin the porting process.\n\nPhone numbers are validated and normalized to E.164 format. Toll-free numbers\nare not supported.\n",
        "operationId": "createPortOrder",
        "tags": [
          "Number Porting"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePortOrderRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Port a single number",
                  "value": {
                    "phone_numbers": [
                      "+12025551234"
                    ],
                    "subscriber": {
                      "btn": "+12025551234",
                      "business_name": "Doe Enterprises",
                      "approver_name": "John Doe",
                      "address": {
                        "house_number": "123",
                        "street_name": "Main St",
                        "city": "Anytown",
                        "state": "VA",
                        "zip": "22030"
                      }
                    },
                    "requested_foc_date": "2026-03-01"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Draft port order created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortOrder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "The port order cannot be created for the numbers requested.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhoneNumberOrderConflictResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/port-orders \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"phone_numbers\":[\"+12025551234\"],\"subscriber\":{\"btn\":\"+12025551234\",\"business_name\":\"Doe Enterprises\",\"approver_name\":\"John Doe\",\"account_number\":\"123456789\",\"pin\":\"1234\",\"address\":{\"house_number\":\"123\",\"street_name\":\"Main St\",\"line2\":\"Suite 200\",\"city\":\"Anytown\",\"state\":\"VA\",\"zip\":\"22030\"}},\"requested_foc_date\":\"2026-03-01\",\"requested_foc_time\":\"10:00\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/port-orders`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "get": {
        "summary": "List port orders",
        "description": "Returns a paginated list of port orders for the account.\nResults are returned in reverse chronological order (newest first).\nOptionally filter by status.\n",
        "operationId": "listPortOrders",
        "tags": [
          "Number Porting"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/PortOrderStatus"
          }
        ],
        "responses": {
          "200": {
            "description": "List of port orders",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PortOrder"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/port-orders?limit=10&status=SOME_STRING_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/port-orders`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/port-orders/{order_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/PortOrderId"
        }
      ],
      "get": {
        "summary": "Get a port order",
        "description": "Retrieve a port order by ID. If the order is in a non-terminal status\n(`submitted`, `exception`, or `foc`), the status is automatically refreshed\nfrom the carrier before returning.\n",
        "operationId": "getPortOrder",
        "tags": [
          "Number Porting"
        ],
        "responses": {
          "200": {
            "description": "Port order details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortOrder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/PortOrderNotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/port-orders/por_01h2xcejqtf2nbrexx3vqjhp53 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/port-orders/{order_id}`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Update a port order",
        "description": "Update a port order that is in `approved` or `exception` status. Use this to correct\ninformation that caused a rejection, then resubmit. All fields are optional —\nonly provided fields are updated. Updating an approved order clears the approval\nand reverts the status to `draft`.\n",
        "operationId": "updatePortOrder",
        "tags": [
          "Number Porting"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePortOrderRequest"
              },
              "examples": {
                "fix_address": {
                  "summary": "Fix service address after rejection",
                  "value": {
                    "subscriber": {
                      "btn": "+12025551234",
                      "business_name": "Doe Enterprises",
                      "approver_name": "John Doe",
                      "address": {
                        "house_number": "456",
                        "street_name": "Oak Ave",
                        "city": "Anytown",
                        "state": "VA",
                        "zip": "22030"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Port order updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortOrder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/PortOrderNotFound"
          },
          "409": {
            "description": "The port order cannot be edited as requested.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortOrderUpdateConflictResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/port-orders/por_01h2xcejqtf2nbrexx3vqjhp53 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"phone_numbers\":[\"+12025551234\"],\"subscriber\":{\"btn\":\"+12025551234\",\"business_name\":\"Doe Enterprises\",\"approver_name\":\"John Doe\",\"account_number\":\"123456789\",\"pin\":\"1234\",\"address\":{\"house_number\":\"123\",\"street_name\":\"Main St\",\"line2\":\"Suite 200\",\"city\":\"Anytown\",\"state\":\"VA\",\"zip\":\"22030\"}},\"requested_foc_date\":\"2026-03-15\",\"requested_foc_time\":\"10:00\",\"resubmit\":false}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/port-orders/{order_id}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/port-orders/{order_id}/submit": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/PortOrderId"
        }
      ],
      "post": {
        "summary": "Submit a port order",
        "description": "Submit an approved port order for processing. The order must first be\n[approved](#tag/Number-Porting/operation/approvePortOrder) by the customer.\n\nOn success, the order status transitions from `approved` to `submitted`.\nThe necessary authorization documents are generated and forwarded to the\ncarrier automatically.\n",
        "operationId": "submitPortOrder",
        "tags": [
          "Number Porting"
        ],
        "responses": {
          "200": {
            "description": "Port order submitted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortOrder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/PortOrderNotFound"
          },
          "409": {
            "description": "Order is not in approved status. Carries `code: port_order_invalid_state`, so the\nstatus can be branched on without reading `error`.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortOrderStateConflictResponse"
                },
                "example": {
                  "error": "port order is in \"draft\" status, cannot submit",
                  "code": "port_order_invalid_state"
                }
              }
            }
          },
          "422": {
            "description": "Approval required — the order must be approved before submission",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/port-orders/por_01h2xcejqtf2nbrexx3vqjhp53/submit \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/port-orders/{order_id}/submit`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/port-orders/{order_id}/cancel": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/PortOrderId"
        }
      ],
      "post": {
        "summary": "Cancel a port order",
        "description": "Cancel a port order. Draft and approved orders are cancelled locally.\nSubmitted orders are also cancelled with the carrier.\n\nCannot cancel orders in terminal status (`complete` or `cancelled`).\n",
        "operationId": "cancelPortOrder",
        "tags": [
          "Number Porting"
        ],
        "responses": {
          "200": {
            "description": "Port order cancelled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortOrder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/PortOrderNotFound"
          },
          "409": {
            "description": "Order is in a terminal status and cannot be cancelled. Carries `code: port_order_invalid_state`, so the\nstatus can be branched on without reading `error`.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortOrderStateConflictResponse"
                },
                "example": {
                  "error": "port order is in \"complete\" status, cannot cancel",
                  "code": "port_order_invalid_state"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/port-orders/por_01h2xcejqtf2nbrexx3vqjhp53/cancel \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/port-orders/{order_id}/cancel`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/port-orders/{order_id}/approve": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/PortOrderId"
        }
      ],
      "post": {
        "summary": "Approve a port order",
        "description": "Have the customer approve a port order by providing their electronic signature\nand IP address. This authorizes the number transfer and allows the order to be submitted.\n\nThe order must be in `draft` status and must have subscriber details.\n\nOn success, the order status transitions from `draft` to `approved`. If the order\ndetails are updated after approval, the approval is cleared and the status reverts\nto `draft` — the customer must approve again.\n",
        "operationId": "approvePortOrder",
        "tags": [
          "Number Porting"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApprovePortOrderRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Port order approved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortOrder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/PortOrderNotFound"
          },
          "409": {
            "description": "Order is not in draft status. Carries `code: port_order_invalid_state`, so the\nstatus can be branched on without reading `error`.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortOrderStateConflictResponse"
                },
                "example": {
                  "error": "port order is in \"submitted\" status, cannot approve",
                  "code": "port_order_invalid_state"
                }
              }
            }
          },
          "422": {
            "description": "Subscriber details are missing from the port order",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/port-orders/por_01h2xcejqtf2nbrexx3vqjhp53/approve \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"signature\":\"Jane Smith\",\"ip\":\"203.0.113.42\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/port-orders/{order_id}/approve`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/port-orders/{order_id}/csr": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/PortOrderId"
        }
      ],
      "post": {
        "summary": "Upload CSR document",
        "description": "Upload an optional Customer Service Record (CSR) document for a port order.\nA CSR can help resolve porting issues by providing carrier account details.\n\nAccepted formats: PDF, PNG, JPG, TIFF. Maximum file size: 3 MB.\n",
        "operationId": "uploadPortOrderCSR",
        "tags": [
          "Number Porting"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "CSR document file"
                  }
                },
                "required": [
                  "file"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "CSR uploaded successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "csr uploaded successfully"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/PortOrderNotFound"
          },
          "409": {
            "description": "The order's current status does not accept a document upload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortOrderStateConflictResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/port-orders/por_01h2xcejqtf2nbrexx3vqjhp53/csr \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: multipart/form-data' \\\n  --form file=string"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/port-orders/{order_id}/csr`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "get": {
        "summary": "Download CSR document",
        "description": "Download the Customer Service Record (CSR) document for a port order.\n",
        "operationId": "downloadPortOrderCSR",
        "tags": [
          "Number Porting"
        ],
        "responses": {
          "200": {
            "description": "CSR document file",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/jpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/tiff": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/DocumentNotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/port-orders/por_01h2xcejqtf2nbrexx3vqjhp53/csr \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/port-orders/{order_id}/csr`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/port-orders/{order_id}/bill-copy": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/PortOrderId"
        }
      ],
      "post": {
        "summary": "Upload bill copy document",
        "description": "Upload an optional bill copy document for a port order.\nA bill copy can help resolve porting issues by providing carrier account details.\n\nAccepted formats: PDF, PNG, JPG, TIFF. Maximum file size: 3 MB.\n",
        "operationId": "uploadPortOrderBillCopy",
        "tags": [
          "Number Porting"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Bill copy document file"
                  }
                },
                "required": [
                  "file"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Bill copy uploaded successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "bill_copy uploaded successfully"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/PortOrderNotFound"
          },
          "409": {
            "description": "The order's current status does not accept a document upload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortOrderStateConflictResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/port-orders/por_01h2xcejqtf2nbrexx3vqjhp53/bill-copy \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: multipart/form-data' \\\n  --form file=string"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/port-orders/{order_id}/bill-copy`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "get": {
        "summary": "Download bill copy document",
        "description": "Download the bill copy document for a port order.\n",
        "operationId": "downloadPortOrderBillCopy",
        "tags": [
          "Number Porting"
        ],
        "responses": {
          "200": {
            "description": "Bill copy document file",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/jpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/tiff": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/DocumentNotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/port-orders/por_01h2xcejqtf2nbrexx3vqjhp53/bill-copy \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/port-orders/{order_id}/bill-copy`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/port-orders/{order_id}/events": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/PortOrderId"
        }
      ],
      "get": {
        "summary": "List port order events",
        "description": "Returns the audit trail of status changes for a port order,\nin reverse chronological order.\n",
        "operationId": "listPortOrderEvents",
        "tags": [
          "Number Porting"
        ],
        "responses": {
          "200": {
            "description": "List of port order events",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PortOrderEvent"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/PortOrderNotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/port-orders/por_01h2xcejqtf2nbrexx3vqjhp53/events \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/port-orders/{order_id}/events`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/ai-agents": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "post": {
        "summary": "Create an AI agent",
        "description": "Create a new AI agent within the account. This automatically provisions\na managed voice app and extension for call routing.\n",
        "operationId": "createAIAgent",
        "tags": [
          "AI Agents"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAIAgentRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Create a receptionist agent",
                  "value": {
                    "name": "Front Desk Receptionist",
                    "extension_number": "200",
                    "instructions": "You are the receptionist for Jones Family Dental.",
                    "faq_responses": [
                      {
                        "question": "What are your hours?",
                        "answer": "Monday through Friday, 9 AM to 5 PM."
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "AI agent created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AIAgent"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "Extension number already in use",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/ai-agents \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"name\":\"Front Desk Receptionist\",\"extension_number\":\"200\",\"persona_name\":\"Tony\",\"greeting_name\":\"Jones Family Dental\",\"instructions\":\"You are the receptionist for Jones Family Dental.\",\"faq_responses\":[{\"question\":\"What are your business hours?\",\"answer\":\"We are open Monday through Friday, 9 AM to 5 PM.\"}],\"scheduling\":{\"webhook_url\":\"http://example.com\"}}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/ai-agents`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "get": {
        "summary": "List AI agents",
        "description": "List all AI agents for the account.\nResults are returned in reverse chronological order (newest first).\n",
        "operationId": "listAIAgents",
        "tags": [
          "AI Agents"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `extensions`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "extensions"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of AI agents",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AIAgent"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/ai-agents?limit=10&expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/ai-agents`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/ai-agents/{ai_agent_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/AIAgentId"
        }
      ],
      "get": {
        "summary": "Get AI agent details",
        "description": "Retrieve a specific AI agent by ID.\n",
        "operationId": "getAIAgent",
        "tags": [
          "AI Agents"
        ],
        "parameters": [
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `extensions`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "extensions"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "AI agent details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AIAgent"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/AIAgentNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/ai-agents/aia_01h2xcejqtf2nbrexx3vqjhp60?expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/ai-agents/{ai_agent_id}`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Update AI agent",
        "description": "Update AI agent details (name, instructions, or FAQ responses).\n",
        "operationId": "updateAIAgent",
        "tags": [
          "AI Agents"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAIAgentRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "AI agent updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AIAgent"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/AIAgentNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/ai-agents/aia_01h2xcejqtf2nbrexx3vqjhp60 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"name\":\"Updated Receptionist\",\"persona_name\":\"Tony\",\"greeting_name\":\"Jones Family Dental\",\"instructions\":\"string\",\"faq_responses\":[{\"question\":\"What are your business hours?\",\"answer\":\"We are open Monday through Friday, 9 AM to 5 PM.\"}],\"scheduling\":{\"webhook_url\":\"http://example.com\"}}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/ai-agents/{ai_agent_id}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "delete": {
        "summary": "Delete AI agent",
        "description": "Delete an AI agent and its managed voice app and extension.\nThis operation is irreversible.\n",
        "operationId": "deleteAIAgent",
        "tags": [
          "AI Agents"
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/AIAgentDeleted"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/AIAgentNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/ai-agents/aia_01h2xcejqtf2nbrexx3vqjhp60 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/ai-agents/{ai_agent_id}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/voice-apps": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "post": {
        "summary": "Create a voice app",
        "description": "Create a new voice app within the account. Voice apps handle calls via HTTP\nwebhook notification and optional WebSocket audio streaming.\n",
        "operationId": "createVoiceApp",
        "tags": [
          "Voice Apps"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateVoiceAppRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Create AI receptionist",
                  "value": {
                    "name": "AI Receptionist",
                    "url": "https://ai.platform.example.com/calls"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Voice app created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VoiceApp"
                },
                "examples": {
                  "success": {
                    "summary": "Successful voice app creation",
                    "value": {
                      "id": "va_01h2xcejqtf2nbrexx3vqjhp49",
                      "name": "AI Receptionist",
                      "url": "https://ai.platform.example.com/calls",
                      "status": "active",
                      "secret": "whsec_abc123def456...",
                      "created_at": "2025-10-18T10:00:00Z",
                      "updated_at": "2025-10-18T10:00:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/voice-apps \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"name\":\"Spineline\",\"url\":\"https://ai.platform.example.com/calls\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.voiceApps.create(/* body params */, { dialstackAccount: 'acct_...' });"
          }
        ]
      },
      "get": {
        "summary": "List voice apps",
        "description": "List all voice apps for the account.\nResults are returned in reverse chronological order (newest first).\n",
        "operationId": "listVoiceApps",
        "tags": [
          "Voice Apps"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `extensions`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "extensions"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of voice apps",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/VoiceApp"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                },
                "examples": {
                  "list": {
                    "summary": "Voice app list response",
                    "value": {
                      "object": "list",
                      "url": "/v1/voice-apps",
                      "next_page_url": null,
                      "previous_page_url": null,
                      "data": [
                        {
                          "id": "va_01h2xcejqtf2nbrexx3vqjhp49",
                          "name": "AI Receptionist",
                          "url": "https://ai.platform.example.com/calls",
                          "status": "active",
                          "secret": "whsec_abc123def456...",
                          "created_at": "2025-10-18T10:00:00Z",
                          "updated_at": "2025-10-18T10:00:00Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/voice-apps?limit=10&expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.voiceApps.list({ dialstackAccount: 'acct_...' });"
          }
        ]
      }
    },
    "/v1/voice-apps/{voice_app_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/VoiceAppId"
        }
      ],
      "get": {
        "summary": "Get voice app details",
        "description": "Retrieve a specific voice app by ID.\n",
        "operationId": "getVoiceApp",
        "tags": [
          "Voice Apps"
        ],
        "parameters": [
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `extensions`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "extensions"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Voice app details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VoiceApp"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/VoiceAppNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/voice-apps/va_01h2xcejqtf2nbrexx3vqjhp49?expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.voiceApps.retrieve('voice_app_...', { dialstackAccount: 'acct_...' });"
          }
        ]
      },
      "post": {
        "summary": "Update voice app",
        "description": "Update voice app details (name, URL, or status).\n",
        "operationId": "updateVoiceApp",
        "tags": [
          "Voice Apps"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateVoiceAppRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Voice app updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VoiceApp"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/VoiceAppNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/voice-apps/va_01h2xcejqtf2nbrexx3vqjhp49 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"name\":\"Spineline\",\"url\":\"https://ai.platform.example.com/calls\",\"status\":\"active\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.voiceApps.update('voice_app_...', /* body params */, { dialstackAccount: 'acct_...' });"
          }
        ]
      },
      "delete": {
        "summary": "Delete voice app",
        "description": "Delete a voice app. Active calls to this voice app will be terminated.\nThis operation is irreversible.\n",
        "operationId": "deleteVoiceApp",
        "tags": [
          "Voice Apps"
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/VoiceAppDeleted"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/VoiceAppNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/voice-apps/va_01h2xcejqtf2nbrexx3vqjhp49 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.voiceApps.del('voice_app_...', { dialstackAccount: 'acct_...' });"
          }
        ]
      }
    },
    "/v1/voice-apps/{voice_app_id}/rotate_secret": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/VoiceAppId"
        }
      ],
      "post": {
        "summary": "Rotate webhook secret",
        "description": "Generate a new webhook signing secret for the voice app.\nThe old secret is immediately invalidated.\n",
        "operationId": "rotateVoiceAppSecret",
        "tags": [
          "Voice Apps"
        ],
        "responses": {
          "200": {
            "description": "Secret rotated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VoiceApp"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/VoiceAppNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/voice-apps/va_01h2xcejqtf2nbrexx3vqjhp49/rotate_secret \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/voice-apps/{voice_app_id}/rotate_secret`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/events": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "get": {
        "summary": "Stream real-time events",
        "description": "Establish a Server-Sent Events (SSE) connection to receive real-time notifications\nabout account activity such as incoming calls.\n\n**Connection Behavior:**\n- On successful connection, a `connected` event is sent immediately\n- Events are streamed in real-time as they occur\n- The connection stays open indefinitely until the client disconnects\n- Clients should implement automatic reconnection with exponential backoff\n\n**Event Format:**\nEvents follow the SSE specification with `event:` and `data:` fields:\n```\nevent: call.incoming\ndata: {\"event\":\"call.incoming\",\"account_id\":\"acct_...\",\"from_number\":\"+14155551234\",\"to_number\":\"+14155559876\"}\n```\n\n**Available Event Types:**\n\n### connected\nSent immediately when the SSE connection is established.\n```json\n{\"message\": \"Connected to event stream\"}\n```\n\n### call.incoming\nSent when an incoming call arrives for the account.\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `event` | string | Always `\"call.incoming\"` |\n| `account` | string | Account receiving the call |\n| `call_id` | string | Call detail record identifier |\n| `from_number` | string | Caller's phone number (E.164) |\n| `from_name` | string \\| null | Caller's name from caller ID |\n| `to_number` | string | Called phone number (E.164) |\n| `from_user` | string \\| null | User who initiated the call, when known |\n| `to_user` | string \\| null | User the call is destined for, when known |\n\n### call.initiated\nSent when an outbound call starts dialing.\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `event` | string | Always `\"call.initiated\"` |\n| `account` | string | Account initiating the call |\n| `call_id` | string | Call detail record identifier |\n| `from_number` | string | Outbound caller number (E.164) |\n| `to_number` | string | Destination number (E.164) |\n| `user` | string | User who initiated the call (alias for `from_user`) |\n| `from_user` | string \\| null | User who initiated the call, when known |\n| `to_user` | string \\| null | User the call is destined for, when known |\n\n### call.ringing\nSent once per (call, user) when the platform is about to ring a user's phone(s). Fires\nregardless of how the call was routed to the user — direct extension, ring group, ring-all-users,\nFind-Me/Follow-Me (including forwarding to an external number), dial plan Dial User node, voice\napp transfer, or a parked-call ring-back. The event indicates logical \"we're ringing this user\",\nnot a SIP 180 Ringing signal.\n\nA user with multiple endpoints (desk phone + mobile app) produces one event, not one per device.\n\nNo stop event is emitted — consumers that dismiss UI on ring stop (e.g. screen pop) should rely on\n`call.answered` or `call.end`.\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `event` | string | Always `\"call.ringing\"` |\n| `account` | string | Account owning the user being rung |\n| `call_id` | string | Call detail record identifier |\n| `user` | string | User whose phone(s) are being rung |\n| `from_number` | string | Caller's phone number (E.164) |\n| `from_name` | string \\| null | Caller's name from caller ID |\n| `to_number` | string | Called phone number (E.164) |\n| `ringing_at` | string | ISO 8601 timestamp |\n\n### call.mobile_push_wakeup\nSent when an incoming call is being delivered to the calling session of a user who has\n`mobile_push_wakeup` enabled — the cue to send the push notification that wakes the user's\nmobile app. Unlike `call.ringing`, it never fires for pure external forwarding: every event\ncorresponds to a real, answerable call for that user's app.\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `event` | string | Always `\"call.mobile_push_wakeup\"` |\n| `account` | string | Account owning the user being woken |\n| `call_id` | string | Call detail record identifier |\n| `user` | string | User whose app should be woken |\n| `from_number` | string | Caller's phone number (E.164) |\n| `from_name` | string \\| null | Caller's name from caller ID |\n| `to_number` | string | Called phone number (E.164) |\n| `ringing_at` | string | ISO 8601 timestamp |\n\n### call.answered\nSent when a call is answered.\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `event` | string | Always `\"call.answered\"` |\n| `account` | string | Account where the call was answered |\n| `call_id` | string | Call detail record identifier |\n| `from_number` | string | Caller's phone number (E.164) |\n| `to_number` | string | Called phone number (E.164) |\n| `direction` | string | `\"inbound\"` or `\"outbound\"` |\n| `answered_at` | string | Signalling answer (a greeting/menu counts, so ≈ start for inbound calls that play one) |\n| `connected_at` | string \\| null | When the winning leg (user device / external number) answered — live-conversation start. Null if answered by voicemail |\n| `from_user` | string \\| null | User who initiated the call, when known |\n| `to_user` | string \\| null | User who answered, when applicable |\n\n### call.end\nSent when a call ends.\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `event` | string | Always `\"call.end\"` |\n| `account` | string | Account where the call ended |\n| `call_id` | string | Call detail record identifier |\n| `from_number` | string | Caller's phone number (E.164) |\n| `to_number` | string | Called phone number (E.164) |\n| `direction` | string | `\"inbound\"` or `\"outbound\"` |\n| `status` | string | `\"completed\"`, `\"no-answer\"`, `\"busy\"`, `\"failed\"`, or `\"voicemail\"` |\n| `duration_seconds` | integer | Call duration in seconds |\n| `answered_at` | string \\| null | Signalling answer (a greeting/menu counts). Null if never answered |\n| `connected_at` | string \\| null | When the winning leg (user device / external number) answered — live-conversation start. Null if abandoned while ringing/greeting or answered by voicemail |\n| `ended_at` | string | ISO 8601 timestamp |\n| `from_user` | string \\| null | User who initiated the call, when known |\n| `to_user` | string \\| null | User the call reached, when applicable |\n\n### call.transfer\nSent when a call is transferred. A warm (attended) transfer involves\ntwo calls, and `call.transfer` fires for each. The\nconsultation call you placed is merged into the primary call when you\ncomplete the transfer — it is not hung up, so it never emits `call.end`;\nits `call.transfer` is its final event.\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `event` | string | Always `\"call.transfer\"` |\n| `account` | string | Account where the transfer occurred |\n| `call_id` | string | Call detail record identifier |\n| `from_number` | string | Caller's phone number (E.164) |\n| `to_number` | string | Original called number (E.164) |\n| `transferred_to` | string | Transfer target (extension number or E.164 phone number) |\n| `related_call` | string \\| null | The other call involved in an attended transfer, when it can be linked; `null` otherwise |\n",
        "operationId": "streamEvents",
        "tags": [
          "Events"
        ],
        "responses": {
          "200": {
            "description": "SSE event stream established",
            "headers": {
              "Content-Type": {
                "schema": {
                  "type": "string",
                  "example": "text/event-stream"
                }
              },
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "example": "no-cache"
                }
              },
              "Connection": {
                "schema": {
                  "type": "string",
                  "example": "keep-alive"
                }
              }
            },
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "description": "Server-Sent Events stream. Each event has an `event:` type and `data:` payload.\n"
                },
                "examples": {
                  "connected": {
                    "summary": "Connection established",
                    "value": "event: connected\ndata: {\"message\":\"Connected to event stream\"}\n"
                  },
                  "incoming_call": {
                    "summary": "Incoming call event",
                    "value": "event: call.incoming\ndata: {\"event\":\"call.incoming\",\"account_id\":\"acct_01h2xcejqtf2nbrexx3vqjhp41\",\"from_number\":\"+14155551234\",\"from_name\":\"John Smith\",\"to_number\":\"+14155559876\"}\n"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "description": "Too many concurrent event-stream connections for this platform. Retry\nafter the interval in `Retry-After`, or close a connection you no\nlonger need. The limit is generous enough that normal use will not\nreach it.\n",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before reconnecting.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/events \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/events`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/webhook_endpoints": {
      "post": {
        "summary": "Create a webhook endpoint",
        "description": "Register a URL to receive event notifications. The endpoint's mode is\ndetermined by the API key used to create it: a live key creates a\nlive-mode endpoint (`livemode: true`), a test key creates a sandbox\nendpoint (`livemode: false`). An endpoint only receives events from\naccounts in its own mode, so test traffic never reaches a live URL.\n\nThe signing `secret` is returned **only** in this create response —\nstore it to verify webhook signatures. It cannot be retrieved later.\n\nBy default the endpoint is **platform-global** and receives every\naccount's events for its mode. Include the `DialStack-Account` header to\ninstead scope the endpoint to a single account: that account's events are\nthen delivered to this endpoint **in addition** to the platform-global\nones. The scope is fixed at creation.\n",
        "operationId": "createWebhookEndpoint",
        "tags": [
          "Webhook Endpoints"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/DialStackAccountOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWebhookEndpointRequest"
              },
              "examples": {
                "all_events": {
                  "summary": "Subscribe to all events",
                  "value": {
                    "url": "https://example.com/webhooks"
                  }
                },
                "filtered": {
                  "summary": "Subscribe to specific event types",
                  "value": {
                    "url": "https://example.com/webhooks",
                    "enabled_events": [
                      "call.answered",
                      "call.end"
                    ],
                    "description": "Call lifecycle handler"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook endpoint created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpoint"
                },
                "examples": {
                  "success": {
                    "summary": "Created endpoint (secret shown once)",
                    "value": {
                      "id": "we_01h2xcejqtf2nbrexx3vqjhp41",
                      "url": "https://example.com/webhooks",
                      "livemode": true,
                      "enabled_events": [
                        "*"
                      ],
                      "status": "enabled",
                      "description": null,
                      "secret": "whsec_3f9a...",
                      "created_at": "2025-10-18T10:00:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/webhook_endpoints \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"url\":\"https://example.com/webhooks\",\"enabled_events\":[\"*\"],\"description\":\"string\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/webhook_endpoints`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "get": {
        "summary": "List webhook endpoints",
        "description": "List webhook endpoints for the authenticated platform. Only endpoints\nmatching the API key's mode are returned (a test key lists sandbox\nendpoints; a live key lists live endpoints). Newest first.\n\nWithout the `DialStack-Account` header, this lists **platform-global**\nendpoints. Include the header to list a single account's scoped\nendpoints instead.\n",
        "operationId": "listWebhookEndpoints",
        "tags": [
          "Webhook Endpoints"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/DialStackAccountOptional"
          },
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "List of webhook endpoints",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookEndpoint"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/webhook_endpoints?limit=10' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/webhook_endpoints`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/webhook_endpoints/{webhook_endpoint}": {
      "parameters": [
        {
          "name": "webhook_endpoint",
          "in": "path",
          "required": true,
          "description": "The webhook endpoint ID.",
          "schema": {
            "type": "string"
          }
        },
        {
          "$ref": "#/components/parameters/DialStackAccountOptional"
        }
      ],
      "get": {
        "summary": "Get a webhook endpoint",
        "operationId": "getWebhookEndpoint",
        "tags": [
          "Webhook Endpoints"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook endpoint details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpoint"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/webhook_endpoints/%7Bwebhook_endpoint%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/webhook_endpoints/{webhook_endpoint}`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Update a webhook endpoint",
        "description": "Update an endpoint's URL, subscribed events, status, or description.\nAn endpoint's mode (`livemode`) is fixed at creation and cannot change.\n",
        "operationId": "updateWebhookEndpoint",
        "tags": [
          "Webhook Endpoints"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWebhookEndpointRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook endpoint updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpoint"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/webhook_endpoints/%7Bwebhook_endpoint%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"url\":\"string\",\"enabled_events\":[\"*\"],\"status\":\"enabled\",\"description\":\"string\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/webhook_endpoints/{webhook_endpoint}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "delete": {
        "summary": "Delete a webhook endpoint",
        "operationId": "deleteWebhookEndpoint",
        "tags": [
          "Webhook Endpoints"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "Webhook endpoint deleted"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/webhook_endpoints/%7Bwebhook_endpoint%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/webhook_endpoints/{webhook_endpoint}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/schedules": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "post": {
        "summary": "Create a schedule",
        "description": "Create a new business hours schedule within the account. Schedules define\nwhen the business is open based on weekly time ranges and holidays.\n",
        "operationId": "createSchedule",
        "tags": [
          "Schedules"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateScheduleRequest"
              },
              "examples": {
                "business_hours": {
                  "summary": "Standard business hours",
                  "value": {
                    "name": "Business Hours",
                    "timezone": "America/New_York",
                    "ranges": [
                      {
                        "day": 1,
                        "start": "09:00",
                        "end": "17:00"
                      },
                      {
                        "day": 2,
                        "start": "09:00",
                        "end": "17:00"
                      },
                      {
                        "day": 3,
                        "start": "09:00",
                        "end": "17:00"
                      },
                      {
                        "day": 4,
                        "start": "09:00",
                        "end": "17:00"
                      },
                      {
                        "day": 5,
                        "start": "09:00",
                        "end": "17:00"
                      }
                    ],
                    "holidays": [
                      {
                        "start": "2025-12-25",
                        "end": "2025-12-25"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Schedule created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Schedule"
                },
                "examples": {
                  "success": {
                    "summary": "Successful schedule creation",
                    "value": {
                      "id": "sched_01h2xcejqtf2nbrexx3vqjhp50",
                      "name": "Business Hours",
                      "timezone": "America/New_York",
                      "ranges": [
                        {
                          "day": 1,
                          "start": "09:00",
                          "end": "17:00"
                        }
                      ],
                      "holidays": [],
                      "created_at": "2025-10-18T10:00:00Z",
                      "updated_at": "2025-10-18T10:00:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/schedules \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"name\":\"Business Hours\",\"timezone\":\"America/New_York\",\"ranges\":[{\"day\":1,\"start\":\"09:00\",\"end\":\"17:00\"},{\"day\":2,\"start\":\"09:00\",\"end\":\"17:00\"}],\"holidays\":[{\"start\":\"2025-12-25\",\"end\":\"2025-12-25\"}]}'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.schedules.create(/* body params */, { dialstackAccount: 'acct_...' });"
          }
        ]
      },
      "get": {
        "summary": "List schedules",
        "description": "List all schedules for the account.\nResults are returned in reverse chronological order (newest first).\n",
        "operationId": "listSchedules",
        "tags": [
          "Schedules"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "List of schedules",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Schedule"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                },
                "examples": {
                  "list": {
                    "summary": "Schedule list response",
                    "value": {
                      "object": "list",
                      "url": "/v1/schedules",
                      "next_page_url": null,
                      "previous_page_url": null,
                      "data": [
                        {
                          "id": "sched_01h2xcejqtf2nbrexx3vqjhp50",
                          "name": "Business Hours",
                          "timezone": "America/New_York",
                          "ranges": [
                            {
                              "day": 1,
                              "start": "09:00",
                              "end": "17:00"
                            }
                          ],
                          "holidays": [],
                          "created_at": "2025-10-18T10:00:00Z",
                          "updated_at": "2025-10-18T10:00:00Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/schedules?limit=10' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.schedules.list({ dialstackAccount: 'acct_...' });"
          }
        ]
      }
    },
    "/v1/schedules/{schedule_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/ScheduleId"
        }
      ],
      "get": {
        "summary": "Get schedule details",
        "description": "Retrieve a specific schedule by ID.\n",
        "operationId": "getSchedule",
        "tags": [
          "Schedules"
        ],
        "responses": {
          "200": {
            "description": "Schedule details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Schedule"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/ScheduleNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/schedules/sched_01h2xcejqtf2nbrexx3vqjhp50 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.schedules.retrieve('schedule_...', { dialstackAccount: 'acct_...' });"
          }
        ]
      },
      "post": {
        "summary": "Update schedule",
        "description": "Update schedule details (name, timezone, ranges, or holidays).\nOnly the fields provided will be updated.\n",
        "operationId": "updateSchedule",
        "tags": [
          "Schedules"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateScheduleRequest"
              },
              "examples": {
                "update_name": {
                  "summary": "Update schedule name",
                  "value": {
                    "name": "New Business Hours"
                  }
                },
                "update_ranges": {
                  "summary": "Update time ranges",
                  "value": {
                    "ranges": [
                      {
                        "day": 1,
                        "start": "08:00",
                        "end": "18:00"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Schedule updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Schedule"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/ScheduleNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/schedules/sched_01h2xcejqtf2nbrexx3vqjhp50 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"name\":\"Updated Business Hours\",\"timezone\":\"America/Los_Angeles\",\"ranges\":[{\"day\":1,\"start\":\"09:00\",\"end\":\"17:00\"}],\"holidays\":[{\"start\":\"2025-12-25\",\"end\":\"2025-12-25\"}]}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/schedules/{schedule_id}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "delete": {
        "summary": "Delete schedule",
        "description": "Delete a schedule. This operation is irreversible.\n",
        "operationId": "deleteSchedule",
        "tags": [
          "Schedules"
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/ScheduleDeleted"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/ScheduleNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/schedules/sched_01h2xcejqtf2nbrexx3vqjhp50 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/schedules/{schedule_id}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/schedules/{schedule_id}/hold": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/ScheduleId"
        }
      ],
      "post": {
        "summary": "Set schedule hold",
        "description": "Set a temporary hold on a schedule. The hold overrides the normal schedule\ncalculation until the specified time.\n\nUse `value: true` to force the schedule to be considered \"open\" regardless\nof the time ranges, or `value: false` to force it to be considered \"closed\".\n\nIf `until` is not provided, it defaults to midnight (00:00:00) the next day\nin the schedule's timezone.\n",
        "operationId": "setScheduleHold",
        "tags": [
          "Schedules"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HoldScheduleRequest"
              },
              "examples": {
                "close_until_specific_time": {
                  "summary": "Close until specific time",
                  "value": {
                    "value": false,
                    "until": "2025-12-20T22:00:00Z"
                  }
                },
                "close_until_tomorrow": {
                  "summary": "Close until midnight (default)",
                  "value": {
                    "value": false
                  }
                },
                "force_open": {
                  "summary": "Force open temporarily",
                  "value": {
                    "value": true,
                    "until": "2025-12-20T17:00:00Z"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Hold set successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Schedule"
                },
                "examples": {
                  "with_hold": {
                    "summary": "Schedule with hold set",
                    "value": {
                      "id": "sched_01h2xcejqtf2nbrexx3vqjhp50",
                      "name": "Business Hours",
                      "timezone": "America/New_York",
                      "ranges": [
                        {
                          "day": 1,
                          "start": "09:00",
                          "end": "17:00"
                        }
                      ],
                      "holidays": [],
                      "hold": {
                        "value": false,
                        "until": "2025-12-20T22:00:00Z"
                      },
                      "created_at": "2025-10-18T10:00:00Z",
                      "updated_at": "2025-10-18T14:30:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/ScheduleNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/schedules/sched_01h2xcejqtf2nbrexx3vqjhp50/hold \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"value\":false,\"until\":\"2025-12-20T22:00:00Z\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/schedules/{schedule_id}/hold`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "delete": {
        "summary": "Clear schedule hold",
        "description": "Clear the hold from a schedule, returning it to normal schedule-based calculation.\n",
        "operationId": "clearScheduleHold",
        "tags": [
          "Schedules"
        ],
        "responses": {
          "200": {
            "description": "Hold cleared successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Schedule"
                },
                "examples": {
                  "hold_cleared": {
                    "summary": "Schedule with hold cleared",
                    "value": {
                      "id": "sched_01h2xcejqtf2nbrexx3vqjhp50",
                      "name": "Business Hours",
                      "timezone": "America/New_York",
                      "ranges": [
                        {
                          "day": 1,
                          "start": "09:00",
                          "end": "17:00"
                        }
                      ],
                      "holidays": [],
                      "created_at": "2025-10-18T10:00:00Z",
                      "updated_at": "2025-10-18T14:35:00Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/ScheduleNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/schedules/sched_01h2xcejqtf2nbrexx3vqjhp50/hold \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/schedules/{schedule_id}/hold`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/dialplans": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "post": {
        "summary": "Create a dial plan",
        "description": "Create a new visual call routing graph for the account.\nSee the `DialPlanNode` schema for the full list of node types and\ntheir configuration options.\n",
        "operationId": "createDialPlan",
        "tags": [
          "Dial Plans"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDialPlanRequest"
              },
              "examples": {
                "main_line": {
                  "summary": "Main line routing with schedule check",
                  "value": {
                    "name": "Main Line Routing",
                    "entry_node": "check_hours",
                    "nodes": [
                      {
                        "id": "check_hours",
                        "type": "schedule",
                        "config": {
                          "schedule": "sched_01h2xcejqtf2nbrexx3vqjhp50",
                          "open": "reception",
                          "closed": "voicemail"
                        }
                      },
                      {
                        "id": "reception",
                        "type": "internal_dial",
                        "config": {
                          "target": "user_01h2xcejqtf2nbrexx3vqjhp45",
                          "timeout": 30,
                          "next": "voicemail"
                        }
                      },
                      {
                        "id": "voicemail",
                        "type": "internal_dial",
                        "config": {
                          "target": "user_01h2xcejqtf2nbrexx3vqjhp46",
                          "timeout": 60
                        }
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Dial plan created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DialPlan"
                },
                "examples": {
                  "success": {
                    "summary": "Successful dial plan creation",
                    "value": {
                      "id": "dp_01h2xcejqtf2nbrexx3vqjhp60",
                      "name": "Main Line Routing",
                      "entry_node": "check_hours",
                      "nodes": [
                        {
                          "id": "check_hours",
                          "type": "schedule",
                          "config": {
                            "schedule": "sched_01h2xcejqtf2nbrexx3vqjhp50",
                            "open": "reception",
                            "closed": "voicemail"
                          }
                        },
                        {
                          "id": "reception",
                          "type": "internal_dial",
                          "config": {
                            "target": "user_01h2xcejqtf2nbrexx3vqjhp45",
                            "timeout": 30,
                            "next": "voicemail"
                          }
                        },
                        {
                          "id": "voicemail",
                          "type": "internal_dial",
                          "config": {
                            "target": "user_01h2xcejqtf2nbrexx3vqjhp46",
                            "timeout": 60
                          }
                        }
                      ],
                      "created_at": "2025-10-18T10:00:00Z",
                      "updated_at": "2025-10-18T10:00:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/RoutingLoop"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/dialplans \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"name\":\"Main Line Routing\",\"entry_node\":\"check_hours\",\"nodes\":[{\"id\":\"check_hours\",\"type\":\"schedule\",\"position\":{\"x\":200,\"y\":100},\"config\":{\"schedule\":\"sched_01h2xcejqtf2nbrexx3vqjhp50\",\"open\":\"reception\",\"closed\":\"voicemail\",\"holiday\":\"holiday_announcement\"}}]}'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.dialPlans.create(/* body params */, { dialstackAccount: 'acct_...' });"
          }
        ]
      },
      "get": {
        "summary": "List dial plans",
        "description": "List all dial plans for the account.\nResults are returned in reverse chronological order (newest first).\n",
        "operationId": "listDialPlans",
        "tags": [
          "Dial Plans"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `extensions`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "extensions"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of dial plans",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/DialPlan"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/dialplans?limit=10&expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.dialPlans.list({ dialstackAccount: 'acct_...' });"
          }
        ]
      }
    },
    "/v1/dialplans/{dial_plan_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "name": "dial_plan_id",
          "in": "path",
          "required": true,
          "description": "The dial plan identifier",
          "schema": {
            "type": "string"
          },
          "example": "dp_01h2xcejqtf2nbrexx3vqjhp60"
        }
      ],
      "get": {
        "summary": "Get a dial plan",
        "description": "Retrieve a dial plan by ID.\n",
        "operationId": "getDialPlan",
        "tags": [
          "Dial Plans"
        ],
        "parameters": [
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `extensions`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "extensions"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Dial plan details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DialPlan"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/DialPlanNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/dialplans/dp_01h2xcejqtf2nbrexx3vqjhp60?expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.dialPlans.retrieve('dial_plan_...', { dialstackAccount: 'acct_...' });"
          }
        ]
      },
      "post": {
        "summary": "Update a dial plan",
        "description": "Update an existing dial plan. All fields are optional;\nonly provided fields will be updated.\n\nWhen `nodes` is provided, it fully replaces all nodes (not a partial node update).\n",
        "operationId": "updateDialPlan",
        "tags": [
          "Dial Plans"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDialPlanRequest"
              },
              "examples": {
                "update_name": {
                  "summary": "Update dial plan name",
                  "value": {
                    "name": "Updated Main Line Routing"
                  }
                },
                "update_nodes": {
                  "summary": "Update nodes (full replacement)",
                  "value": {
                    "entry_node": "check_hours",
                    "nodes": [
                      {
                        "id": "check_hours",
                        "type": "schedule",
                        "config": {
                          "schedule": "sched_01h2xcejqtf2nbrexx3vqjhp50",
                          "open": "reception",
                          "closed": "after_hours"
                        }
                      },
                      {
                        "id": "reception",
                        "type": "internal_dial",
                        "config": {
                          "target": "user_01h2xcejqtf2nbrexx3vqjhp45",
                          "timeout": 30
                        }
                      },
                      {
                        "id": "after_hours",
                        "type": "internal_dial",
                        "config": {
                          "target": "user_01h2xcejqtf2nbrexx3vqjhp47",
                          "timeout": 45
                        }
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Dial plan updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DialPlan"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/DialPlanNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/dialplans/dp_01h2xcejqtf2nbrexx3vqjhp60 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"name\":\"Updated Main Line Routing\",\"entry_node\":\"check_hours\",\"nodes\":[{\"id\":\"check_hours\",\"type\":\"schedule\",\"position\":{\"x\":200,\"y\":100},\"config\":{\"schedule\":\"sched_01h2xcejqtf2nbrexx3vqjhp50\",\"open\":\"reception\",\"closed\":\"voicemail\",\"holiday\":\"holiday_announcement\"}}]}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/dialplans/{dial_plan_id}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "delete": {
        "summary": "Delete a dial plan",
        "description": "Delete a dial plan by ID.\n\n**Note**: Deletion will fail if any extensions still reference this dial plan.\nYou must first update or delete those extensions.\n",
        "operationId": "deleteDialPlan",
        "tags": [
          "Dial Plans"
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/DialPlanDeleted"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/DialPlanNotFound"
          },
          "409": {
            "$ref": "#/components/responses/DialPlanConflict"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/dialplans/dp_01h2xcejqtf2nbrexx3vqjhp60 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/dialplans/{dial_plan_id}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/ring_groups": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "post": {
        "summary": "Create a ring group",
        "description": "Creates a new ring group for parallel dialing.\n\nWhen a call is routed to a ring group, all members ring simultaneously.\nThe first member to answer wins; other ringing channels are cancelled.\n",
        "operationId": "createRingGroup",
        "tags": [
          "Ring Groups"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateRingGroupRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Ring group created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RingGroup"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/ring_groups \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"name\":\"Sales Team\",\"timeout_seconds\":30,\"ignore_forwarding\":false,\"confirm_external\":false,\"timeout_action\":\"voicemail\",\"timeout_target\":\"user_01h2xcejqtf2nbrexx3vqjhp42\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.ringGroups.create(/* body params */, { dialstackAccount: 'acct_...' });"
          }
        ]
      },
      "get": {
        "summary": "List ring groups",
        "description": "Returns a paginated list of ring groups for the account.\n",
        "operationId": "listRingGroups",
        "tags": [
          "Ring Groups"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `extensions`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "extensions"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of ring groups",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/RingGroup"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/ring_groups?limit=10&expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.ringGroups.list({ dialstackAccount: 'acct_...' });"
          }
        ]
      }
    },
    "/v1/ring_groups/{ring_group_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/RingGroupId"
        }
      ],
      "get": {
        "summary": "Get a ring group",
        "description": "Retrieves a ring group by ID, including its members.\n",
        "operationId": "getRingGroup",
        "tags": [
          "Ring Groups"
        ],
        "parameters": [
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `extensions`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "extensions"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ring group details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RingGroup"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/RingGroupNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/ring_groups/rg_01h2xcejqtf2nbrexx3vqjhp51?expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.ringGroups.retrieve('ring_group_...', { dialstackAccount: 'acct_...' });"
          }
        ]
      },
      "post": {
        "summary": "Update a ring group",
        "description": "Updates ring group settings. All fields are optional.\n",
        "operationId": "updateRingGroup",
        "tags": [
          "Ring Groups"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateRingGroupRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated ring group",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RingGroup"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/RingGroupNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/ring_groups/rg_01h2xcejqtf2nbrexx3vqjhp51 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"name\":\"Support Team\",\"timeout_seconds\":45,\"ignore_forwarding\":true,\"confirm_external\":true,\"timeout_action\":\"voicemail\",\"timeout_target\":\"user_01h2xcejqtf2nbrexx3vqjhp42\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.ringGroups.update('ring_group_...', /* body params */, { dialstackAccount: 'acct_...' });"
          }
        ]
      },
      "delete": {
        "summary": "Delete a ring group",
        "description": "Deletes a ring group. Cannot delete if used by an extension.\n",
        "operationId": "deleteRingGroup",
        "tags": [
          "Ring Groups"
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/RingGroupDeleted"
          },
          "404": {
            "$ref": "#/components/responses/RingGroupNotFound"
          },
          "409": {
            "$ref": "#/components/responses/RingGroupConflict"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/ring_groups/rg_01h2xcejqtf2nbrexx3vqjhp51 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.ringGroups.del('ring_group_...', { dialstackAccount: 'acct_...' });"
          }
        ]
      }
    },
    "/v1/ring_groups/{ring_group_id}/members": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/RingGroupId"
        }
      ],
      "post": {
        "summary": "Add a member",
        "description": "Adds a member to the ring group.\n\nExactly one of `extension` or `phone_number` must be provided:\n- `extension`: ID of a routing target\n- `phone_number`: Dial string (E.164, local number, extension, 911, etc.)\n",
        "operationId": "addRingGroupMember",
        "tags": [
          "Ring Groups"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddRingGroupMemberRequest"
              },
              "examples": {
                "extension": {
                  "summary": "Extension member",
                  "value": {
                    "extension": "user_01h2xcejqtf2nbrexx3vqjhp42"
                  }
                },
                "phone": {
                  "summary": "Phone number member",
                  "value": {
                    "phone_number": "+14155551234"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Member added",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RingGroupMember"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/RingGroupNotFound"
          },
          "422": {
            "description": "Routing loop detected. Adding this member would create a circular reference\n(e.g., RG1 → DP1 → RG1), or nesting exceeds maximum depth of 20.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "routing loop detected: rg_01h2x... → dp_01h2x... → rg_01h2x..."
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/ring_groups/rg_01h2xcejqtf2nbrexx3vqjhp51/members \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"extension\":\"user_01h2xcejqtf2nbrexx3vqjhp42\",\"phone_number\":\"+14155551234\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/ring_groups/{ring_group_id}/members`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/ring_groups/{ring_group_id}/members/{member_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/RingGroupId"
        },
        {
          "$ref": "#/components/parameters/RingGroupMemberId"
        }
      ],
      "delete": {
        "summary": "Remove a member",
        "description": "Removes a member from the ring group.\n",
        "operationId": "removeRingGroupMember",
        "tags": [
          "Ring Groups"
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/RingGroupMemberDeleted"
          },
          "404": {
            "$ref": "#/components/responses/RingGroupMemberNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/ring_groups/rg_01h2xcejqtf2nbrexx3vqjhp51/members/rgm_01h2xcejqtf2nbrexx3vqjhp52 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/ring_groups/{ring_group_id}/members/{member_id}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/files": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "post": {
        "summary": "Upload a file",
        "description": "Uploads a file and returns its metadata, including the `id` to\nreference elsewhere. The `purpose` determines the accepted content and\nvalidation. `fax_source` (for sending a fax) accepts a single PDF up to\n25 MB and 50 pages.\n\nUploads are served from a dedicated host: send this request to\n`https://files.dialstack.ai/v1/files` (not `api.dialstack.ai`, which\nreturns a 404 for this operation). Authentication and the request body\nare otherwise identical. All other API operations use the regular\n`api.dialstack.ai` host.\n",
        "operationId": "uploadFile",
        "servers": [
          {
            "url": "https://files.dialstack.ai"
          }
        ],
        "tags": [
          "Files"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "The file to upload."
                  },
                  "purpose": {
                    "type": "string",
                    "description": "What the file will be used for.",
                    "example": "fax_source"
                  }
                },
                "required": [
                  "file",
                  "purpose"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The file was uploaded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/File"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "413": {
            "description": "The uploaded file exceeds the size limit for this purpose.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://files.dialstack.ai/v1/files \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: multipart/form-data' \\\n  --form file=string \\\n  --form purpose=fax_source"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://files.dialstack.ai/v1/files`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/faxes": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "get": {
        "summary": "List faxes",
        "description": "Returns a paginated list of faxes for the account, most recent first.\n",
        "operationId": "listFaxes",
        "tags": [
          "Faxes"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "direction",
            "in": "query",
            "description": "Filter by fax direction.",
            "schema": {
              "type": "string",
              "enum": [
                "inbound",
                "outbound"
              ]
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by fax status.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "delivered",
                "failed",
                "received"
              ]
            }
          },
          {
            "name": "did",
            "in": "query",
            "description": "Filter by your own associated phone number (DID), by its id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "number",
            "in": "query",
            "description": "Substring filter on the sender or recipient number. Non-digit\ncharacters are stripped, then the digits are matched anywhere within\nthe stored E.164 value — e.g. `415` returns every fax to or from a\n415-area-code number.\n",
            "schema": {
              "type": "string"
            },
            "example": "4155551234"
          },
          {
            "name": "is_read",
            "in": "query",
            "description": "Filter by read state. Pass `false` to show only unread faxes.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to inline. Supported values: `file`, `did`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "file",
                  "did"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of faxes",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Fax"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "A page of faxes (one outbound, one inbound)",
                    "value": {
                      "object": "list",
                      "url": "/v1/faxes",
                      "next_page_url": null,
                      "previous_page_url": null,
                      "data": [
                        {
                          "id": "fax_01h2xcejqtf2nbrexx3vqjhp60",
                          "direction": "outbound",
                          "status": "delivered",
                          "file": "file_01h2xcejqtf2nbrexx3vqjhp99",
                          "did": "did_01h2xcejqtf2nbrexx3vqjhp33",
                          "from_number": "+14155550100",
                          "to_number": "+12125558888",
                          "call_id": null,
                          "pages": 3,
                          "source_pages": 3,
                          "transport": "t38",
                          "error_code": null,
                          "attempts": 1,
                          "read_at": null,
                          "submitted_at": "2026-06-10T18:04:00Z",
                          "completed_at": "2026-06-10T18:05:12Z",
                          "created_at": "2026-06-10T18:04:00Z",
                          "updated_at": "2026-06-10T18:05:12Z"
                        },
                        {
                          "id": "fax_01h2xcejqtf2nbrexx3vqjhp61",
                          "direction": "inbound",
                          "status": "received",
                          "file": "file_01h2xcejqtf2nbrexx3vqjhpa1",
                          "did": "did_01h2xcejqtf2nbrexx3vqjhp33",
                          "from_number": "+13055554444",
                          "to_number": "+14155550100",
                          "call_id": null,
                          "pages": 5,
                          "source_pages": null,
                          "transport": "t38",
                          "error_code": null,
                          "attempts": 0,
                          "read_at": null,
                          "submitted_at": null,
                          "completed_at": "2026-06-10T17:40:09Z",
                          "created_at": "2026-06-10T17:39:30Z",
                          "updated_at": "2026-06-10T17:40:09Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/faxes?limit=10&direction=SOME_STRING_VALUE&status=SOME_STRING_VALUE&did=SOME_STRING_VALUE&number=4155551234&is_read=SOME_BOOLEAN_VALUE&expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/faxes`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Send a fax",
        "description": "Sends an outbound fax. Upload the document first with\n`POST https://files.dialstack.ai/v1/files` (purpose `fax_source`) —\nnote the dedicated upload host — to obtain a `file`, then\nreference it here along with the source number (`did`) and the\ndestination. The source number must be active and fax-enabled. The\ndestination is normalized to E.164.\n\nThe fax is created in `pending` and progresses to `delivered` or\n`failed`. Outbound sends are subject to a rolling-hour, per-account\nrate limit.\n",
        "operationId": "sendFax",
        "tags": [
          "Faxes"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "description": "ID of a file uploaded with purpose `fax_source`."
                  },
                  "to": {
                    "type": "string",
                    "description": "Destination fax number. Normalized to E.164.",
                    "example": "+14155551234"
                  },
                  "did": {
                    "type": "string",
                    "description": "ID of the account phone number (DID) to send from. Must be active and fax-enabled."
                  }
                },
                "required": [
                  "file",
                  "to",
                  "did"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The fax was accepted and queued for delivery.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Fax"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "description": "The account's rolling-hour fax rate limit has been exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/faxes \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"file\":\"string\",\"to\":\"+14155551234\",\"did\":\"string\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/faxes`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/faxes/{fax}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/FaxId"
        }
      ],
      "get": {
        "summary": "Get a fax",
        "description": "Returns a single fax. Expand `file` for a signed download URL for the\ndocument, and `did` for the compact phone-number object.\n",
        "operationId": "getFax",
        "tags": [
          "Faxes"
        ],
        "parameters": [
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `file`, `did`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "file",
                  "did"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Fax details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Fax"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/FaxNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/faxes/fax_01h2xcejqtf2nbrexx3vqjhp60?expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/faxes/{fax}`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Update a fax",
        "description": "Marks a received fax read or unread. Read state is exposed on the fax as\nthe null-ness of `read_at`.\n",
        "operationId": "updateFax",
        "tags": [
          "Faxes"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "is_read": {
                    "type": "boolean",
                    "description": "Mark the fax as read or unread."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated fax",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Fax"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/FaxNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/faxes/fax_01h2xcejqtf2nbrexx3vqjhp60 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"is_read\":true}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/faxes/{fax}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "delete": {
        "summary": "Delete a fax",
        "description": "Deletes a fax record. The referenced file keeps its own lifecycle.\n",
        "operationId": "deleteFax",
        "tags": [
          "Faxes"
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/FaxDeleted"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/FaxNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/faxes/fax_01h2xcejqtf2nbrexx3vqjhp60 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/faxes/{fax}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/shared_voicemail_boxes": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "post": {
        "summary": "Create a shared voicemail box",
        "description": "Creates a new shared voicemail box for team or departmental voicemail.\n",
        "operationId": "createSharedVoicemailBox",
        "tags": [
          "Shared Voicemail Boxes"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateSharedVoicemailBoxRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Shared voicemail box created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SharedVoicemailBox"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/shared_voicemail_boxes \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"name\":\"Sales Voicemail\",\"email\":\"sales@example.com\",\"pin\":\"1234\",\"email_attach_audio\":true,\"email_include_summary\":true,\"email_include_transcript\":true,\"delete_after_email\":true}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/shared_voicemail_boxes`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "get": {
        "summary": "List shared voicemail boxes",
        "description": "Returns a paginated list of shared voicemail boxes for the account.\n",
        "operationId": "listSharedVoicemailBoxes",
        "tags": [
          "Shared Voicemail Boxes"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `extensions`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "extensions"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of shared voicemail boxes",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SharedVoicemailBox"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/shared_voicemail_boxes?limit=10&expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/shared_voicemail_boxes`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/shared_voicemail_boxes/{shared_voicemail_box_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/SharedVoicemailBoxId"
        }
      ],
      "get": {
        "summary": "Get a shared voicemail box",
        "description": "Retrieves a shared voicemail box by ID.\n",
        "operationId": "getSharedVoicemailBox",
        "tags": [
          "Shared Voicemail Boxes"
        ],
        "parameters": [
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `extensions`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "extensions"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Shared voicemail box details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SharedVoicemailBox"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/SharedVoicemailBoxNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/shared_voicemail_boxes/svm_01h2xcejqtf2nbrexx3vqjhp60?expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/shared_voicemail_boxes/{shared_voicemail_box_id}`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Update a shared voicemail box",
        "description": "Updates shared voicemail box settings. All fields are optional.\n",
        "operationId": "updateSharedVoicemailBox",
        "tags": [
          "Shared Voicemail Boxes"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateSharedVoicemailBoxRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated shared voicemail box",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SharedVoicemailBox"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/SharedVoicemailBoxNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/shared_voicemail_boxes/svm_01h2xcejqtf2nbrexx3vqjhp60 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"name\":\"Support Voicemail\",\"email\":\"support@example.com\",\"pin\":\"5678\",\"email_attach_audio\":false,\"email_include_summary\":false,\"email_include_transcript\":false,\"delete_after_email\":false}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/shared_voicemail_boxes/{shared_voicemail_box_id}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "delete": {
        "summary": "Delete a shared voicemail box",
        "description": "Deletes a shared voicemail box. Cannot delete if used by an extension.\n",
        "operationId": "deleteSharedVoicemailBox",
        "tags": [
          "Shared Voicemail Boxes"
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/SharedVoicemailBoxDeleted"
          },
          "404": {
            "$ref": "#/components/responses/SharedVoicemailBoxNotFound"
          },
          "409": {
            "$ref": "#/components/responses/SharedVoicemailBoxConflict"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/shared_voicemail_boxes/svm_01h2xcejqtf2nbrexx3vqjhp60 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/shared_voicemail_boxes/{shared_voicemail_box_id}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/audio_clips": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "post": {
        "summary": "Upload an audio clip",
        "description": "Uploads a new audio clip for use as hold music, IVR prompts, or other audio playback.\n\nAccepts a multipart form with a `file` field (audio file) and a `name` field (display name).\nThe audio is validated and transcoded server-side. Maximum file size: 5 MB.\nSupported input formats: WAV, MP3, AAC, Ogg Vorbis, Opus.\n",
        "operationId": "createAudioClip",
        "tags": [
          "Audio Clips"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 255,
                    "description": "Display name for the audio clip (must be unique per account)",
                    "example": "Hold Music"
                  },
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Audio file to upload"
                  }
                },
                "required": [
                  "name",
                  "file"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Audio clip created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AudioClip"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "description": "An audio clip with this name already exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "File size exceeds the 5 MB limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/audio_clips \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: multipart/form-data' \\\n  --form 'name=Hold Music' \\\n  --form file=string"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/audio_clips`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "get": {
        "summary": "List audio clips",
        "description": "Returns a paginated list of audio clips for the account.\n",
        "operationId": "listAudioClips",
        "tags": [
          "Audio Clips"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "List of audio clips",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AudioClip"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/audio_clips?limit=10' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/audio_clips`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/audio_clips/{audio_clip_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/AudioClipId"
        }
      ],
      "get": {
        "summary": "Get an audio clip",
        "description": "Retrieves an audio clip by ID. The response includes a signed URL for downloading the audio file.\n",
        "operationId": "getAudioClip",
        "tags": [
          "Audio Clips"
        ],
        "responses": {
          "200": {
            "description": "Audio clip details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AudioClip"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/AudioClipNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/audio_clips/%7Baudio_clip_id%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/audio_clips/{audio_clip_id}`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Update an audio clip",
        "description": "Updates an audio clip's display name.\n",
        "operationId": "updateAudioClip",
        "tags": [
          "Audio Clips"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAudioClipRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated audio clip",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AudioClip"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/AudioClipNotFound"
          },
          "409": {
            "description": "An audio clip with this name already exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/audio_clips/%7Baudio_clip_id%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"name\":\"Updated Hold Music\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/audio_clips/{audio_clip_id}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "delete": {
        "summary": "Delete an audio clip",
        "description": "Deletes an audio clip.\n",
        "operationId": "deleteAudioClip",
        "tags": [
          "Audio Clips"
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/AudioClipDeleted"
          },
          "404": {
            "$ref": "#/components/responses/AudioClipNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/audio_clips/%7Baudio_clip_id%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/audio_clips/{audio_clip_id}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/extensions": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "post": {
        "summary": "Create an extension",
        "description": "Creates a new extension mapping a dial code to a routing target.\n",
        "operationId": "createExtension",
        "tags": [
          "Extensions"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateExtensionRequest"
              },
              "examples": {
                "user_extension": {
                  "summary": "Create a user extension",
                  "value": {
                    "number": "105",
                    "target": "user_01h2xcejqtf2nbrexx3vqjhp42"
                  }
                },
                "dial_plan_extension": {
                  "summary": "Create a dial plan extension",
                  "value": {
                    "number": "200",
                    "target": "dp_01h2xcejqtf2nbrexx3vqjhp60"
                  }
                },
                "voice_app_extension": {
                  "summary": "Create a voice app extension",
                  "value": {
                    "number": "300",
                    "target": "va_01h2xcejqtf2nbrexx3vqjhp49"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Extension created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Extension"
                },
                "examples": {
                  "success": {
                    "summary": "Successful extension creation",
                    "value": {
                      "number": "105",
                      "target": "user_01h2xcejqtf2nbrexx3vqjhp42",
                      "status": "active",
                      "created_at": "2025-10-18T10:00:00Z",
                      "updated_at": "2025-10-18T10:00:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/ExtensionConflict"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/extensions \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"number\":\"105\",\"target\":\"user_01h2xcejqtf2nbrexx3vqjhp42\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.extensions.create(/* body params */, { dialstackAccount: 'acct_...' });"
          }
        ]
      },
      "get": {
        "summary": "List extensions",
        "description": "List all extensions for the account.\nOptionally filter by target to find extensions pointing to a specific routing target.\nResults are returned in reverse chronological order (newest first).\n",
        "operationId": "listExtensions",
        "tags": [
          "Extensions"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ExtensionTargetFilter"
          },
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "List of extensions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Extension"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                },
                "examples": {
                  "list": {
                    "summary": "Extension list response",
                    "value": {
                      "object": "list",
                      "url": "/v1/extensions",
                      "next_page_url": null,
                      "previous_page_url": null,
                      "data": [
                        {
                          "number": "105",
                          "target": "user_01h2xcejqtf2nbrexx3vqjhp42",
                          "status": "active",
                          "created_at": "2025-10-18T10:00:00Z",
                          "updated_at": "2025-10-18T10:00:00Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/extensions?target=user_01h2xcejqtf2nbrexx3vqjhp42&limit=10' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/extensions`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/extensions/{number}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/ExtensionNumber"
        }
      ],
      "get": {
        "summary": "Get an extension",
        "description": "Retrieve an extension by its number (dial code).\n",
        "operationId": "getExtension",
        "tags": [
          "Extensions"
        ],
        "responses": {
          "200": {
            "description": "Extension details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Extension"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/ExtensionNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/extensions/105 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { DialStack } from '@dialstack/sdk-server';\n\nconst ds = new DialStack(process.env.DIALSTACK_KEY);\n\nconst result = await ds.extensions.retrieve('number_...', { dialstackAccount: 'acct_...' });"
          }
        ]
      },
      "post": {
        "summary": "Update an extension",
        "description": "Update an existing extension. You can change the target, the extension\nnumber, or both in one request (applied atomically). Renaming to a\nnumber already in use in the account returns `409`.\n",
        "operationId": "updateExtension",
        "tags": [
          "Extensions"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateExtensionRequest"
              },
              "examples": {
                "update_target": {
                  "summary": "Update extension target",
                  "value": {
                    "target": "user_01h2xcejqtf2nbrexx3vqjhp43"
                  }
                },
                "rename_number": {
                  "summary": "Rename the extension number",
                  "value": {
                    "number": "1200"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Extension updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Extension"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/ExtensionNotFound"
          },
          "409": {
            "description": "The requested extension number is already in use in this account",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "extension number already exists"
                }
              }
            }
          },
          "422": {
            "description": "Loop detected - updating to target a ring group would create a circular reference, or nesting exceeds maximum depth of 10",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "extension is a member of the target ring group"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/extensions/105 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"target\":\"user_01h2xcejqtf2nbrexx3vqjhp43\",\"number\":\"1200\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/extensions/{number}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "delete": {
        "summary": "Delete an extension",
        "description": "Delete an extension by its number (dial code).\n",
        "operationId": "deleteExtension",
        "tags": [
          "Extensions"
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/ExtensionDeleted"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/ExtensionNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/extensions/105 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/extensions/{number}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/button_templates": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "post": {
        "summary": "Create a button template",
        "description": "Create a reusable programmable-key template for an account.",
        "operationId": "createButtonTemplate",
        "tags": [
          "Button Templates"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateButtonTemplateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Button template created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ButtonTemplate"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/button_templates \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"name\":\"Front Desk\",\"description\":\"Shared front desk programmable keys\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/button_templates`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "get": {
        "summary": "List button templates",
        "description": "Returns a paginated list of button templates for the account.",
        "operationId": "listButtonTemplates",
        "tags": [
          "Button Templates"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "List of button templates",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ButtonTemplate"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/button_templates?limit=10' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/button_templates`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/button_templates/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/ButtonTemplateId"
        }
      ],
      "get": {
        "summary": "Get a button template",
        "operationId": "getButtonTemplate",
        "tags": [
          "Button Templates"
        ],
        "parameters": [
          {
            "name": "for_device",
            "in": "query",
            "required": false,
            "description": "Device identifier. Attaches a `compatibility` block showing how this\ntemplate would render on the named device (before binding).\n",
            "schema": {
              "type": "string",
              "example": "dev_01h2xcejqtf2nbrexx3vqjhp50"
            }
          },
          {
            "name": "expand[]",
            "in": "query",
            "required": false,
            "description": "Set to `buttons` to embed the template's buttons in the response.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "buttons"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Button template details",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ButtonTemplate"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "buttons": {
                          "type": "array",
                          "description": "Present only when `expand[]=buttons`.",
                          "items": {
                            "$ref": "#/components/schemas/TemplateButton"
                          }
                        },
                        "compatibility": {
                          "allOf": [
                            {
                              "$ref": "#/components/schemas/ButtonCompatibilitySummary"
                            }
                          ],
                          "description": "Present only when `for_device` is supplied."
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/ButtonTemplateNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/button_templates/btpl_01h2xcejqtf2nbrexx3vqjhp70?for_device=dev_01h2xcejqtf2nbrexx3vqjhp50&expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/button_templates/{id}`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Update a button template",
        "operationId": "updateButtonTemplate",
        "tags": [
          "Button Templates"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateButtonTemplateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Button template updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ButtonTemplate"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/ButtonTemplateNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/button_templates/btpl_01h2xcejqtf2nbrexx3vqjhp70 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"name\":\"string\",\"description\":\"string\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/button_templates/{id}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "delete": {
        "summary": "Delete a button template",
        "description": "Soft-deletes the template, clears it from every device currently bound to it, and sets the owning account's `default_button_template` to null when this template was the account default.",
        "operationId": "deleteButtonTemplate",
        "tags": [
          "Button Templates"
        ],
        "responses": {
          "204": {
            "description": "Button template deleted"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/ButtonTemplateNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/button_templates/btpl_01h2xcejqtf2nbrexx3vqjhp70 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/button_templates/{id}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/button_templates/{id}/buttons": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/ButtonTemplateId"
        }
      ],
      "get": {
        "summary": "List template buttons",
        "operationId": "listTemplateButtons",
        "tags": [
          "Button Templates"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "List of template buttons",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TemplateButton"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/ButtonTemplateNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/button_templates/btpl_01h2xcejqtf2nbrexx3vqjhp70/buttons?limit=10' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/button_templates/{id}/buttons`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Add a template button",
        "operationId": "createTemplateButton",
        "tags": [
          "Button Templates"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTemplateButtonRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Template button created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateButton"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/ButtonTemplateNotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/button_templates/btpl_01h2xcejqtf2nbrexx3vqjhp70/buttons \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"position\":1,\"label\":\"string\",\"type\":\"line\",\"target\":{\"user\":\"user_01h2xcejqtf2nbrexx3vqjhp42\"}}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/button_templates/{id}/buttons`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/button_templates/{id}/buttons/{button_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/ButtonTemplateId"
        },
        {
          "$ref": "#/components/parameters/ButtonId"
        }
      ],
      "post": {
        "summary": "Update a template button",
        "description": "Moves a button to a new position. When the target position is already\noccupied, the buttons between the old and new position rotate over the\ntemplate's occupied positions — the set of occupied positions never\nchanges, so gaps in the layout are preserved. When the target position\nis free, only the moved button changes.\n\n`position` is the only updatable field.\n",
        "operationId": "updateTemplateButton",
        "tags": [
          "Button Templates"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTemplateButtonRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Template button updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateButton"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/ButtonTemplateNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/button_templates/btpl_01h2xcejqtf2nbrexx3vqjhp70/buttons/btn_01h2xcejqtf2nbrexx3vqjhp71 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"position\":1}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/button_templates/{id}/buttons/{button_id}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "delete": {
        "summary": "Delete a template button",
        "operationId": "deleteTemplateButton",
        "tags": [
          "Button Templates"
        ],
        "responses": {
          "204": {
            "description": "Template button deleted"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/ButtonTemplateNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/button_templates/btpl_01h2xcejqtf2nbrexx3vqjhp70/buttons/btn_01h2xcejqtf2nbrexx3vqjhp71 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/button_templates/{id}/buttons/{button_id}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/devices": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "post": {
        "summary": "Create a device",
        "description": "**Recommended** way to create any device. Prefer this endpoint over\n`POST /v1/deskphones`, `POST /v1/dect-bases`, and\n`POST /v1/dect-bases/{id}/handsets`.\n\nSupported types:\n- `deskphone` requires `mac_address`\n- `dect_base` requires `mac_address`\n- `dect_handset` requires `ipei`. `base` is optional —\n  omit to stock the handset as unpaired and pair it later.\n\n`type` is optional for MAC-addressable devices: omit it and the device\ntype is detected from `mac_address` via the vendor product catalog. If\nthe MAC cannot be classified, the request returns `400` and you must\nsupply `type`. Supplying a `type` that contradicts a positive catalog\nmatch also returns `400` (the request is never silently reclassified).\n`dect_handset` is IPEI-identified, so its `type` must always be supplied.\n",
        "operationId": "createDevice",
        "tags": [
          "Devices"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDeviceRequest"
              },
              "examples": {
                "deskphone": {
                  "summary": "Create a deskphone",
                  "value": {
                    "type": "deskphone",
                    "mac_address": "00:04:13:aa:bb:cc",
                    "model": "D785"
                  }
                },
                "detected": {
                  "summary": "Create a device, detecting the type from the MAC",
                  "value": {
                    "mac_address": "00:04:13:aa:bb:cc",
                    "model": "D785"
                  }
                },
                "dect_base": {
                  "summary": "Create a DECT base",
                  "value": {
                    "type": "dect_base",
                    "mac_address": "00:04:13:11:22:33",
                    "model": "M500"
                  }
                },
                "dect_handset": {
                  "summary": "Create a DECT handset",
                  "value": {
                    "type": "dect_handset",
                    "base": "01h2xcejqtf2nbrexx3vqjhp50",
                    "ipei": "123456789012345",
                    "name": "Front Desk"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Device created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateDeviceResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Parent DECT base not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Device creation conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/devices \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"type\":\"deskphone\",\"mac_address\":\"00:04:13:aa:bb:cc\",\"model\":\"D785\",\"name\":\"string\",\"overrides\":{\"abstractions\":{\"audio\":{\"codecs\":[\"PCMU\",\"PCMA\"],\"vad_enabled\":true,\"echo_cancellation\":true,\"jitter_buffer\":{\"mode\":\"adaptive\",\"min_ms\":40,\"max_ms\":200}},\"display\":{\"time_format\":\"12h\",\"date_format\":\"M/D/Y\",\"backlight_timeout\":30,\"backlight_level\":\"low\"},\"regional\":{\"timezone\":\"America/New_York\",\"language\":\"en-US\",\"tone_scheme\":\"us\"},\"network\":{\"vlan_id\":0,\"qos_dscp_sip\":26,\"qos_dscp_rtp\":46,\"rtcp_enabled\":true,\"sip_transport\":\"udp\"},\"features\":{\"dnd_enabled\":true,\"call_waiting_enabled\":true,\"call_forward_enabled\":true,\"auto_answer_enabled\":true,\"srtp_enabled\":true,\"call_waiting_dialtone_enabled\":true},\"provisioning\":{\"resync_time\":\"02:00\",\"resync_mode\":\"config_and_firmware\",\"bootup_check_enabled\":true}}},\"multicell_role\":\"single\",\"location\":\"loc_01h2xcejqtf2nbrexx3vqjhp40\",\"base\":\"dectb_01h2xcejqtf2nbrexx3vqjhp50\",\"ipei\":\"123456789012345\",\"display_name\":\"string\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/devices`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "get": {
        "summary": "List devices",
        "description": "**Recommended** way to list devices. Prefer this endpoint over\n`GET /v1/deskphones` and `GET /v1/dect-bases`.\n\nUnified view of devices (deskphones, DECT base stations, and DECT handsets).\nUse the optional `type` filter to return only one device type.\nUse `expand[]=users` to include device/user assignment metadata.\nResults are returned in reverse chronological order (newest first).\n",
        "operationId": "listDevices",
        "tags": [
          "Devices"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/DeviceTypeFilter"
          },
          {
            "name": "location",
            "in": "query",
            "description": "Return only devices assigned to this location. Covers desk phones\nand DECT bases; DECT handsets have no location of their own and are\nomitted. Useful for finding what blocks a location delete.\n",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `users`.\nNote `button_template` is only expandable on the single-device read\n(`GET /v1/devices/{id}`); the list returns `button_template_id` only.\n",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "users"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of devices",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Device"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/devices?type=SOME_STRING_VALUE&location=SOME_STRING_VALUE&limit=10&expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/devices`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/devices/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Device identifier",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "summary": "Get a device",
        "description": "**Recommended** way to fetch any device. Prefer this endpoint over\n`GET /v1/deskphones/{id}`, `GET /v1/dect-bases/{id}`, and\n`GET /v1/dect-bases/{id}/handsets/{handset_id}`.\n\nUnified view of a single device. Works for deskphones, DECT base stations, and DECT handsets.\n",
        "operationId": "getDevice",
        "tags": [
          "Devices"
        ],
        "parameters": [
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `users`, `button_template`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "users",
                  "button_template"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Device details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Device"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/DeviceNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/devices/%7Bid%7D?expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/devices/{id}`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Update a device",
        "description": "Update a device by ID. Works for deskphones, DECT base stations, and DECT handsets.\nDECT handset updates support `name`, `ipei`, and `model`.\n",
        "operationId": "updateDevice",
        "tags": [
          "Devices"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDeviceRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Device updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Device"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/DeviceNotFound"
          },
          "409": {
            "description": "Update conflicts with current device state — for example, pairing\na DECT handset with a base station that has no free slots.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceUserConflictResponse"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/devices/%7Bid%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"model\":\"string\",\"name\":\"string\",\"status\":\"pending-sync\",\"overrides\":{\"abstractions\":{\"audio\":{\"codecs\":[\"PCMU\",\"PCMA\"],\"vad_enabled\":true,\"echo_cancellation\":true,\"jitter_buffer\":{\"mode\":\"adaptive\",\"min_ms\":40,\"max_ms\":200}},\"display\":{\"time_format\":\"12h\",\"date_format\":\"M/D/Y\",\"backlight_timeout\":30,\"backlight_level\":\"low\"},\"regional\":{\"timezone\":\"America/New_York\",\"language\":\"en-US\",\"tone_scheme\":\"us\"},\"network\":{\"vlan_id\":0,\"qos_dscp_sip\":26,\"qos_dscp_rtp\":46,\"rtcp_enabled\":true,\"sip_transport\":\"udp\"},\"features\":{\"dnd_enabled\":true,\"call_waiting_enabled\":true,\"call_forward_enabled\":true,\"auto_answer_enabled\":true,\"srtp_enabled\":true,\"call_waiting_dialtone_enabled\":true},\"provisioning\":{\"resync_time\":\"02:00\",\"resync_mode\":\"config_and_firmware\",\"bootup_check_enabled\":true}}},\"ipei\":\"string\",\"display_name\":\"string\",\"location\":\"string\",\"base\":\"string\",\"button_template\":\"string\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/devices/{id}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "delete": {
        "summary": "Delete a device",
        "description": "**Recommended** way to delete any device. Prefer this endpoint over\n`DELETE /v1/deskphones/{id}`, `DELETE /v1/dect-bases/{id}`, and\n`DELETE /v1/dect-bases/{id}/handsets/{handset_id}`.\n\nDelete any device by its ID. Works for deskphones, DECT base stations, and DECT handsets.\n\nDeleting a deskphone removes all associated user assignments. Deleting a DECT base\nkeeps its handsets: they become unpaired (no base station) and can be paired with\nanother base station later. Their user assignments are preserved.\n",
        "operationId": "deleteDevice",
        "tags": [
          "Devices"
        ],
        "responses": {
          "204": {
            "description": "Device deleted"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/DeviceNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/devices/%7Bid%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/devices/{id}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/devices/{id}/compatible_button_templates": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Device identifier",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "summary": "List button templates compatible with a device",
        "description": "Returns a paginated list of the account's button templates that render\nat least one supported button on this device. Standard cursor\npagination applies.\n",
        "operationId": "listCompatibleButtonTemplates",
        "tags": [
          "Devices"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "Compatible button templates",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ButtonTemplate"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/DeviceNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/devices/%7Bid%7D/compatible_button_templates?limit=10' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/devices/{id}/compatible_button_templates`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/devices/{id}/buttons": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Device identifier",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "summary": "List effective device buttons",
        "description": "Returns the compatibility-filtered button set that will be sent to\nprovisioning for this device. Template buttons and per-device\noverrides are merged by position. The aggregate `compatibility`\nblock (including unsupported buttons) is returned on the parent\ndevice retrieve (`GET /v1/devices/{id}`).\n",
        "operationId": "listDeviceButtons",
        "tags": [
          "Devices"
        ],
        "responses": {
          "200": {
            "description": "Effective programmable buttons",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MaterializedButton"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/DeviceNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/devices/%7Bid%7D/buttons \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/devices/{id}/buttons`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/devices/{id}/button_overrides": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Device identifier",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "summary": "List device button overrides",
        "operationId": "listDeviceButtonOverrides",
        "tags": [
          "Devices"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "List of per-device button overrides",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/DeviceButtonOverride"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/DeviceNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/devices/%7Bid%7D/button_overrides?limit=10' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/devices/{id}/button_overrides`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Create a device button override",
        "operationId": "createDeviceButtonOverride",
        "tags": [
          "Devices"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDeviceButtonOverrideRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Device button override created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceButtonOverride"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/DeviceNotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/devices/%7Bid%7D/button_overrides \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"position\":1,\"suppressed\":false,\"label\":\"string\",\"type\":\"line\",\"target\":{\"user\":\"user_01h2xcejqtf2nbrexx3vqjhp42\"}}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/devices/{id}/button_overrides`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/devices/{id}/button_overrides/{override_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Device identifier",
          "schema": {
            "type": "string"
          }
        },
        {
          "$ref": "#/components/parameters/ButtonOverrideId"
        }
      ],
      "delete": {
        "summary": "Delete a device button override",
        "operationId": "deleteDeviceButtonOverride",
        "tags": [
          "Devices"
        ],
        "responses": {
          "204": {
            "description": "Device button override deleted"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/ButtonOverrideNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/devices/%7Bid%7D/button_overrides/devbtn_01h2xcejqtf2nbrexx3vqjhp72 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/devices/{id}/button_overrides/{override_id}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/deskphones": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "post": {
        "summary": "Create a deskphone",
        "deprecated": true,
        "description": "**Deprecated:** Use `POST /v1/devices` with `type: deskphone` instead.\n\nProvision a new deskphone. The vendor is auto-detected from the MAC address.\n",
        "operationId": "createDeskphone",
        "tags": [
          "Deskphones"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDeskphoneRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Create a deskphone",
                  "value": {
                    "mac_address": "00:04:13:aa:bb:cc",
                    "model": "D785"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Deskphone created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProvisionedDevice"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "description": "A device with this MAC address already exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/deskphones \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"mac_address\":\"00:04:13:aa:bb:cc\",\"model\":\"D785\",\"overrides\":{\"abstractions\":{\"audio\":{\"codecs\":[\"PCMU\",\"PCMA\"],\"vad_enabled\":true,\"echo_cancellation\":true,\"jitter_buffer\":{\"mode\":\"adaptive\",\"min_ms\":40,\"max_ms\":200}},\"display\":{\"time_format\":\"12h\",\"date_format\":\"M/D/Y\",\"backlight_timeout\":30,\"backlight_level\":\"low\"},\"regional\":{\"timezone\":\"America/New_York\",\"language\":\"en-US\",\"tone_scheme\":\"us\"},\"network\":{\"vlan_id\":0,\"qos_dscp_sip\":26,\"qos_dscp_rtp\":46,\"rtcp_enabled\":true,\"sip_transport\":\"udp\"},\"features\":{\"dnd_enabled\":true,\"call_waiting_enabled\":true,\"call_forward_enabled\":true,\"auto_answer_enabled\":true,\"srtp_enabled\":true,\"call_waiting_dialtone_enabled\":true},\"provisioning\":{\"resync_time\":\"02:00\",\"resync_mode\":\"config_and_firmware\",\"bootup_check_enabled\":true}}}}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/deskphones`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "get": {
        "summary": "List deskphones",
        "deprecated": true,
        "description": "**Deprecated:** Use `GET /v1/devices?type=deskphone` instead.\n\nList all deskphones for the account.\nResults are returned in reverse chronological order (newest first).\n",
        "operationId": "listDeskphones",
        "tags": [
          "Deskphones"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "List of deskphones",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ProvisionedDevice"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/deskphones?limit=10' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/deskphones`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/deskphones/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Deskphone identifier",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "summary": "Get a deskphone",
        "deprecated": true,
        "description": "**Deprecated:** Use `GET /v1/devices/{id}` instead.\n\nRetrieve a deskphone by its ID.\n",
        "operationId": "getDeskphone",
        "tags": [
          "Deskphones"
        ],
        "responses": {
          "200": {
            "description": "Deskphone details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProvisionedDevice"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/DeviceNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/deskphones/%7Bid%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/deskphones/{id}`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Update a deskphone",
        "description": "Update a deskphone's properties. Only provided fields are changed.\n",
        "operationId": "updateDeskphone",
        "tags": [
          "Deskphones"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDeskphoneRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Deskphone updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProvisionedDevice"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/DeviceNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/deskphones/%7Bid%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"model\":\"string\",\"status\":\"pending-sync\",\"overrides\":{\"abstractions\":{\"audio\":{\"codecs\":[\"PCMU\",\"PCMA\"],\"vad_enabled\":true,\"echo_cancellation\":true,\"jitter_buffer\":{\"mode\":\"adaptive\",\"min_ms\":40,\"max_ms\":200}},\"display\":{\"time_format\":\"12h\",\"date_format\":\"M/D/Y\",\"backlight_timeout\":30,\"backlight_level\":\"low\"},\"regional\":{\"timezone\":\"America/New_York\",\"language\":\"en-US\",\"tone_scheme\":\"us\"},\"network\":{\"vlan_id\":0,\"qos_dscp_sip\":26,\"qos_dscp_rtp\":46,\"rtcp_enabled\":true,\"sip_transport\":\"udp\"},\"features\":{\"dnd_enabled\":true,\"call_waiting_enabled\":true,\"call_forward_enabled\":true,\"auto_answer_enabled\":true,\"srtp_enabled\":true,\"call_waiting_dialtone_enabled\":true},\"provisioning\":{\"resync_time\":\"02:00\",\"resync_mode\":\"config_and_firmware\",\"bootup_check_enabled\":true}}}}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/deskphones/{id}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "delete": {
        "summary": "Delete a deskphone",
        "deprecated": true,
        "description": "**Deprecated:** Use `DELETE /v1/devices/{id}` instead.\n\nDelete a deskphone and all its associated lines.\n",
        "operationId": "deleteDeskphone",
        "tags": [
          "Deskphones"
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/DeviceDeleted"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/DeviceNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/deskphones/%7Bid%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/deskphones/{id}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/deskphones/{id}/provisioning-events": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Deskphone identifier",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "summary": "List provisioning events",
        "description": "List provisioning events for a deskphone. Returns a log of configuration\nfetches by the device.\n",
        "operationId": "listDeskphoneProvisioningEvents",
        "tags": [
          "Deskphones"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "List of provisioning events",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ProvisioningEvent"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/DeviceNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/deskphones/%7Bid%7D/provisioning-events?limit=10' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/deskphones/{id}/provisioning-events`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/devices/{id}/status/check-sync": {
      "post": {
        "summary": "Trigger device configuration reload",
        "description": "Tells the device to fetch and apply its latest configuration.\nWorks for deskphones, DECT bases, and DECT handsets — on a DECT\nsystem, one request reloads configuration on every handset paired\nwith the base.\n\nWith the default `reboot: false`, the device applies configuration\nin place. Active calls continue and the device stays registered.\nWith `reboot: true`, the device reboots immediately — any active\ncall is dropped, and the device is offline for about 30–90 seconds.\n\nTrigger check-sync when you actually change configuration, not on\nevery admin-UI interaction. See the [Device provisioning\nguide](https://docs.dialstack.ai/guides/device-provisioning) for\nthe full list of side effects.\n",
        "operationId": "deviceCheckSync",
        "tags": [
          "Devices"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/DialStackAccount"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Device identifier (deskphone, DECT base, or DECT handset)"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reboot": {
                    "type": "boolean",
                    "description": "If true, the device reboots immediately after applying\nconfig, interrupting any active call. Default `false`\nperforms a non-disruptive config reload.\n",
                    "default": false
                  }
                }
              },
              "examples": {
                "default": {
                  "summary": "Default (no reboot)",
                  "value": {}
                },
                "with_reboot": {
                  "summary": "With reboot — destructive, interrupts active calls",
                  "value": {
                    "reboot": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "At least one line accepted the request. Inspect `lines` for the\nper-line outcome — some lines may be `unreachable` or\n`not_registered` even when the overall request succeeds.\n",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "lines_notified",
                    "lines"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "lines_notified": {
                      "type": "integer",
                      "description": "Number of lines that accepted the request.",
                      "example": 1
                    },
                    "lines": {
                      "type": "array",
                      "description": "Per-line outcome. `line_number` is a 1-indexed\nidentifier; for deskphones it matches the physical\nline, for DECT it is a stable sequence within the\nresponse. A `line_number` of `0` with `management:\ntrue` denotes the device-level reprovision attempt\n(see `management`).\n",
                      "items": {
                        "type": "object",
                        "required": [
                          "line_number",
                          "status"
                        ],
                        "properties": {
                          "line_number": {
                            "type": "integer",
                            "example": 1
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "delivered",
                              "not_registered",
                              "unreachable",
                              "error"
                            ]
                          },
                          "management": {
                            "type": "boolean",
                            "description": "Present and `true` when this entry is the\ndevice-level reprovision attempt, used to reach\na device that has no assigned line yet (or has\nnot finished provisioning its line). `line_number`\nis `0` for this entry.\n",
                            "example": true
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid device ID or device has no SIP lines configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "invalid_id": {
                    "value": {
                      "error": "Invalid device ID"
                    }
                  },
                  "no_lines": {
                    "value": {
                      "error": "Device has no SIP lines configured"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Device not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Device not found"
                }
              }
            }
          },
          "409": {
            "description": "The device could not be reached. The `reason` field tells you why:\n\n- `not_registered` — the device has no active registration. It\n  may be powered off, unable to reach the SIP server, or has\n  never registered.\n- `unreachable` — the device didn't respond in time. It is\n  likely offline or has lost its connection.\n",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "reason"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "reason": {
                      "type": "string",
                      "enum": [
                        "not_registered",
                        "unreachable"
                      ]
                    }
                  }
                },
                "examples": {
                  "not_registered": {
                    "value": {
                      "error": "Device is not registered - phone may be offline",
                      "reason": "not_registered"
                    }
                  },
                  "unreachable": {
                    "value": {
                      "error": "Device did not respond - it may be offline",
                      "reason": "unreachable"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Check-sync not available in this environment",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Check-sync not available in this environment"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/devices/%7Bid%7D/status/check-sync \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"reboot\":false}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/devices/{id}/status/check-sync`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'DialStack-Account': 'acct_...',\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/devices/{id}/users": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Device identifier (deskphone, DECT handset, or DECT base)",
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "summary": "Assign a user to a device",
        "description": "Assigns a user to a device. SIP credentials and line configuration are created automatically.\n\nSupported device types:\n- **Deskphones** — assigns the user to the next available line key (max 24)\n- **DECT handsets** — assigns the user to the handset (max 24)\n- **DECT bases** — not supported (returns 400); assign to individual handsets instead\n",
        "operationId": "assignUserToDevice",
        "tags": [
          "Devices"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AssignUserToDeviceRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Assign a user to a deskphone",
                  "value": {
                    "user": "user_01h2xcejqtf2nbrexx3vqjhp42"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "User assigned to deskphone",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceUserAssignment"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/DeviceNotFound"
          },
          "409": {
            "description": "Conflict. The user is already on this device, on a different\ndevice (one-device-per-user), or the device is full.\nClients should branch on `code`; `existing_device` is\npresent when `code` is `user_already_has_device` and points\nat the device the user is currently bound to.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceUserConflictResponse"
                },
                "examples": {
                  "already_assigned": {
                    "value": {
                      "error": "user is already assigned to this device",
                      "code": "user_already_assigned"
                    }
                  },
                  "user_already_has_device": {
                    "value": {
                      "error": "user is already assigned to another device",
                      "code": "user_already_has_device",
                      "existing_device": "dev_01h2xcejqtf2nbrexx3vqjhp40"
                    }
                  },
                  "user_already_has_endpoint": {
                    "value": {
                      "error": "user already has an active endpoint",
                      "code": "user_already_has_endpoint"
                    }
                  },
                  "handset_already_assigned": {
                    "value": {
                      "error": "handset already has an assigned user",
                      "code": "handset_already_assigned"
                    }
                  },
                  "max_lines": {
                    "value": {
                      "error": "device has reached the maximum of 24 lines",
                      "code": "device_full"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/devices/%7Bid%7D/users \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"user\":\"01h2xcejqtf2nbrexx3vqjhp42\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/devices/{id}/users`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "get": {
        "summary": "List users assigned to a device",
        "description": "Returns all users currently assigned to the device.\nDevices support at most 24 users, so no pagination is needed.\n",
        "operationId": "listDeviceUsers",
        "tags": [
          "Devices"
        ],
        "responses": {
          "200": {
            "description": "List of assigned users",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string",
                      "enum": [
                        "list"
                      ]
                    },
                    "url": {
                      "type": "string"
                    },
                    "next_page_url": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "previous_page_url": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/DeviceUserAssignment"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/DeviceNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/devices/%7Bid%7D/users \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/devices/{id}/users`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/devices/{id}/users/{user_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Device identifier (deskphone, DECT handset, or DECT base)",
          "schema": {
            "type": "string"
          }
        },
        {
          "$ref": "#/components/parameters/UserId"
        }
      ],
      "delete": {
        "summary": "Remove a user from a device",
        "description": "Removes the user's assignment from the device.\nThe associated SIP credentials and line configuration are cleaned up automatically.\n",
        "operationId": "removeUserFromDevice",
        "tags": [
          "Devices"
        ],
        "responses": {
          "204": {
            "description": "User removed from deskphone"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Device not found or user is not assigned to this device",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/devices/%7Bid%7D/users/user_01h2xcejqtf2nbrexx3vqjhp42 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/devices/{id}/users/{user_id}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/deskphones/{id}/lines": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Deskphone identifier",
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "summary": "Create a deskphone line",
        "deprecated": true,
        "description": "**Deprecated:** Use `POST /v1/devices/{id}/users` instead.\n\nAssigns a SIP endpoint to the next available line key on the deskphone.\nThe line number is automatically assigned as the lowest unused number (1-24).\nA deskphone supports a maximum of 24 lines. Each endpoint can only be assigned once per device.\n",
        "operationId": "createDeskphoneLine",
        "tags": [
          "Deskphones"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDeviceLineRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Assign an endpoint to a line",
                  "value": {
                    "endpoint": "ep_01h2xcejqtf2nbrexx3vqjhp43"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Device line created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceLine"
                },
                "examples": {
                  "success": {
                    "summary": "Successful line creation",
                    "value": {
                      "id": "dln_01h2xcejqtf2nbrexx3vqjhp55",
                      "device": "dev_01h2xcejqtf2nbrexx3vqjhp50",
                      "endpoint": "ep_01h2xcejqtf2nbrexx3vqjhp43",
                      "line_number": 1,
                      "created_at": "2025-10-18T10:00:00Z",
                      "updated_at": "2025-10-18T10:00:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/DeviceNotFound"
          },
          "409": {
            "description": "Conflict (endpoint already assigned or maximum lines reached)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "duplicate_endpoint": {
                    "value": {
                      "error": "Endpoint is already assigned to this device"
                    }
                  },
                  "max_lines": {
                    "value": {
                      "error": "Device has reached the maximum of 24 lines"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/deskphones/%7Bid%7D/lines \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"endpoint\":\"ep_01h2xcejqtf2nbrexx3vqjhp43\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/deskphones/{id}/lines`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "get": {
        "summary": "List deskphone lines",
        "deprecated": true,
        "description": "**Deprecated:** Use `GET /v1/devices/{id}/users` instead.\n\nList all SIP line assignments for a deskphone.\nReturns lines ordered by line number.\n",
        "operationId": "listDeskphoneLines",
        "tags": [
          "Deskphones"
        ],
        "responses": {
          "200": {
            "description": "List of device lines",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/DeviceLine"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/DeviceNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/deskphones/%7Bid%7D/lines \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/deskphones/{id}/lines`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/deskphones/{id}/lines/{line_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Deskphone identifier",
          "schema": {
            "type": "string"
          }
        },
        {
          "$ref": "#/components/parameters/DeviceLineId"
        }
      ],
      "post": {
        "summary": "Update a deskphone line",
        "deprecated": true,
        "description": "**Deprecated:** Use `DELETE /v1/devices/{id}/users/{user_id}` and `POST /v1/devices/{id}/users` instead.\n\nReassigns a deskphone line to a different SIP endpoint.\nThe line number remains unchanged; only the endpoint is updated.\n",
        "operationId": "updateDeskphoneLine",
        "tags": [
          "Deskphones"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDeviceLineRequest"
              },
              "examples": {
                "reassign": {
                  "summary": "Reassign to a different endpoint",
                  "value": {
                    "endpoint": "ep_01h2xcejqtf2nbrexx3vqjhp44"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Device line updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceLine"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/DeviceLineNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/deskphones/%7Bid%7D/lines/dln_01h2xcejqtf2nbrexx3vqjhp55 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"endpoint\":\"ep_01h2xcejqtf2nbrexx3vqjhp44\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/deskphones/{id}/lines/{line_id}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "delete": {
        "summary": "Delete a deskphone line",
        "deprecated": true,
        "description": "**Deprecated:** Use `DELETE /v1/devices/{id}/users/{user_id}` instead.\n\nRemoves a SIP line assignment from the deskphone.\n",
        "operationId": "deleteDeskphoneLine",
        "tags": [
          "Deskphones"
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/DeviceLineDeleted"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/DeviceLineNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/deskphones/%7Bid%7D/lines/dln_01h2xcejqtf2nbrexx3vqjhp55 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/deskphones/{id}/lines/{line_id}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/dect-bases": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "post": {
        "summary": "Create a DECT base station",
        "deprecated": true,
        "description": "**Deprecated:** Use `POST /v1/devices` with `type: dect_base` instead.\n\nRegister a new DECT base station for provisioning.\nThe vendor is automatically detected from the MAC address.\n",
        "operationId": "createDECTBase",
        "tags": [
          "DECT Bases"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDECTBaseRequest"
              },
              "examples": {
                "standalone": {
                  "summary": "Standalone base station",
                  "value": {
                    "mac_address": "00:04:13:bb:cc:dd"
                  }
                },
                "multicell_secondary": {
                  "summary": "Secondary base in multicell deployment",
                  "value": {
                    "mac_address": "00:04:13:bb:cc:ee",
                    "multicell_role": "secondary"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "DECT base created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DECTBase"
                },
                "examples": {
                  "success": {
                    "summary": "Successful creation",
                    "value": {
                      "id": "dectb_01h2xcejqtf2nbrexx3vqjhp60",
                      "mac_address": "00:04:13:bb:cc:dd",
                      "vendor": "snom",
                      "model": null,
                      "status": "pending-sync",
                      "multicell_role": "single",
                      "max_handsets": 30,
                      "created_at": "2025-10-18T10:00:00Z",
                      "updated_at": "2025-10-18T10:00:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "description": "A device with this MAC address already exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "A device with this MAC address already exists"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/dect-bases \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"mac_address\":\"00:04:13:bb:cc:dd\",\"model\":\"M500\",\"multicell_role\":\"single\",\"overrides\":{\"abstractions\":{\"audio\":{\"codecs\":[\"PCMU\",\"PCMA\"],\"vad_enabled\":true,\"echo_cancellation\":true,\"jitter_buffer\":{\"mode\":\"adaptive\",\"min_ms\":40,\"max_ms\":200}},\"display\":{\"time_format\":\"12h\",\"date_format\":\"M/D/Y\",\"backlight_timeout\":30,\"backlight_level\":\"low\"},\"regional\":{\"timezone\":\"America/New_York\",\"language\":\"en-US\",\"tone_scheme\":\"us\"},\"network\":{\"vlan_id\":0,\"qos_dscp_sip\":26,\"qos_dscp_rtp\":46,\"rtcp_enabled\":true,\"sip_transport\":\"udp\"},\"features\":{\"dnd_enabled\":true,\"call_waiting_enabled\":true,\"call_forward_enabled\":true,\"auto_answer_enabled\":true,\"srtp_enabled\":true,\"call_waiting_dialtone_enabled\":true},\"provisioning\":{\"resync_time\":\"02:00\",\"resync_mode\":\"config_and_firmware\",\"bootup_check_enabled\":true}}}}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/dect-bases`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "get": {
        "summary": "List DECT base stations",
        "deprecated": true,
        "description": "**Deprecated:** Use `GET /v1/devices?type=dect_base` instead.\n\nList all DECT base stations in the account.\n",
        "operationId": "listDECTBases",
        "tags": [
          "DECT Bases"
        ],
        "responses": {
          "200": {
            "description": "List of DECT base stations",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/DECTBase"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/dect-bases \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/dect-bases`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/dect-bases/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "DECT base station identifier",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "summary": "Get a DECT base station",
        "deprecated": true,
        "description": "**Deprecated:** Use `GET /v1/devices/{id}` instead.\n\nRetrieve a DECT base station by ID.\n",
        "operationId": "getDECTBase",
        "tags": [
          "DECT Bases"
        ],
        "responses": {
          "200": {
            "description": "DECT base station details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DECTBase"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "DECT base not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "DECT base not found"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/dect-bases/%7Bid%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/dect-bases/{id}`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Update a DECT base station",
        "description": "Update properties of a DECT base station.\n",
        "operationId": "updateDECTBase",
        "tags": [
          "DECT Bases"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDECTBaseRequest"
              },
              "examples": {
                "update_role": {
                  "summary": "Change multicell role",
                  "value": {
                    "multicell_role": "data_master"
                  }
                },
                "update_overrides": {
                  "summary": "Set device overrides",
                  "value": {
                    "overrides": {
                      "abstractions": {
                        "regional": {
                          "timezone": "America/Toronto",
                          "language": "fr-CA"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "DECT base updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DECTBase"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "DECT base not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "DECT base not found"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/dect-bases/%7Bid%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"model\":\"string\",\"status\":\"pending-sync\",\"multicell_role\":\"single\",\"overrides\":{\"abstractions\":{\"audio\":{\"codecs\":[\"PCMU\",\"PCMA\"],\"vad_enabled\":true,\"echo_cancellation\":true,\"jitter_buffer\":{\"mode\":\"adaptive\",\"min_ms\":40,\"max_ms\":200}},\"display\":{\"time_format\":\"12h\",\"date_format\":\"M/D/Y\",\"backlight_timeout\":30,\"backlight_level\":\"low\"},\"regional\":{\"timezone\":\"America/New_York\",\"language\":\"en-US\",\"tone_scheme\":\"us\"},\"network\":{\"vlan_id\":0,\"qos_dscp_sip\":26,\"qos_dscp_rtp\":46,\"rtcp_enabled\":true,\"sip_transport\":\"udp\"},\"features\":{\"dnd_enabled\":true,\"call_waiting_enabled\":true,\"call_forward_enabled\":true,\"auto_answer_enabled\":true,\"srtp_enabled\":true,\"call_waiting_dialtone_enabled\":true},\"provisioning\":{\"resync_time\":\"02:00\",\"resync_mode\":\"config_and_firmware\",\"bootup_check_enabled\":true}}}}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/dect-bases/{id}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "delete": {
        "summary": "Delete a DECT base station",
        "deprecated": true,
        "description": "**Deprecated:** Use `DELETE /v1/devices/{id}` instead.\n\nDelete a DECT base station and all associated handsets and extensions.\n",
        "operationId": "deleteDECTBase",
        "tags": [
          "DECT Bases"
        ],
        "responses": {
          "204": {
            "description": "DECT base deleted"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "DECT base not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "DECT base not found"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/dect-bases/%7Bid%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/dect-bases/{id}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/dect-bases/{id}/handsets": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "DECT base station identifier",
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "summary": "Add a handset to a DECT base",
        "deprecated": true,
        "description": "**Deprecated:** Use `POST /v1/devices` with `type: dect_handset` and\n`base` set to the DECT base identifier instead.\n\nPair a new wireless handset with a DECT base station.\nThe slot number is automatically assigned as the lowest available slot.\nIPEI (International Portable Equipment Identity) is a unique hardware identifier\nfor wireless handsets, formatted as a hexadecimal string up to 20 characters.\n",
        "operationId": "createDECTHandset",
        "tags": [
          "DECT Bases"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateHandsetRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Add a handset",
                  "value": {
                    "ipei": "0328A0000F",
                    "display_name": "Front Desk"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Handset created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DECTHandset"
                },
                "examples": {
                  "success": {
                    "summary": "Handset paired with base",
                    "value": {
                      "id": "decth_01h2xcejqtf2nbrexx3vqjhp70",
                      "base": "dectb_01h2xcejqtf2nbrexx3vqjhp60",
                      "ipei": "0328A0000F",
                      "status": "pending-sync",
                      "display_name": "Front Desk",
                      "slot_number": 1,
                      "created_at": "2025-10-18T10:00:00Z",
                      "updated_at": "2025-10-18T10:00:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "DECT base not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "DECT base not found"
                }
              }
            }
          },
          "409": {
            "description": "Handset limit reached or IPEI already exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "max_handsets": {
                    "value": {
                      "error": "Base station has reached the maximum number of handsets"
                    }
                  },
                  "duplicate_ipei": {
                    "value": {
                      "error": "A handset with this IPEI already exists on this base"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/dect-bases/%7Bid%7D/handsets \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"ipei\":\"0328A0000F\",\"display_name\":\"string\",\"model\":\"string\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/dect-bases/{id}/handsets`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "get": {
        "summary": "List handsets on a DECT base",
        "description": "List all wireless handsets paired with a DECT base station.\n",
        "operationId": "listDECTHandsets",
        "tags": [
          "DECT Bases"
        ],
        "responses": {
          "200": {
            "description": "List of handsets",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/DECTHandset"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/dect-bases/%7Bid%7D/handsets \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/dect-bases/{id}/handsets`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/dect-bases/{id}/handsets/{handset_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "DECT base station identifier",
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "handset_id",
          "in": "path",
          "required": true,
          "description": "Handset identifier",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "summary": "Get a handset",
        "deprecated": true,
        "description": "**Deprecated:** Use `GET /v1/devices/{id}` with the handset ID instead.\n\nRetrieve a specific handset.\n",
        "operationId": "getDECTHandset",
        "tags": [
          "DECT Bases"
        ],
        "responses": {
          "200": {
            "description": "Handset details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DECTHandset"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Handset not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Handset not found"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/dect-bases/%7Bid%7D/handsets/%7Bhandset_id%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/dect-bases/{id}/handsets/{handset_id}`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Update a handset",
        "description": "Update handset properties such as IPEI, display name, or model.\n\nHandsets never provision, so the `model` can't be auto-detected — set it\nhere to unlock programmable-button (template) support.\n",
        "operationId": "updateDECTHandset",
        "tags": [
          "DECT Bases"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateHandsetRequest"
              },
              "examples": {
                "update_name": {
                  "summary": "Update display name",
                  "value": {
                    "display_name": "Warehouse"
                  }
                },
                "update_model": {
                  "summary": "Set the handset model",
                  "value": {
                    "model": "M55"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Handset updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DECTHandset"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Handset not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Handset not found"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/dect-bases/%7Bid%7D/handsets/%7Bhandset_id%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"ipei\":\"string\",\"display_name\":\"string\",\"model\":\"string\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/dect-bases/{id}/handsets/{handset_id}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "delete": {
        "summary": "Delete a handset",
        "deprecated": true,
        "description": "**Deprecated:** Use `DELETE /v1/devices/{id}` with the handset ID instead.\n\nRemove a handset from a DECT base station.\nAll extensions on the handset are also removed.\n",
        "operationId": "deleteDECTHandset",
        "tags": [
          "DECT Bases"
        ],
        "responses": {
          "204": {
            "description": "Handset deleted"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Handset not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Handset not found"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/dect-bases/%7Bid%7D/handsets/%7Bhandset_id%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/dect-bases/{id}/handsets/{handset_id}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/dect-bases/{id}/handsets/{handset_id}/extensions": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "DECT base station identifier",
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "handset_id",
          "in": "path",
          "required": true,
          "description": "Handset identifier",
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "summary": "Assign an extension to a handset",
        "deprecated": true,
        "description": "**Deprecated:** Use `POST /v1/devices/{id}/users` with the handset ID instead.\n\nAssign a SIP endpoint to a DECT handset as an extension (SIP line).\n",
        "operationId": "createDECTExtension",
        "tags": [
          "DECT Bases"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateHandsetLineRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Assign a SIP endpoint",
                  "value": {
                    "endpoint": "ep_01h2xcejqtf2nbrexx3vqjhp43"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Extension created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HandsetLine"
                },
                "examples": {
                  "success": {
                    "summary": "Extension assigned",
                    "value": {
                      "id": "decte_01h2xcejqtf2nbrexx3vqjhp80",
                      "handset": "decth_01h2xcejqtf2nbrexx3vqjhp70",
                      "endpoint": "ep_01h2xcejqtf2nbrexx3vqjhp43",
                      "display_name": null,
                      "created_at": "2025-10-18T10:00:00Z",
                      "updated_at": "2025-10-18T10:00:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Handset not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Handset not found"
                }
              }
            }
          },
          "409": {
            "description": "Endpoint already assigned to this handset",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Endpoint is already assigned to this handset"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/dect-bases/%7Bid%7D/handsets/%7Bhandset_id%7D/extensions \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"endpoint\":\"string\",\"display_name\":\"string\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/dect-bases/{id}/handsets/{handset_id}/extensions`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "get": {
        "summary": "List extensions on a handset",
        "deprecated": true,
        "description": "**Deprecated:** Use `GET /v1/devices/{id}/users` with the handset ID instead.\n\nList all SIP line assignments on a DECT handset.\n",
        "operationId": "listDECTExtensions",
        "tags": [
          "DECT Bases"
        ],
        "responses": {
          "200": {
            "description": "List of extensions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/HandsetLine"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Handset not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Handset not found"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/dect-bases/%7Bid%7D/handsets/%7Bhandset_id%7D/extensions \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/dect-bases/{id}/handsets/{handset_id}/extensions`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/dect-bases/{id}/handsets/{handset_id}/extensions/{extension_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "DECT base station identifier",
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "handset_id",
          "in": "path",
          "required": true,
          "description": "Handset identifier",
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "extension_id",
          "in": "path",
          "required": true,
          "description": "Extension identifier",
          "schema": {
            "type": "string"
          }
        }
      ],
      "delete": {
        "summary": "Remove an extension from a handset",
        "deprecated": true,
        "description": "**Deprecated:** Use `DELETE /v1/devices/{id}/users/{user_id}` with the handset ID instead.\n\nRemove a SIP line assignment from a DECT handset.\n",
        "operationId": "deleteDECTExtension",
        "tags": [
          "DECT Bases"
        ],
        "responses": {
          "204": {
            "description": "Extension removed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Extension not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Extension not found"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/dect-bases/%7Bid%7D/handsets/%7Bhandset_id%7D/extensions/%7Bextension_id%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/dect-bases/{id}/handsets/{handset_id}/extensions/{extension_id}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/locations": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "post": {
        "summary": "Create a location",
        "description": "Create a new business location with a validated address.\n",
        "operationId": "createLocation",
        "tags": [
          "Locations"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateLocationRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Create main office",
                  "value": {
                    "name": "Main Office",
                    "address": {
                      "street": "123 Main St",
                      "city": "New York",
                      "state": "NY",
                      "postal_code": "10001",
                      "country": "US"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Location created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Location"
                },
                "examples": {
                  "success": {
                    "summary": "Successful location creation",
                    "value": {
                      "id": "loc_01h2xcejqtf2nbrexx3vqjhp50",
                      "name": "Main Office",
                      "address": {
                        "city": "New York",
                        "state": "NY",
                        "postal_code": "10001",
                        "country": "US",
                        "formatted_address": "123 Main St, New York, NY 10001, US"
                      },
                      "status": "active",
                      "e911_status": "none",
                      "created_at": "2025-10-18T10:00:00Z",
                      "updated_at": "2025-10-18T10:00:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/locations \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"name\":\"Main Office\",\"address\":{\"address_number\":\"1600\",\"street\":\"Pennsylvania Avenue NW\",\"unit\":\"Suite 200\",\"city\":\"New York\",\"state\":\"NY\",\"postal_code\":\"10001\",\"country\":\"US\"},\"primary_did\":\"string\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/locations`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "get": {
        "summary": "List locations",
        "description": "List all locations for the account.\nResults are returned in reverse chronological order (newest first).\n",
        "operationId": "listLocations",
        "tags": [
          "Locations"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/LocationStatus"
          }
        ],
        "responses": {
          "200": {
            "description": "List of locations",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Location"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                },
                "examples": {
                  "list": {
                    "summary": "Location list response",
                    "value": {
                      "object": "list",
                      "url": "/v1/locations",
                      "next_page_url": null,
                      "previous_page_url": null,
                      "data": [
                        {
                          "id": "loc_01h2xcejqtf2nbrexx3vqjhp50",
                          "name": "Main Office",
                          "address": {
                            "city": "New York",
                            "state": "NY",
                            "postal_code": "10001",
                            "country": "US",
                            "formatted_address": "123 Main St, New York, NY 10001, US"
                          },
                          "status": "active",
                          "e911_status": "none",
                          "created_at": "2025-10-18T10:00:00Z",
                          "updated_at": "2025-10-18T10:00:00Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/locations?limit=10&status=active' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/locations`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/locations/{location_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/LocationId"
        }
      ],
      "get": {
        "summary": "Get location details",
        "description": "Retrieve a specific location by ID.\n",
        "operationId": "getLocation",
        "tags": [
          "Locations"
        ],
        "responses": {
          "200": {
            "description": "Location details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Location"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/LocationNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/locations/loc_01h2xcejqtf2nbrexx3vqjhp50 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/locations/{location_id}`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Update location",
        "description": "Update location details. Changing the address revalidates it and\nupdates the E911 registration for the location.\n",
        "operationId": "updateLocation",
        "tags": [
          "Locations"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateLocationRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Location updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Location"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/LocationNotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/locations/loc_01h2xcejqtf2nbrexx3vqjhp50 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"name\":\"Updated Office\",\"address\":{\"address_number\":\"1600\",\"street\":\"Pennsylvania Avenue NW\",\"unit\":\"Suite 200\",\"city\":\"New York\",\"state\":\"NY\",\"postal_code\":\"10001\",\"country\":\"US\"},\"primary_did\":\"string\",\"status\":\"active\",\"config\":{\"e911_notification\":{\"emails\":[\"security@example.com\",\"frontdesk@example.com\"]}}}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/locations/{location_id}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "delete": {
        "summary": "Delete location",
        "description": "Delete a location and its associated address.\n\nThe delete is refused with `409` (`code: location_in_use`) while the\nlocation is still in use — either it is the account's main location, or\na device (desk phone, DECT base), an open hardware order, or a\nregistered directory listing still references it. Reassign or remove\nthose first, then retry. To find what references a location, use the\n`location` filter on `GET /v1/devices` and `GET /v1/hardware-orders`.\n",
        "operationId": "deleteLocation",
        "tags": [
          "Locations"
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/LocationDeleted"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/LocationNotFound"
          },
          "409": {
            "description": "The location cannot be deleted because it is still in use — it is\nthe account's main location, or a device (desk phone, DECT base),\nan open hardware order, or a registered directory listing still\nreferences it. For a referenced location the response body carries\n`code: location_in_use`; use the `location` filter on\n`GET /v1/devices` and `GET /v1/hardware-orders` to find the\nreferences, then reassign or remove them and retry.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/locations/loc_01h2xcejqtf2nbrexx3vqjhp50 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/locations/{location_id}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/locations/{location_id}/validate-e911": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/LocationId"
        }
      ],
      "post": {
        "summary": "Validate E911 address",
        "description": "Pre-check the location's address for E911 provisioning.\nReturns the address fields that will be used during provisioning. Full address validation\noccurs during the provision-e911 call.\n",
        "operationId": "validateLocationE911",
        "tags": [
          "Locations"
        ],
        "responses": {
          "200": {
            "description": "Address validation result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/E911ValidationResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/LocationNotFound"
          },
          "502": {
            "description": "Upstream provider address validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/locations/loc_01h2xcejqtf2nbrexx3vqjhp50/validate-e911 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/locations/{location_id}/validate-e911`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/locations/{location_id}/provision-e911": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/LocationId"
        }
      ],
      "post": {
        "summary": "Provision E911",
        "description": "Start E911 provisioning for a location.\nThe location must have a valid, validated address. A phone number\nassignment is not required.\nProvisioning is asynchronous; the `e911_status` field tracks progress.\n",
        "operationId": "provisionLocationE911",
        "tags": [
          "Locations"
        ],
        "responses": {
          "200": {
            "description": "E911 provisioning started",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Location"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request: the emergency address could not be validated by the carrier.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/LocationNotFound"
          },
          "502": {
            "description": "Upstream provider order failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/locations/loc_01h2xcejqtf2nbrexx3vqjhp50/provision-e911 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/locations/{location_id}/provision-e911`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/quality/summary": {
      "get": {
        "summary": "Get quality metrics summary",
        "description": "Returns aggregated call quality metrics for the account, including\nKPI averages (MOS, jitter, packet loss) and a time-bucketed series.\nMOS is computed using the ITU-T G.107 E-model.\n",
        "operationId": "getQualitySummary",
        "tags": [
          "Quality"
        ],
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "description": "Start of time range (RFC 3339)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "description": "End of time range (RFC 3339)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "granularity",
            "in": "query",
            "required": true,
            "description": "Time bucket granularity",
            "schema": {
              "type": "string",
              "enum": [
                "hourly",
                "daily"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Quality summary with KPIs and time series",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "kpi": {
                      "type": "object",
                      "properties": {
                        "avg_mos": {
                          "type": [
                            "number",
                            "null"
                          ],
                          "description": "Average MOS score (1.0–5.0)"
                        },
                        "avg_jitter_ms": {
                          "type": [
                            "number",
                            "null"
                          ],
                          "description": "Average jitter in milliseconds"
                        },
                        "avg_packet_loss_pct": {
                          "type": [
                            "number",
                            "null"
                          ],
                          "description": "Average packet loss percentage"
                        },
                        "total_calls": {
                          "type": "integer",
                          "description": "Total number of answered calls with quality data"
                        }
                      }
                    },
                    "time_series": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "bucket": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "avg_mos": {
                            "type": [
                              "number",
                              "null"
                            ]
                          },
                          "call_count": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/quality/summary?from=SOME_STRING_VALUE&to=SOME_STRING_VALUE&granularity=SOME_STRING_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/quality/summary`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/quality/worst-calls": {
      "get": {
        "summary": "Get worst quality calls",
        "description": "Returns the calls with the lowest MOS scores in the given time range,\nsorted by MOS ascending (worst first). Limited to 90-day range.\n",
        "operationId": "getQualityWorstCalls",
        "tags": [
          "Quality"
        ],
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "description": "Start of time range (RFC 3339)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "description": "End of time range (RFC 3339)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of calls to return (default 10, max 50)",
            "schema": {
              "type": "integer",
              "default": 10,
              "maximum": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of worst quality calls",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "calls": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "description": "Call record ID"
                          },
                          "started_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "direction": {
                            "type": "string",
                            "enum": [
                              "inbound",
                              "outbound",
                              "internal"
                            ]
                          },
                          "from_number": {
                            "type": "string"
                          },
                          "to_number": {
                            "type": "string"
                          },
                          "duration_seconds": {
                            "type": "integer"
                          },
                          "mos": {
                            "type": "number",
                            "description": "MOS score (1.0–5.0)"
                          },
                          "jitter_ms": {
                            "type": "number"
                          },
                          "packet_loss_pct": {
                            "type": "number"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/quality/worst-calls?from=SOME_STRING_VALUE&to=SOME_STRING_VALUE&limit=SOME_INTEGER_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/quality/worst-calls`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/quality/device-registrations": {
      "get": {
        "summary": "Get device registration status",
        "description": "Returns the registration status of all endpoints in the account,\nincluding whether each device is currently online or offline and\nits public IP address when available.\n",
        "operationId": "getDeviceRegistrations",
        "tags": [
          "Quality"
        ],
        "responses": {
          "200": {
            "description": "List of device registration statuses",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "devices": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "description": "Endpoint ID"
                          },
                          "name": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Endpoint display name"
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "online",
                              "offline"
                            ],
                            "description": "Current registration status"
                          },
                          "public_ip": {
                            "type": "string",
                            "description": "Public IP address of the device (when online)"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/quality/device-registrations \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/quality/device-registrations`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/catalog": {
      "get": {
        "summary": "List hardware catalog",
        "description": "Returns the list of active hardware items available for selection during onboarding.\nThis endpoint does not require account context.\n",
        "operationId": "listCatalog",
        "tags": [
          "Catalog"
        ],
        "responses": {
          "200": {
            "description": "List of active hardware catalog items",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string",
                      "example": "list"
                    },
                    "url": {
                      "type": "string",
                      "example": "/v1/catalog"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/HardwareCatalogItem"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/catalog \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/catalog`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/hardware-orders": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "post": {
        "summary": "Create hardware order",
        "description": "Creates a new hardware order with the given items and submits it for\nreview. Each item references a hardware catalog entry with a quantity.\n\nAn order may contain at most 10 distinct line items. Requests that\nexceed this limit are rejected with `400`.\n",
        "operationId": "createHardwareOrder",
        "tags": [
          "Hardware Orders"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HardwareOrderRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Hardware order created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HardwareOrder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/hardware-orders \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"items\":[{\"hardware_catalog\":\"string\",\"quantity\":1}]}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/hardware-orders`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "get": {
        "summary": "List hardware orders",
        "description": "Returns all hardware orders for the account, including embedded items.\n",
        "operationId": "listHardwareOrders",
        "tags": [
          "Hardware Orders"
        ],
        "parameters": [
          {
            "name": "location",
            "in": "query",
            "description": "Return only orders with a unit staged to this location. Useful for\nfinding which orders block a location delete.\n",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `items.device`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "items.device"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of hardware orders",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string",
                      "example": "list"
                    },
                    "url": {
                      "type": "string",
                      "example": "/v1/hardware-orders"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/HardwareOrder"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/hardware-orders?location=SOME_STRING_VALUE&expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/hardware-orders`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/hardware-orders/{order_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "get": {
        "summary": "Get hardware order",
        "description": "Returns a hardware order by ID, including embedded items.\n",
        "operationId": "getHardwareOrder",
        "tags": [
          "Hardware Orders"
        ],
        "parameters": [
          {
            "name": "order_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `items.device`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "items.device"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Hardware order details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HardwareOrder"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/HardwareOrderNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/hardware-orders/%7Border_id%7D?expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/hardware-orders/{order_id}`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Update hardware order items",
        "description": "Replaces all items on a draft order. The order must be in draft\nstatus; orders are currently submitted as soon as they are created,\nso this returns a conflict until a draft flow exists. To change a\nsubmitted order, contact DialStack — items can be adjusted during\nreview.\n\nSends the complete desired state of items — existing items are\nreplaced atomically.\n\nAn order may contain at most 10 distinct line items. Requests that\nexceed this limit are rejected with `400`.\n",
        "operationId": "updateHardwareOrder",
        "tags": [
          "Hardware Orders"
        ],
        "parameters": [
          {
            "name": "order_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HardwareOrderRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Hardware order updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HardwareOrder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/HardwareOrderNotFound"
          },
          "409": {
            "description": "Order is not in draft status"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/hardware-orders/%7Border_id%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"items\":[{\"hardware_catalog\":\"string\",\"quantity\":1}]}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/hardware-orders/{order_id}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/hardware-orders/{order_id}/items/{item_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "post": {
        "summary": "Update pre-staging intents on a hardware order item",
        "description": "Updates the pre-staging intents on a single unit of an order — the\nuser and/or physical location the unit is destined for once it ships.\nFields are tri-state: an omitted field is unchanged, `null` clears\nthe intent, and a value sets it. At least one field must be provided.\n\nIntents are applied to the real device record when the unit is\nfulfilled. Updates are allowed while the order is in `draft`,\n`submitted`, or `approved` status. `user` only applies to hardware\ntypes that support user assignment (deskphones and DECT handsets —\nnot base stations); `location` applies to deskphones and DECT\nbases — handsets inherit location from their paired base.\n\nA user can only be pre-assigned if they're available — they must not\nalready have a device or be pre-assigned to another ordered unit\n(one pending device per user, mirroring the assignment rule on real\ndevices). Otherwise the request is rejected with `409`.\n",
        "operationId": "assignHardwareOrderItem",
        "tags": [
          "Hardware Orders"
        ],
        "parameters": [
          {
            "name": "order_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "item_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "user": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "User to assign the unit to; null clears the assignment"
                  },
                  "location": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Location to stage the unit for; null clears it. Not valid on DECT handsets — they inherit location from their base."
                  },
                  "base_item": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Ordered base unit to pair this handset with; null clears it. Only valid on DECT handsets, and must reference a base ordered on the same order. Auto-set when the order has a single base."
                  }
                }
              },
              "example": {
                "user": "user_01h455vb4pex5vsknk084sn02t",
                "location": "loc_01h455vb4pex5vsknk084sn02t"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated hardware order item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HardwareOrderItem"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Order or item not found"
          },
          "409": {
            "description": "Conflict — the order can no longer be modified (fulfilled or terminal), or the user already has a device / is already pre-assigned to another ordered unit."
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/hardware-orders/%7Border_id%7D/items/%7Bitem_id%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"user\":\"string\",\"location\":\"string\",\"base_item\":\"string\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/hardware-orders/{order_id}/items/{item_id}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/webrtc/ice-servers": {
      "get": {
        "summary": "Get ICE server credentials",
        "description": "Returns STUN and TURN server configurations for establishing WebRTC peer\nconnections. TURN credentials are time-limited — fetch fresh credentials\nbefore the `expires_at` timestamp.\n\nCall this before initiating or answering a call. The returned configuration\ncan be passed directly to `RTCPeerConnection` as `iceServers`.\n",
        "operationId": "getIceServers",
        "tags": [
          "WebRTC"
        ],
        "security": [
          {
            "UserAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "ICE server configuration",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IceServersResponse"
                },
                "example": {
                  "ice_servers": [
                    {
                      "urls": "stun:stun.dialstack.ai:3478"
                    },
                    {
                      "urls": [
                        "turn:turn.dialstack.ai:443?transport=tcp",
                        "turn:turn.dialstack.ai:443?transport=udp"
                      ],
                      "username": "1712793600:user_01h2xcejqtf2nbrexx3vqjhp42",
                      "credential": "aGVsbG8gd29ybGQ="
                    }
                  ],
                  "expires_at": "2026-04-10T22:00:00Z"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/webrtc/ice-servers \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/webrtc/ice-servers`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/webrtc/push-key": {
      "get": {
        "summary": "Get the Web Push application server key",
        "description": "Returns the public key the browser needs to subscribe to push\nnotifications for background call wake-up. The WebRTC SDK calls this\nautomatically on connect and passes the value to the browser as the\n`applicationServerKey`; you do not normally call it directly.\n\nThe key is stable — it is safe to cache for the lifetime of a session.\n\nReturns `503` when push wake-up is not available in this environment. The\nsoftphone works normally without it; calls that cannot wake a tab fall\nthrough to voicemail.\n",
        "operationId": "getWebPushKey",
        "tags": [
          "WebRTC"
        ],
        "security": [
          {
            "UserAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "The Web Push application server key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebPushKeyResponse"
                },
                "example": {
                  "vapid_public_key": "BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "503": {
            "description": "Push wake-up is not available in this environment",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/webrtc/push-key \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/webrtc/push-key`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/webrtc/push-subscriptions": {
      "post": {
        "summary": "Register a browser push subscription",
        "description": "Stores the browser Web Push subscription so DialStack can wake a\nbackgrounded or discarded softphone tab when a call arrives. The WebRTC\nSDK calls this automatically on connect; you do not normally call it\ndirectly.\n\nThe subscription is keyed by its push destination URL: registering a URL\nthat is already stored (for this user or another) reassigns it to the\ncurrent user, so a shared browser only ever has one active owner.\n\nThe subscription deliberately outlives the connection — it is what wakes\nthe tab after the session is gone — so it is not removed on disconnect.\n",
        "operationId": "createPushSubscription",
        "tags": [
          "WebRTC"
        ],
        "security": [
          {
            "UserAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePushSubscriptionRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The stored push subscription",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PushSubscription"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/webrtc/push-subscriptions \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'content-type: application/json' \\\n  -d '{\"endpoint\":\"string\",\"keys\":{\"p256dh\":\"string\",\"auth\":\"string\"}}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/webrtc/push-subscriptions`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/me": {
      "get": {
        "summary": "Get current user profile",
        "description": "**Coming soon.** This endpoint is documented ahead of release so you can review\nthe design before it ships — requests to it currently fail. If the proposed\nshape does or does not fit your use case, we would love to hear about it at\n[api@dialstack.ai](mailto:api@dialstack.ai).\n\nReturns the authenticated user's profile, including their assigned extensions\nand registered devices.\n",
        "operationId": "getCurrentUser",
        "tags": [
          "User Profile"
        ],
        "security": [
          {
            "UserAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "User profile",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserProfile"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/me \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/me`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/me/calls": {
      "get": {
        "summary": "List own call history",
        "description": "**Coming soon.** This endpoint is documented ahead of release so you can review\nthe design before it ships — requests to it currently fail. If the proposed\nshape does or does not fit your use case, we would love to hear about it at\n[api@dialstack.ai](mailto:api@dialstack.ai).\n\nReturns call records where the authenticated user was a participant.\nResults are returned in reverse chronological order (newest first).\n",
        "operationId": "listOwnCalls",
        "tags": [
          "User Profile"
        ],
        "security": [
          {
            "UserAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "direction",
            "in": "query",
            "description": "Filter by call direction",
            "schema": {
              "type": "string",
              "enum": [
                "inbound",
                "outbound"
              ]
            }
          },
          {
            "name": "from_date",
            "in": "query",
            "description": "Return calls on or after this date (ISO 8601)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to_date",
            "in": "query",
            "description": "Return calls before this date (ISO 8601)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of call records",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CallLog"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/me/calls?limit=10&direction=SOME_STRING_VALUE&from_date=SOME_STRING_VALUE&to_date=SOME_STRING_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/me/calls`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/me/presence": {
      "get": {
        "summary": "Get own presence status",
        "description": "**Coming soon.** This endpoint is documented ahead of release so you can review\nthe design before it ships — requests to it currently fail. If the proposed\nshape does or does not fit your use case, we would love to hear about it at\n[api@dialstack.ai](mailto:api@dialstack.ai). To read a user's\npresence today, use `GET /v1/users/{user_id}/presence` with a platform\nAPI key.\n\nReturns the authenticated user's current presence status.\n",
        "operationId": "getOwnPresence",
        "tags": [
          "User Profile"
        ],
        "security": [
          {
            "UserAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Presence status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PresenceStatus"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/me/presence \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/me/presence`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "put": {
        "summary": "Update own presence status",
        "description": "**Coming soon.** This endpoint is documented ahead of release so you can review\nthe design before it ships — requests to it currently fail. If the proposed\nshape does or does not fit your use case, we would love to hear about it at\n[api@dialstack.ai](mailto:api@dialstack.ai). There is no\nuser-settable presence status today.\n\nUpdates the authenticated user's presence status. Only `available`, `dnd`,\nand `away` can be set manually. The `on_call` and `offline` statuses are\nmanaged automatically by the system.\n",
        "operationId": "updateOwnPresence",
        "tags": [
          "User Profile"
        ],
        "security": [
          {
            "UserAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PresenceUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Presence updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PresenceStatus"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X PUT \\\n  https://api.dialstack.ai/v1/me/presence \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'content-type: application/json' \\\n  -d '{\"status\":\"available\",\"status_text\":\"string\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/me/presence`, {\n  method: 'PUT',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/me/directory": {
      "get": {
        "summary": "List the account directory",
        "description": "Returns the colleagues the authenticated user may see — the discovery\nread that lets a softphone resolve which users to show in a contact list,\nwatch with `phone.subscribePresence(userIds[])`, or offer as dial /\ntransfer targets, using only its user-session token, with no platform API\nkey and no account roster supplied by your backend.\n\nUnlike `GET /v1/users`, this returns only `user` and `display_name` —\nnever full user objects, emails, or device configuration — so it is safe\nto expose to an end-user credential.\n\nThe account is derived from the session token; you pass no ids and no\naccount context. Today the directory is every other active user in your\naccount. It is cursor-paginated like the other list endpoints; follow\n`next_page_url` to read the whole account. Note that presence\nsubscription itself accepts at most 100 users at once, so a client\nwatching a very large directory subscribes to a subset.\n",
        "operationId": "listDirectory",
        "tags": [
          "User Profile"
        ],
        "security": [
          {
            "UserAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "The caller's account directory",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/DirectoryEntry"
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/me/directory?limit=10' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/me/directory`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/me/emergency-addresses": {
      "post": {
        "summary": "Register an emergency address",
        "description": "Validates a civic address against the official 911 address database\nand stores it for the authenticated user. This operation creates the\naddress resource only; it does not update an already-authenticated\nsoftphone connection. The new address therefore has no network binding\n(`registered_ip` is null) until its id is presented in a WebRTC\n`authenticate` message.\n\nTo activate an address on a phone that is already connected, reconnect\nthe phone with the new id (`phone.reconnectWithEmergency(address.id)`).\nAlternatively, supply the id as `PhoneOptions.emergencyAddressId` before\nthe phone's first `connect()`. Until then, non-emergency PSTN calls are\nblocked and emergency calls do not carry this dispatchable location.\n\nA user may keep several saved addresses (location profiles). The app\nselects the appropriate one and presents it when the phone connects.\n",
        "operationId": "createEmergencyAddress",
        "tags": [
          "User Profile"
        ],
        "security": [
          {
            "UserAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmergencyAddressRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Emergency address validated and stored; not yet active on any existing connection",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmergencyAddress"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "description": "The address could not be validated against the MSAG.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "examples": [
                        "emergency address could not be validated"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/me/emergency-addresses \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'content-type: application/json' \\\n  -d '{\"address_number\":\"string\",\"street\":\"string\",\"unit\":\"string\",\"city\":\"string\",\"state\":\"string\",\"postal_code\":\"string\",\"country\":\"string\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/me/emergency-addresses`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "get": {
        "summary": "List emergency addresses",
        "description": "Lists the authenticated user's saved emergency addresses.",
        "operationId": "listEmergencyAddresses",
        "tags": [
          "User Profile"
        ],
        "security": [
          {
            "UserAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "A list of emergency addresses",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string",
                      "enum": [
                        "list"
                      ]
                    },
                    "url": {
                      "type": "string"
                    },
                    "next_page_url": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "previous_page_url": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EmergencyAddress"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/me/emergency-addresses \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/me/emergency-addresses`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/me/emergency-addresses/{emergency_address_id}": {
      "parameters": [
        {
          "name": "emergency_address_id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "summary": "Get an emergency address",
        "operationId": "getEmergencyAddress",
        "tags": [
          "User Profile"
        ],
        "security": [
          {
            "UserAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Emergency address",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmergencyAddress"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "No such emergency address"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/me/emergency-addresses/%7Bemergency_address_id%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/me/emergency-addresses/{emergency_address_id}`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "delete": {
        "summary": "Delete an emergency address",
        "operationId": "deleteEmergencyAddress",
        "tags": [
          "User Profile"
        ],
        "security": [
          {
            "UserAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "No such emergency address"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/me/emergency-addresses/%7Bemergency_address_id%7D \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/me/emergency-addresses/{emergency_address_id}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/me/emergency-addresses/{emergency_address_id}/registered_ip": {
      "parameters": [
        {
          "name": "emergency_address_id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "delete": {
        "summary": "Clear an emergency address's network binding",
        "description": "Clears the address's `registered_ip`. The next time a softphone\nconnects using this address, it is re-bound to the device's current\nnetwork. Use this when a device has moved and you want the saved\naddress to re-register where the device now is.\n",
        "operationId": "clearEmergencyAddressRegisteredIp",
        "tags": [
          "User Profile"
        ],
        "security": [
          {
            "UserAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "Binding cleared"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "No such emergency address"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/me/emergency-addresses/%7Bemergency_address_id%7D/registered_ip \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/me/emergency-addresses/{emergency_address_id}/registered_ip`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/queues": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "post": {
        "summary": "Create a call queue",
        "description": "Creates a new call queue. The queue starts with no members; add agents\nwith `POST /v1/queues/{queue_id}/members`.\n",
        "operationId": "createQueue",
        "tags": [
          "Call Queues"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateQueueRequest"
              },
              "examples": {
                "ringall": {
                  "summary": "Ringall queue with voicemail timeout",
                  "value": {
                    "name": "Support",
                    "strategy": "ringall",
                    "timeout_seconds": 120,
                    "wrap_up_seconds": 15,
                    "announcements": {
                      "frequency_seconds": 30
                    },
                    "max_queue_length": 50,
                    "timeout": {
                      "type": "voicemail",
                      "voicemail": "svm_01h2xcejqtf2nbrexx3vqjhp60"
                    }
                  }
                },
                "linear": {
                  "summary": "Linear queue, no timeout",
                  "value": {
                    "name": "Tier 1",
                    "strategy": "linear"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Queue created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Queue"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/QueueValidationFailed"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/queues \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"name\":\"Support\",\"strategy\":\"ringall\",\"timeout_seconds\":120,\"wrap_up_seconds\":15,\"announcements\":{\"frequency_seconds\":30},\"callback\":{\"offer_after_seconds\":60,\"outbound_did\":\"did_01h2xcejqtf2nbrexx3vqjhp44\"},\"timeout\":{\"type\":\"ring_user\",\"user\":\"user_01h2xcejqtf2nbrexx3vqjhp42\"},\"max_queue_length\":50,\"join_empty\":\"strict\",\"leave_when_empty\":\"strict\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/queues`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "get": {
        "summary": "List call queues",
        "description": "Returns a paginated list of queues for the account.",
        "operationId": "listQueues",
        "tags": [
          "Call Queues"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `extensions`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "extensions"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of queues",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Queue"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/queues?limit=10&expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/queues`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/queues/{queue_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/QueueId"
        }
      ],
      "get": {
        "summary": "Get a call queue",
        "description": "Retrieves a queue by ID. The first 10 members are embedded inline under\n`members`; page through the rest via `members.next_page_url` or\n`GET /v1/queues/{queue_id}/members`.\n",
        "operationId": "getQueue",
        "tags": [
          "Call Queues"
        ],
        "parameters": [
          {
            "name": "expand[]",
            "in": "query",
            "description": "Related resources to include inline. Supported values: `extensions`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "extensions"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Queue details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Queue"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/QueueNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/queues/qu_01h2xcejqtf2nbrexx3vqjhp61?expand%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/queues/{queue_id}`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Update a call queue",
        "description": "Updates queue settings. All fields are optional.\n\nSend `timeout: null` to clear the timeout configuration; omit the field\nto leave it unchanged.\n",
        "operationId": "updateQueue",
        "tags": [
          "Call Queues"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateQueueRequest"
              },
              "examples": {
                "clear_timeout": {
                  "summary": "Clear the timeout configuration",
                  "value": {
                    "timeout": null
                  }
                },
                "switch_strategy": {
                  "summary": "Change strategy, wrap-up, and announcement cadence",
                  "value": {
                    "strategy": "fewestcalls",
                    "wrap_up_seconds": 30,
                    "announcements": {
                      "frequency_seconds": 45
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated queue",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Queue"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/QueueNotFound"
          },
          "422": {
            "$ref": "#/components/responses/QueueValidationFailed"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/queues/qu_01h2xcejqtf2nbrexx3vqjhp61 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"name\":\"string\",\"strategy\":\"ringall\",\"timeout_seconds\":3600,\"wrap_up_seconds\":600,\"announcements\":{\"frequency_seconds\":30},\"callback\":{\"offer_after_seconds\":60,\"outbound_did\":\"did_01h2xcejqtf2nbrexx3vqjhp44\"},\"timeout\":{\"type\":\"ring_user\",\"user\":\"user_01h2xcejqtf2nbrexx3vqjhp42\"},\"max_queue_length\":0,\"join_empty\":\"strict\",\"leave_when_empty\":\"strict\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/queues/{queue_id}`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "delete": {
        "summary": "Delete a call queue",
        "description": "Deletes a queue and removes all of its members.",
        "operationId": "deleteQueue",
        "tags": [
          "Call Queues"
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/QueueDeleted"
          },
          "404": {
            "$ref": "#/components/responses/QueueNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/queues/qu_01h2xcejqtf2nbrexx3vqjhp61 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/queues/{queue_id}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/queues/{queue_id}/members": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/QueueId"
        }
      ],
      "get": {
        "summary": "List queue members",
        "description": "Returns a paginated list of members on the queue.",
        "operationId": "listQueueMembers",
        "tags": [
          "Call Queues"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "List of queue members",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/QueueMember"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/QueueNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/queues/qu_01h2xcejqtf2nbrexx3vqjhp61/members?limit=10' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/queues/{queue_id}/members`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Add a queue member",
        "description": "Adds a user agent to the queue. Each user can be a member of a queue\nat most once; re-adding returns `409`.\n\n**Auto-login side effect.** On success, the user is also marked\nlogged in for queue dispatch (equivalent to dialing `*45`) so they\nstart receiving queue calls immediately — admins don't have to log\nagents in separately. The auto-login is conservative:\n\n- Agents who are already logged in are unaffected (no-op).\n- Paused agents stay paused. Adding someone to another queue while\n  they're on a break doesn't end the break.\n- Logged-out agents and users who have never had queue state are\n  marked available.\n\nAgents can still log themselves out with `*45` or via the\n`POST /v1/users/{user_id}/queue-agent` endpoint.\n",
        "operationId": "addQueueMember",
        "tags": [
          "Call Queues"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddQueueMemberRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Add user with default penalty",
                  "value": {
                    "user": "user_01h2xcejqtf2nbrexx3vqjhp42"
                  }
                },
                "ranked": {
                  "summary": "Add user with explicit penalty and position",
                  "value": {
                    "user": "user_01h2xcejqtf2nbrexx3vqjhp43",
                    "penalty": 2,
                    "position": 3
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Member added",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QueueMember"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/QueueNotFound"
          },
          "409": {
            "$ref": "#/components/responses/QueueMemberConflict"
          },
          "422": {
            "$ref": "#/components/responses/QueueValidationFailed"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/queues/qu_01h2xcejqtf2nbrexx3vqjhp61/members \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"user\":\"user_01h2xcejqtf2nbrexx3vqjhp42\",\"penalty\":0,\"position\":3}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/queues/{queue_id}/members`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/queues/{queue_id}/members/{member_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/QueueId"
        },
        {
          "$ref": "#/components/parameters/QueueMemberId"
        }
      ],
      "delete": {
        "summary": "Remove a queue member",
        "description": "Removes a member from the queue.",
        "operationId": "removeQueueMember",
        "tags": [
          "Call Queues"
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/QueueMemberDeleted"
          },
          "404": {
            "$ref": "#/components/responses/QueueMemberNotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \\\n  https://api.dialstack.ai/v1/queues/qu_01h2xcejqtf2nbrexx3vqjhp61/members/qum_01h2xcejqtf2nbrexx3vqjhp62 \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/queues/{queue_id}/members/{member_id}`, {\n  method: 'DELETE',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/users/{user_id}/presence": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/UserId"
        }
      ],
      "get": {
        "summary": "Get a user's presence",
        "description": "Returns whether a user is reachable right now and whether they are on a\ncall, read live from the phone system.\n\nThe response is always freshly verified. If presence cannot be\ndetermined (the underlying system is unavailable or the read does not\ncomplete in time), the request fails with `503` rather than returning a\nstale or guessed value.\n",
        "operationId": "getUserPresence",
        "tags": [
          "Presence"
        ],
        "responses": {
          "200": {
            "description": "The user's current presence",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserPresence"
                },
                "examples": {
                  "available": {
                    "summary": "Reachable and idle",
                    "value": {
                      "object": "user_presence",
                      "state": "available",
                      "notifiable": false,
                      "do_not_disturb": false,
                      "webrtc": {
                        "state": "available",
                        "sessions": 1
                      }
                    }
                  },
                  "on_call_elsewhere": {
                    "summary": "On a call, but reachable in the browser",
                    "description": "The user answered on another endpoint type (a desk phone),\nso the top-level `state` is `on_call` while their WebRTC\nsession is idle and still ringable.\n",
                    "value": {
                      "object": "user_presence",
                      "state": "on_call",
                      "notifiable": false,
                      "do_not_disturb": false,
                      "webrtc": {
                        "state": "available",
                        "sessions": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such user in this account",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Presence could not be determined; try again",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/users/user_01h2xcejqtf2nbrexx3vqjhp42/presence \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/users/{user_id}/presence`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/presence": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        }
      ],
      "get": {
        "summary": "Read or subscribe to presence",
        "description": "Returns the current state of the presentities you select. Two kinds are\navailable, each with the selector that suits it:\n\n- **`user[]`** — presence for an explicit set of users, the bounded\n  candidate set a caller already has in hand (for example, the possible\n  targets of a transfer). Repeat the parameter per user.\n- **`park_slot[]`** — park slots in the account, selected one of two ways.\n  `all` returns every call currently parked in the account, and only the\n  occupied slots: park slots have no inventory to enumerate, since a slot\n  exists only while a call occupies it. Naming slots instead\n  (`park_slot[]=1&park_slot[]=2`) returns exactly those slots **including\n  the free ones**, because a client that names its slots has supplied the\n  set `all` cannot know — so the response is that whole set rather than\n  a fragment to merge. Slots not present in the response are free either\n  way.\n\n  `all` and specific slots cannot be combined: they disagree about\n  whether free slots are emitted, so mixing them returns `400` rather\n  than quietly answering the narrower question.\n\nAt least one selector is required. This is a filtered list, not a\npaginated collection: there is no `limit` or cursor. The number of users\nper request is capped; exceeding the cap returns `400`. If anything you\nselected cannot be read, the whole request fails (`400`/`503`) rather\nthan returning a partial or guessed result — a partial answer is\nindistinguishable from a genuinely quiet one.\n\nEvery element of `data` carries an `object` naming its resource, because\nselecting more than one kind of presentity makes the list heterogeneous.\n\n## Subscribing\n\nSend `Accept: text/event-stream` to receive the same information as a\nlive subscription instead of a one-shot read. On connect you get the\ncomplete current state, then one frame per change:\n\n| Frame | Body |\n| --- | --- |\n| `connected` | `{}` |\n| `snapshot` | the same list envelope this endpoint returns as JSON |\n| `park_slot` | one `ParkSlotPresence` — the slot's **new state** |\n| `terminated` | `{\"reason\": \"...\"}` — see below |\n\nFrames carry **state, not transitions**. A slot being freed arrives as\n`parked_call: null` — a frame always describes what\nthe slot is now, never what changed, so there is no log of parks and\nunparks to reconcile and receiving the same frame twice changes nothing.\n\n**`user[]` is not supported on a subscription** and returns `400`. User\npresence has no change source yet, and a subscription that never updates\nwould be worse than none — you would believe it was live. Read user\npresence as JSON in the meantime.\n\n**Recovery is always the same: reconnect.** If slot state can no longer be\nverified we send a `terminated` frame and close the connection rather\nthan leave you holding state that silently drifts. Reconnecting delivers a\nfresh `snapshot`, which is a complete resync — there are no sequence\nnumbers to track.\n\nExpect reconnects routinely rather than as incidents: we deploy often, and\neach deploy closes open streams with `reason: shutdown`, so a long-lived\nsubscriber reconnects several times a day at baseline.\n\n**Subscribe from a server, not from a browser.** The connection carries\nyour secret key, so opening it from client-side code would expose it.\nRelay the frames to your front end over your own transport.\n",
        "operationId": "listPresence",
        "tags": [
          "Presence"
        ],
        "parameters": [
          {
            "name": "user[]",
            "in": "query",
            "required": false,
            "description": "The users to read presence for. Repeat the parameter for each user.\nNot supported with `Accept: text/event-stream`.\n",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "example": "user_01h2xcejqtf2nbrexx3vqjhp42"
              }
            }
          },
          {
            "name": "park_slot[]",
            "in": "query",
            "required": false,
            "description": "Either `all` — every currently parked call in the account, occupied\nslots only — or the specific slot numbers to watch, repeated once per\nslot. Named slots come back including the free ones.\n\nNaming slots does not restrict where calls can be parked: `*68<slot>`\nworks whether or not anyone has a key for that slot, so a slot you did\nnot name can still become occupied. Treat any slot missing from a\nresponse as free, and expect slots you did not ask for. The two\nforms cannot be combined; mixing them returns `400`.\n",
            "schema": {
              "type": "array",
              "items": {
                "oneOf": [
                  {
                    "type": "string",
                    "enum": [
                      "all"
                    ]
                  },
                  {
                    "type": "integer",
                    "minimum": 1,
                    "example": 3
                  }
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The selected presentities. With `Accept: application/json` this is a\npoint-in-time list; with `Accept: text/event-stream` it is a live\nsubscription whose first frames are `connected` and `snapshot`.\n",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/ListObject"
                    },
                    "url": {
                      "$ref": "#/components/schemas/ListUrl"
                    },
                    "next_page_url": {
                      "$ref": "#/components/schemas/NextPageUrl"
                    },
                    "previous_page_url": {
                      "$ref": "#/components/schemas/PreviousPageUrl"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "oneOf": [
                          {
                            "$ref": "#/components/schemas/UserPresenceItem"
                          },
                          {
                            "$ref": "#/components/schemas/ParkSlotPresence"
                          }
                        ],
                        "discriminator": {
                          "propertyName": "object"
                        }
                      }
                    }
                  },
                  "required": [
                    "object",
                    "url",
                    "next_page_url",
                    "previous_page_url",
                    "data"
                  ]
                },
                "examples": {
                  "users": {
                    "summary": "Bulk user presence",
                    "value": {
                      "object": "list",
                      "url": "/v1/presence",
                      "next_page_url": null,
                      "previous_page_url": null,
                      "data": [
                        {
                          "object": "user_presence",
                          "user": "user_01h2xcejqtf2nbrexx3vqjhp42",
                          "state": "on_call",
                          "notifiable": false,
                          "do_not_disturb": true,
                          "webrtc": {
                            "state": "on_call",
                            "sessions": 1
                          }
                        },
                        {
                          "object": "user_presence",
                          "user": "user_01h2xcejqtf2nbrexx3vqjhp43",
                          "state": "offline",
                          "notifiable": true,
                          "do_not_disturb": false,
                          "webrtc": {
                            "state": "offline",
                            "sessions": 0
                          }
                        }
                      ]
                    }
                  },
                  "park_slots": {
                    "summary": "One call parked, in slot 3",
                    "value": {
                      "object": "list",
                      "url": "/v1/presence",
                      "next_page_url": null,
                      "previous_page_url": null,
                      "data": [
                        {
                          "object": "park_slot",
                          "slot": 3,
                          "parked_call": {
                            "call": "call_01kyqarr27ejcscvv5wbw7c4h5",
                            "from_number": "+16135551234",
                            "from_label": "JANE DOE",
                            "status": "parked",
                            "parked_by": "user_01h2xcejqtf2nbrexx3vqjhp42",
                            "parked_by_extension": "1001",
                            "parked_at": "2026-08-03T14:12:04Z",
                            "rings_back_at": "2026-08-03T14:14:04Z"
                          }
                        }
                      ]
                    }
                  },
                  "named_park_slots": {
                    "summary": "Slots 1-3 named — free slots included",
                    "value": {
                      "object": "list",
                      "url": "/v1/presence",
                      "next_page_url": null,
                      "previous_page_url": null,
                      "data": [
                        {
                          "object": "park_slot",
                          "slot": 1,
                          "parked_call": null
                        },
                        {
                          "object": "park_slot",
                          "slot": 2,
                          "parked_call": {
                            "call": "call_01kyqarr27ejcscvv5wbw7c4h5",
                            "from_number": "+16135551234",
                            "from_label": "JANE DOE",
                            "status": "ringing_back",
                            "parked_by": "user_01h2xcejqtf2nbrexx3vqjhp42",
                            "parked_by_extension": "1001",
                            "parked_at": "2026-08-03T14:12:04Z",
                            "rings_back_at": "2026-08-03T14:14:04Z"
                          }
                        },
                        {
                          "object": "park_slot",
                          "slot": 3,
                          "parked_call": null
                        }
                      ]
                    }
                  },
                  "empty_park_slots": {
                    "summary": "Nothing currently parked",
                    "value": {
                      "object": "list",
                      "url": "/v1/presence",
                      "next_page_url": null,
                      "previous_page_url": null,
                      "data": []
                    }
                  }
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string"
                },
                "examples": {
                  "subscription": {
                    "summary": "Connect, snapshot, then a slot being freed",
                    "value": "retry: 2000\n\nevent: connected\ndata: {}\n\nevent: snapshot\ndata: {\"object\":\"list\",\"url\":\"/v1/presence\",\"next_page_url\":null,\"previous_page_url\":null,\"data\":[{\"object\":\"park_slot\",\"slot\":3,\"parked_call\":{\"call\":\"call_01kyqarr27ejcscvv5wbw7c4h5\",\"from_number\":\"+16135551234\",\"from_label\":\"JANE DOE\",\"status\":\"parked\",\"parked_by\":\"user_01h2xcejqtf2nbrexx3vqjhp42\",\"parked_by_extension\":\"1001\",\"parked_at\":\"2026-08-03T14:12:04Z\",\"rings_back_at\":\"2026-08-03T14:14:04Z\"}}]}\n\nevent: park_slot\ndata: {\"object\":\"park_slot\",\"slot\":3,\"parked_call\":null}\n"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "description": "Too many concurrent event-stream connections for this platform.\nRetry after the interval in `Retry-After`, or close a connection you\nno longer need.\n",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before reconnecting.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Presence could not be determined; try again",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  'https://api.dialstack.ai/v1/presence?user%5B%5D=SOME_ARRAY_VALUE&park_slot%5B%5D=SOME_ARRAY_VALUE' \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/presence`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      }
    },
    "/v1/users/{user_id}/queue-agent": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DialStackAccount"
        },
        {
          "$ref": "#/components/parameters/UserId"
        }
      ],
      "get": {
        "summary": "Get queue-agent state",
        "description": "Returns the user's current queue-agent operational state. `status`\nis derived from the underlying timestamps: `paused_at` present\nrenders as `paused`; `logged_in_at` absent renders as `logged_out`;\notherwise `available`.\n\nReturns 404 if the user has never had agent state written. A user\nwho logged out is *not* a 404 — the row is retained so historical\nattributes survive the logout/login cycle.\n",
        "operationId": "getQueueAgent",
        "tags": [
          "Call Queues"
        ],
        "responses": {
          "200": {
            "description": "Current agent state",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentStatus"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No agent state has ever been written for this user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \\\n  https://api.dialstack.ai/v1/users/user_01h2xcejqtf2nbrexx3vqjhp42/queue-agent \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/users/{user_id}/queue-agent`, {\n  method: 'GET',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n  },\n});\n\nconst data = await res.json();"
          }
        ]
      },
      "post": {
        "summary": "Update queue-agent state",
        "description": "Sets a queue agent's availability state. The endpoint is idempotent:\nre-sending the current status is a 200 with no semantic change.\n\nTransitioning to `available` (or `paused`) from a logged-out state\nsets `logged_in_at` if it isn't already populated; subsequent flips\nbetween `available` and `paused` preserve the original login time.\nTransitioning to `logged_out` clears `logged_in_at`, `paused_at`,\nand `pause_reason` but retains the row so historical attributes\nsurvive the logout/login cycle.\n\n`reason` is only valid when `status` is `paused`; sending it with\nany other status returns 400.\n",
        "operationId": "updateQueueAgent",
        "tags": [
          "Call Queues"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetAgentStatusRequest"
              },
              "examples": {
                "paused_with_reason": {
                  "summary": "Pause with a reason",
                  "value": {
                    "status": "paused",
                    "reason": "break"
                  }
                },
                "available": {
                  "summary": "Mark available",
                  "value": {
                    "status": "available"
                  }
                },
                "logged_out": {
                  "summary": "Log out",
                  "value": {
                    "status": "logged_out"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Agent status updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentStatus"
                }
              }
            }
          },
          "400": {
            "description": "Request body failed validation. Examples:\n- `status is required`\n- `status must be one of available, paused, logged_out`\n- `reason is only allowed when status is paused`\n- `reason must be 255 characters or fewer`\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \\\n  https://api.dialstack.ai/v1/users/user_01h2xcejqtf2nbrexx3vqjhp42/queue-agent \\\n  -H 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  -H 'DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41' \\\n  -H 'content-type: application/json' \\\n  -d '{\"status\":\"paused\",\"reason\":\"break\"}'"
          },
          {
            "lang": "TypeScript",
            "label": "fetch",
            "source": "const res = await fetch(`https://api.dialstack.ai/v1/users/{user_id}/queue-agent`, {\n  method: 'POST',\n  headers: {\n    'Authorization': \\`Bearer \\${process.env.DIALSTACK_KEY}\\`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ /* request body */ }),\n});\n\nconst data = await res.json();"
          }
        ]
      }
    }
  },
  "tags": [
    {
      "name": "Faxes",
      "description": "Send outbound faxes and review fax history. Requires account context via\nthe `DialStack-Account` header or a session token.\n"
    },
    {
      "name": "Files",
      "description": "Upload files for use with other resources (e.g. a fax document). Requires\naccount context via the `DialStack-Account` header or a session token.\n"
    },
    {
      "name": "Audit Logs",
      "description": "Read-only access to audit trail entries"
    },
    {
      "name": "Presence",
      "description": "Read whether users are reachable and on a call right now, verified live\nfrom the phone system. Requires account context via the\n`DialStack-Account` header or a session token.\n"
    },
    {
      "name": "Call Queues",
      "description": "Call queue configuration, member management, and per-user agent state.\nRequires account context via `DialStack-Account` header or session token.\n"
    },
    {
      "name": "Accounts",
      "description": "Account (customer organization) management.\nThese endpoints operate at the platform level and don't require the `DialStack-Account` header.\n"
    },
    {
      "name": "Sessions",
      "description": "Account session management for embedded components.\nSessions provide scoped authentication for frontend components.\nRequires a platform API key — session tokens cannot be used to create new sessions.\n"
    },
    {
      "name": "Users",
      "description": "User (people) management.\nRequires account context via `DialStack-Account` header or session token.\n"
    },
    {
      "name": "Admin Portal Users",
      "description": "Read-only access to the people who can administer an account in the admin\nportal, and their roles. A different population from Users, which lists\nvoice users. Requires account context via `DialStack-Account` header or\nsession token.\n"
    },
    {
      "name": "Voicemails",
      "description": "Voicemail message management.\nRequires account context via `DialStack-Account` header or session token.\n"
    },
    {
      "name": "Calls",
      "description": "Call initiation, history, and real-time monitoring.\nUse POST /v1/calls to initiate click-to-call, GET /v1/calls to retrieve call history,\nand POST /v1/calls/{call_id}/listeners to stream real-time audio from active calls.\nRequires account context via `DialStack-Account` header or session token.\n"
    },
    {
      "name": "Phone Numbers",
      "description": "Phone number (DID) management including search, ordering, and disconnect.\nRequires account context via `DialStack-Account` header or session token.\nFor porting existing numbers from another carrier, see Number Porting.\n"
    },
    {
      "name": "Number Porting",
      "description": "Number porting (port-in) management. Transfer existing phone numbers from another\ncarrier to DialStack. The eligibility check endpoint does not require the\n`DialStack-Account` header.\n"
    },
    {
      "name": "AI Agents",
      "description": "AI-powered voice agent management.\nAI agents provide automated call handling with customizable instructions and FAQ responses.\nEach agent automatically manages a voice app and extension for call routing.\nRequires account context via `DialStack-Account` header.\n"
    },
    {
      "name": "Voice Apps",
      "description": "Voice app management for programmable voice applications.\nVoice apps handle calls via HTTP webhook notification and optional WebSocket audio streaming.\nRequires account context via `DialStack-Account` header.\n"
    },
    {
      "name": "Events",
      "description": "Real-time event streaming via Server-Sent Events (SSE).\nUse this endpoint to receive live notifications about calls, voicemails, and other account activity.\nRequires account context via `DialStack-Account` header or session token.\n"
    },
    {
      "name": "Webhook Endpoints",
      "description": "Register URLs to receive event notifications. Endpoints are mode-scoped:\nan endpoint created with a live key receives events only from live\naccounts, and one created with a test key receives events only from\nsandbox accounts — so test traffic never reaches a production URL.\nPlatform-level: authenticate with your API key; no account context\nrequired.\n"
    },
    {
      "name": "Schedules",
      "description": "Business hours schedule management.\nSchedules define when the business is open based on weekly time ranges and holidays.\nA temporary hold can override the schedule calculation.\nRequires account context via `DialStack-Account` header or session token.\n"
    },
    {
      "name": "Dial Plans",
      "description": "Visual call routing graph management.\nDial plans define how calls are routed through nodes (schedules, extensions).\nMultiple extensions can share the same dial plan.\nRequires account context via `DialStack-Account` header or session token.\n"
    },
    {
      "name": "Ring Groups",
      "description": "Ring group management for parallel dialing (call forking).\nRing groups dial multiple members simultaneously; the first to answer wins.\nRequires account context via `DialStack-Account` header or session token.\n"
    },
    {
      "name": "Shared Voicemail Boxes",
      "description": "Shared voicemail box management for team or departmental voicemail.\nShared voicemail boxes can receive messages and forward them via email.\nRequires account context via `DialStack-Account` header or session token.\n"
    },
    {
      "name": "Audio Clips",
      "description": "Audio clip management for hold music, IVR prompts, and other audio playback.\nUpload audio files which are validated and transcoded server-side.\nRequires account context via `DialStack-Account` header or session token.\n"
    },
    {
      "name": "Extensions",
      "description": "Extension (dial code) management.\nExtensions map short dial codes to routing targets.\nRequires account context via `DialStack-Account` header or session token.\n"
    },
    {
      "name": "Locations",
      "description": "Business location management.\nLocations represent physical offices or business premises with validated addresses.\nRequires account context via `DialStack-Account` header or session token.\n"
    },
    {
      "name": "Devices",
      "description": "Unified device API for deskphones, DECT bases, and DECT handsets.\n**This is the recommended way to manage devices.** Use `/v1/devices` to\ncreate, list, get, and delete any device type, and `/v1/devices/{id}/users`\nto assign and manage users on any device type.\n\nThe type-specific `/v1/deskphones` and `/v1/dect-bases` endpoints are\nretained only for operations that have no unified equivalent yet\n(updates, provisioning-events, listing handsets under a specific base).\nPrefer `/v1/devices` everywhere else.\n\nRequires account context via `DialStack-Account` header or session token.\n"
    },
    {
      "name": "Deskphones",
      "description": "Deskphone-specific operations retained for the cases `/v1/devices` does\nnot cover yet (updates and provisioning events). For create, list, get,\nand delete, use the unified [Devices](#tag/Devices) API — it is the\nrecommended approach for all new integrations.\n\nRequires account context via `DialStack-Account` header or session token.\n"
    },
    {
      "name": "DECT Bases",
      "description": "DECT-specific operations retained for the cases `/v1/devices` does not\ncover yet (updates and listing handsets under a specific base). For\ncreate, list, get, and delete of bases and handsets, use the unified\n[Devices](#tag/Devices) API — it is the recommended approach for all\nnew integrations.\n\nRequires account context via `DialStack-Account` header or session token.\n"
    },
    {
      "name": "Button Templates",
      "description": "Reusable programmable-key layouts that can be assigned to devices.\nA template defines button positions, types, and labels once and applies\nthem to every device it is assigned to; per-device overrides can add,\nreplace, or suppress individual buttons on top of (or without) a template.\nRequires account context via `DialStack-Account` header or session token.\n"
    },
    {
      "name": "Catalog",
      "description": "Hardware catalog listing.\nReturns available hardware items for selection during onboarding.\nDoes not require account context.\n"
    },
    {
      "name": "Hardware Orders",
      "description": "Hardware order management.\nOrders contain line items representing hardware selections (model + quantity).\nRequires account context via `DialStack-Account` header or session token.\n"
    },
    {
      "name": "WebRTC",
      "description": "WebRTC configuration for softphone applications.\nProvides ICE server credentials for establishing peer connections.\nThe signalling protocol is documented in the [WebRTC Signalling Protocol](/webrtc/protocol).\nRequires a user token.\n"
    },
    {
      "name": "User Profile",
      "description": "User-scoped REST endpoints for softphone and user-facing applications.\nReturns data scoped to the authenticated user (own call history, voicemails,\npresence, device registration). Requires a user token.\n"
    },
    {
      "name": "Quality",
      "description": "Call quality metrics and device registration health.\nAggregate MOS/packet-loss summaries, worst-call lookups, and live device\nregistration state for monitoring and troubleshooting.\nRequires account context via `DialStack-Account` header or session token.\n"
    }
  ],
  "x-tagGroups": [
    {
      "name": "Accounts & Users",
      "tags": [
        "Accounts",
        "Sessions",
        "Users",
        "User Profile",
        "Admin Portal Users",
        "Extensions",
        "Presence"
      ]
    },
    {
      "name": "Calls",
      "tags": [
        "Calls",
        "Voicemails",
        "Faxes",
        "Files",
        "Events",
        "WebRTC"
      ]
    },
    {
      "name": "Routing",
      "tags": [
        "Dial Plans",
        "Ring Groups",
        "Call Queues",
        "Schedules",
        "Shared Voicemail Boxes",
        "Audio Clips",
        "Phone Numbers",
        "Number Porting",
        "Locations"
      ]
    },
    {
      "name": "AI & Voice Apps",
      "tags": [
        "AI Agents",
        "Voice Apps"
      ]
    },
    {
      "name": "Devices & Hardware",
      "tags": [
        "Devices",
        "Deskphones",
        "DECT Bases",
        "Button Templates",
        "Hardware Orders",
        "Catalog"
      ]
    },
    {
      "name": "Platform",
      "tags": [
        "Audit Logs",
        "Quality",
        "Webhook Endpoints"
      ]
    }
  ]
}