--- # yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema openapi: 3.1.0 info: title: agent-call Asterisk/SIP Management API version: 1.0.0 description: >- Independent Asterisk/SIP management backend. Admin write operations are separate from the SaaS read-only Trunk directory and from ordinary scheduling APIs. In mock mode publication records are intents only. In real mode a publication is successful only after every selected Cell Agent returns a matching mTLS acknowledgement. servers: - url: https://sip-admin.internal description: Restricted operator management network - url: https://sip-read.internal description: SaaS read-only service network tags: - name: health - name: admin-providers - name: admin-trunks - name: admin-cells - name: admin-status - name: admin-statistics - name: admin-audit - name: saas-readonly paths: /healthz/live: get: tags: [health] operationId: live responses: '200': description: Service is alive content: application/json: schema: $ref: '#/components/schemas/Health' /admin/v1/providers: get: tags: [admin-providers] operationId: listProviders security: [{SipAdminBearer: []}] responses: '200': description: Provider directory content: application/json: schema: {$ref: '#/components/schemas/ProviderList'} '401': {$ref: '#/components/responses/Unauthorized'} /admin/v1/providers/{provider_id}: parameters: - {$ref: '#/components/parameters/ProviderId'} get: tags: [admin-providers] operationId: getProvider security: [{SipAdminBearer: []}] responses: '200': description: Provider content: application/json: schema: {$ref: '#/components/schemas/ProviderResponse'} '401': {$ref: '#/components/responses/Unauthorized'} '404': {$ref: '#/components/responses/NotFound'} put: tags: [admin-providers] operationId: upsertProvider security: [{SipAdminBearer: []}] parameters: - {$ref: '#/components/parameters/IfMatch'} - {$ref: '#/components/parameters/RequestId'} requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/ProviderInput'} responses: '200': description: Updated provider content: application/json: schema: {$ref: '#/components/schemas/ProviderResponse'} '201': description: Created provider content: application/json: schema: {$ref: '#/components/schemas/ProviderResponse'} '400': {$ref: '#/components/responses/BadRequest'} '401': {$ref: '#/components/responses/Unauthorized'} '403': {$ref: '#/components/responses/Forbidden'} '409': {$ref: '#/components/responses/Conflict'} /admin/v1/trunks: get: tags: [admin-trunks] operationId: listAdminTrunks security: [{SipAdminBearer: []}] parameters: - {$ref: '#/components/parameters/ProviderFilter'} - {$ref: '#/components/parameters/CellIdFilter'} - {$ref: '#/components/parameters/TrunkStatusFilter'} responses: '200': description: All Trunks, including unpublished revisions content: application/json: schema: $ref: '#/components/schemas/AdminTrunkList' '401': {$ref: '#/components/responses/Unauthorized'} '403': {$ref: '#/components/responses/Forbidden'} /admin/v1/trunks/{trunk_id}: parameters: - {$ref: '#/components/parameters/TrunkId'} get: tags: [admin-trunks] operationId: getAdminTrunk security: [{SipAdminBearer: []}] responses: '200': description: Trunk configuration and revisions content: application/json: schema: $ref: '#/components/schemas/AdminTrunk' '401': {$ref: '#/components/responses/Unauthorized'} '404': {$ref: '#/components/responses/NotFound'} put: tags: [admin-trunks] operationId: createTrunkRevision security: [{SipAdminBearer: []}] parameters: - {$ref: '#/components/parameters/IfMatch'} - {$ref: '#/components/parameters/RequestId'} requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/TrunkConfig' responses: '200': description: New draft revision for an existing Trunk content: application/json: schema: {$ref: '#/components/schemas/AdminTrunk'} '201': description: New Trunk with its first draft revision content: application/json: schema: {$ref: '#/components/schemas/AdminTrunk'} '400': {$ref: '#/components/responses/BadRequest'} '401': {$ref: '#/components/responses/Unauthorized'} '409': {$ref: '#/components/responses/Conflict'} /admin/v1/trunks/{trunk_id}/validate: parameters: - {$ref: '#/components/parameters/TrunkId'} post: tags: [admin-trunks] operationId: validateTrunk security: [{SipAdminBearer: []}] requestBody: required: false content: application/json: schema: type: object additionalProperties: false properties: revision: {type: integer, minimum: 1} responses: '200': description: Validation issues, compatible Cells, and impact preview content: application/json: schema: {type: object} '401': {$ref: '#/components/responses/Unauthorized'} '404': {$ref: '#/components/responses/NotFound'} /admin/v1/trunks/{trunk_id}/verifications: parameters: - {$ref: '#/components/parameters/TrunkId'} post: tags: [admin-trunks] operationId: addTrunkVerification security: [{SipAdminBearer: []}] parameters: - {$ref: '#/components/parameters/IfMatch'} - {$ref: '#/components/parameters/RequestId'} requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/VerificationRequest' responses: '200': description: Versioned verification record content: application/json: schema: {type: object} '401': {$ref: '#/components/responses/Unauthorized'} '409': {$ref: '#/components/responses/Conflict'} /admin/v1/trunks/{trunk_id}/publish: parameters: - {$ref: '#/components/parameters/TrunkId'} post: tags: [admin-trunks] operationId: publishTrunk security: [{SipAdminBearer: []}] parameters: - {$ref: '#/components/parameters/IfMatch'} - {$ref: '#/components/parameters/RequestId'} responses: '200': description: >- Published revision after all selected Cell acknowledgements content: application/json: schema: {$ref: '#/components/schemas/AdminTrunk'} '401': {$ref: '#/components/responses/Unauthorized'} '409': {$ref: '#/components/responses/Conflict'} /admin/v1/trunks/{trunk_id}/disable: parameters: - {$ref: '#/components/parameters/TrunkId'} post: tags: [admin-trunks] operationId: disableTrunk security: [{SipAdminBearer: []}] parameters: - {$ref: '#/components/parameters/IfMatch'} - {$ref: '#/components/parameters/RequestId'} responses: '200': description: Trunk disabled after selected Cell acknowledgements content: application/json: schema: {$ref: '#/components/schemas/AdminTrunk'} '401': {$ref: '#/components/responses/Unauthorized'} '409': {$ref: '#/components/responses/Conflict'} /admin/v1/trunks/{trunk_id}/rollback: parameters: - {$ref: '#/components/parameters/TrunkId'} post: tags: [admin-trunks] operationId: rollbackTrunk security: [{SipAdminBearer: []}] parameters: - {$ref: '#/components/parameters/IfMatch'} - {$ref: '#/components/parameters/RequestId'} requestBody: required: true content: application/json: schema: type: object additionalProperties: false required: [target_revision] properties: target_revision: {type: integer, minimum: 1} responses: '200': description: >- New revision copied from the target after Cell acknowledgements content: application/json: schema: {$ref: '#/components/schemas/AdminTrunk'} '401': {$ref: '#/components/responses/Unauthorized'} '409': {$ref: '#/components/responses/Conflict'} /admin/v1/trunks/{trunk_id}/publications: parameters: - {$ref: '#/components/parameters/TrunkId'} get: tags: [admin-trunks] operationId: listTrunkPublications security: [{SipAdminBearer: []}] responses: '200': description: Per-Cell publication intents content: application/json: schema: type: object required: [mode, publications] properties: mode: {$ref: '#/components/schemas/Mode'} publications: type: array items: {$ref: '#/components/schemas/Publication'} '401': {$ref: '#/components/responses/Unauthorized'} '404': {$ref: '#/components/responses/NotFound'} /admin/v1/trunks/{trunk_id}/audit: parameters: - {$ref: '#/components/parameters/TrunkId'} get: tags: [admin-trunks] operationId: listTrunkAudit security: [{SipAdminBearer: []}] responses: '200': description: Immutable management audit entries content: application/json: schema: type: object required: [mode, audit] properties: mode: {$ref: '#/components/schemas/Mode'} audit: type: array items: {$ref: '#/components/schemas/AuditEntry'} '401': {$ref: '#/components/responses/Unauthorized'} '404': {$ref: '#/components/responses/NotFound'} /admin/v1/cells: get: tags: [admin-cells] operationId: listCells security: [{SipAdminBearer: []}] responses: '200': description: Registered multi-machine voice Cells content: application/json: schema: type: object required: [mode, cells] properties: mode: {$ref: '#/components/schemas/Mode'} cells: type: array items: {$ref: '#/components/schemas/Cell'} '401': {$ref: '#/components/responses/Unauthorized'} /admin/v1/cells/{cell_id}: parameters: - {$ref: '#/components/parameters/CellId'} get: tags: [admin-cells] operationId: getCell security: [{SipAdminBearer: []}] responses: '200': description: Registered Cell content: application/json: schema: {$ref: '#/components/schemas/Cell'} '401': {$ref: '#/components/responses/Unauthorized'} '404': {$ref: '#/components/responses/NotFound'} put: tags: [admin-cells] operationId: registerCell security: [{SipAdminBearer: []}] parameters: - {$ref: '#/components/parameters/IfMatch'} - {$ref: '#/components/parameters/RequestId'} requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/CellConfig'} responses: '200': description: Updated Cell revision content: application/json: schema: {$ref: '#/components/schemas/Cell'} '201': description: Registered Cell content: application/json: schema: {$ref: '#/components/schemas/Cell'} '401': {$ref: '#/components/responses/Unauthorized'} '409': {$ref: '#/components/responses/Conflict'} /admin/v1/cells/{cell_id}/observations: parameters: - {$ref: '#/components/parameters/CellId'} post: tags: [admin-cells] operationId: ingestCellObservation security: [{SipAdminBearer: []}] requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/ObservationInput'} responses: '201': description: >- Observation accepted for the current boot and monotonic sequence content: application/json: schema: {type: object} '401': {$ref: '#/components/responses/Unauthorized'} '409': {$ref: '#/components/responses/Conflict'} /admin/v1/egress-pools: get: tags: [admin-cells] operationId: listEgressPools security: [{SipAdminBearer: []}] responses: '200': description: Fixed egress pool directory content: application/json: schema: {type: object} '401': {$ref: '#/components/responses/Unauthorized'} /admin/v1/sip-status: get: tags: [admin-status] operationId: getSipStatus security: [{SipAdminBearer: []}] parameters: - {$ref: '#/components/parameters/CellIdsFilter'} - {$ref: '#/components/parameters/CellIdFilter'} - {$ref: '#/components/parameters/ProviderFilter'} responses: '200': description: >- Cell/trunk status matrix with freshness and missing sources content: application/json: schema: {$ref: '#/components/schemas/StatusResponse'} '401': {$ref: '#/components/responses/Unauthorized'} /admin/v1/cells/{cell_id}/sip-status: parameters: - {$ref: '#/components/parameters/CellId'} get: tags: [admin-status] operationId: getCellSipStatus security: [{SipAdminBearer: []}] parameters: - {$ref: '#/components/parameters/TrunkFilter'} responses: '200': description: One Cell status content: application/json: schema: {$ref: '#/components/schemas/StatusItem'} '401': {$ref: '#/components/responses/Unauthorized'} '404': {$ref: '#/components/responses/NotFound'} /admin/v1/providers/{provider_id}/status: parameters: - {$ref: '#/components/parameters/ProviderId'} get: tags: [admin-status] operationId: getProviderStatus security: [{SipAdminBearer: []}] responses: '200': description: Provider status matrix content: application/json: schema: {$ref: '#/components/schemas/StatusResponse'} '401': {$ref: '#/components/responses/Unauthorized'} '404': {$ref: '#/components/responses/NotFound'} /admin/v1/statistics/outbound/summary: get: tags: [admin-statistics] operationId: getOutboundSummary security: [{SipAdminBearer: []}] parameters: - {$ref: '#/components/parameters/From'} - {$ref: '#/components/parameters/To'} - {$ref: '#/components/parameters/StatsMode'} - {$ref: '#/components/parameters/ProviderFilter'} - {$ref: '#/components/parameters/TrunkFilter'} - {$ref: '#/components/parameters/CellIdFilter'} - {$ref: '#/components/parameters/EgressFilter'} responses: '200': description: Cohort and interval metrics with completeness metadata content: application/json: schema: {$ref: '#/components/schemas/StatisticsSummary'} '401': {$ref: '#/components/responses/Unauthorized'} '422': {$ref: '#/components/responses/BadRequest'} /admin/v1/statistics/outbound/timeseries: get: tags: [admin-statistics] operationId: getOutboundTimeseries security: [{SipAdminBearer: []}] parameters: - {$ref: '#/components/parameters/From'} - {$ref: '#/components/parameters/To'} - {$ref: '#/components/parameters/StatsMode'} - {$ref: '#/components/parameters/Granularity'} - {$ref: '#/components/parameters/ProviderFilter'} - {$ref: '#/components/parameters/TrunkFilter'} - {$ref: '#/components/parameters/CellIdFilter'} - {$ref: '#/components/parameters/EgressFilter'} responses: '200': description: Bounded UTC time series content: application/json: schema: {$ref: '#/components/schemas/TimeseriesResponse'} '401': {$ref: '#/components/responses/Unauthorized'} '422': {$ref: '#/components/responses/BadRequest'} /admin/v1/call-attempts: get: tags: [admin-statistics] operationId: listCallAttempts security: [{SipAdminBearer: []}] parameters: - {$ref: '#/components/parameters/From'} - {$ref: '#/components/parameters/To'} - {$ref: '#/components/parameters/StatsMode'} - {$ref: '#/components/parameters/ProviderFilter'} - {$ref: '#/components/parameters/TrunkFilter'} - {$ref: '#/components/parameters/CellIdFilter'} - {$ref: '#/components/parameters/Limit'} - {$ref: '#/components/parameters/Cursor'} - {$ref: '#/components/parameters/EgressFilter'} responses: '200': description: Redacted raw attempt facts content: application/json: schema: {type: object} '401': {$ref: '#/components/responses/Unauthorized'} /admin/v1/call-attempts/{attempt_id}: parameters: - name: attempt_id in: path required: true schema: {type: string} get: tags: [admin-statistics] operationId: getCallAttempt security: [{SipAdminBearer: []}] responses: '200': description: One redacted attempt fact content: application/json: schema: {type: object} '401': {$ref: '#/components/responses/Unauthorized'} '404': {$ref: '#/components/responses/NotFound'} /admin/v1/audit: get: tags: [admin-audit] operationId: listAudit security: [{SipAdminBearer: []}] parameters: - {$ref: '#/components/parameters/Limit'} - {$ref: '#/components/parameters/ResourceFilter'} - {$ref: '#/components/parameters/RequestFilter'} - {$ref: '#/components/parameters/ActorFilter'} responses: '200': description: Immutable audit entries content: application/json: schema: {type: object} '401': {$ref: '#/components/responses/Unauthorized'} /admin/v1/operations/{operation_id}: parameters: - name: operation_id in: path required: true schema: {type: string} get: tags: [admin-audit] operationId: getOperation security: [{SipAdminBearer: []}] responses: '200': description: Durable operation state for retry/recovery content: application/json: schema: {type: object} '401': {$ref: '#/components/responses/Unauthorized'} '404': {$ref: '#/components/responses/NotFound'} /readonly/v1/sip/trunks: get: tags: [saas-readonly] operationId: listAuthorizedTrunks security: [{SaasTrunkReadBearer: []}] responses: '200': description: Published Trunks authorized for this SaaS principal content: application/json: schema: $ref: '#/components/schemas/ReadonlyTrunkList' '401': {$ref: '#/components/responses/Unauthorized'} /readonly/v1/sip/trunks/{trunk_id}: parameters: - {$ref: '#/components/parameters/TrunkId'} get: tags: [saas-readonly] operationId: getAuthorizedTrunk security: [{SaasTrunkReadBearer: []}] responses: '200': description: Published, sanitized Trunk metadata content: application/json: schema: {$ref: '#/components/schemas/ReadonlyTrunk'} '401': {$ref: '#/components/responses/Unauthorized'} '404': {$ref: '#/components/responses/NotFound'} components: securitySchemes: SipAdminBearer: type: http scheme: bearer bearerFormat: opaque description: >- Dedicated operator/backend credential for SIP management writes. It is not accepted by the SaaS read-only API or ordinary scheduling API. SaasTrunkReadBearer: type: http scheme: bearer bearerFormat: opaque description: >- Dedicated SaaS read-only credential. It cannot publish, modify, disable, rollback, or access Cell management. parameters: ProviderId: name: provider_id in: path required: true schema: {type: string, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$'} TrunkId: name: trunk_id in: path required: true schema: {type: string, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$'} CellId: name: cell_id in: path required: true schema: {type: string, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$'} IfMatch: name: If-Match in: header required: true description: Exact latest revision required for CAS; quotes are accepted. schema: {type: integer, minimum: 0} CellIdsFilter: name: cell_ids in: query required: false schema: {type: string} CellIdFilter: name: cell_id in: query required: false schema: {type: string} ProviderFilter: name: provider_id in: query required: false schema: {type: string} TrunkFilter: name: trunk_id in: query required: false schema: {type: string} TrunkStatusFilter: name: status in: query required: false schema: {type: string} ResourceFilter: name: resource_id in: query required: false schema: {type: string} ActorFilter: name: actor in: query required: false schema: {type: string} From: name: from in: query required: false schema: {type: string, format: date-time} To: name: to in: query required: false schema: {type: string, format: date-time} StatsMode: name: mode in: query required: false schema: {type: string, enum: [mock, mixed, real]} EgressFilter: name: egress_pool_id in: query required: false schema: {type: string} Granularity: name: granularity in: query required: false schema: {type: string, enum: [minute, hour, day]} Limit: name: limit in: query required: false schema: {type: integer, minimum: 1, maximum: 200} Cursor: name: cursor in: query required: false schema: {type: string} RequestFilter: name: request_id in: query required: false schema: {type: string} RequestId: name: X-Request-ID in: header required: true schema: {type: string, minLength: 1, maxLength: 128} responses: BadRequest: description: Invalid configuration or request content: application/json: schema: {$ref: '#/components/schemas/ErrorResponse'} Unauthorized: description: Missing or wrong authentication domain content: application/json: schema: {$ref: '#/components/schemas/ErrorResponse'} Forbidden: description: Credential lacks the required scope content: application/json: schema: {$ref: '#/components/schemas/ErrorResponse'} Conflict: description: CAS conflict or no compatible Cell content: application/json: schema: {$ref: '#/components/schemas/ErrorResponse'} NotFound: description: Resource is not visible or does not exist content: application/json: schema: {$ref: '#/components/schemas/ErrorResponse'} schemas: Mode: type: string enum: [mock, real] StatsMode: type: string enum: [mock, mixed, real] Health: type: object additionalProperties: false required: [status, mode] properties: status: {type: string, const: ok} mode: {$ref: '#/components/schemas/Mode'} CodecProfile: type: object additionalProperties: false required: [allowed, preferred] properties: allowed: type: array minItems: 1 uniqueItems: true items: {type: string, enum: [PCMA, PCMU]} preferred: {type: string, enum: [PCMA, PCMU]} SipConfig: type: object additionalProperties: false required: [host, port, transport, auth_mode, register] properties: host: {type: string, minLength: 1, maxLength: 253} port: {type: integer, minimum: 1, maximum: 65535} transport: {type: string, enum: [udp, tcp, tls]} auth_mode: {type: string, enum: [ip, digest]} register: {type: boolean} credential_ref: type: string writeOnly: true description: >- Secret-store reference only; plaintext credentials are forbidden. VerificationRequest: type: object additionalProperties: false required: [revision, check_name, result] properties: revision: {type: integer, minimum: 1} check_name: type: string enum: - transport - registration_auth - caller_id_rules - codec - capacity - whitelist result: type: string enum: [confirmed, failed, unknown, not_applicable] evidence_ref: {type: string, maxLength: 512} checked_by: {type: string, maxLength: 128} TrunkConfig: type: object additionalProperties: false required: - provider_id - display_name - enabled - sip - codec_profile - caller_ids - dial_prefix - egress_pool_id - max_concurrency - max_cps properties: provider_id: type: string pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$' display_name: {type: string, minLength: 1, maxLength: 256} enabled: {type: boolean} sip: {$ref: '#/components/schemas/SipConfig'} codec_profile: {$ref: '#/components/schemas/CodecProfile'} caller_ids: type: array minItems: 1 uniqueItems: true items: {type: string, minLength: 1, maxLength: 128} dial_prefix: {type: string, maxLength: 32} egress_pool_id: type: string pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$' max_concurrency: {type: integer, minimum: 1} max_cps: {type: integer, minimum: 1} CellConfig: type: object additionalProperties: false required: [egress_pool_id, codec_capabilities, status, max_concurrency] properties: egress_pool_id: type: string pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$' codec_capabilities: type: array minItems: 1 uniqueItems: true items: {type: string, enum: [PCMA, PCMU]} status: {type: string, enum: [healthy, draining, disabled]} max_concurrency: {type: integer, minimum: 1} management_url: type: string format: uri pattern: '^https://' description: >- mTLS Cell Agent endpoint. Required when mode=real; credentials and query strings are not allowed. RevisionInfo: type: object additionalProperties: false required: [revision, state, created_at, created_by] properties: revision: {type: integer, minimum: 1} state: {type: string, enum: [draft, publishing, published, superseded]} config_sha256: {type: string, pattern: '^[a-f0-9]{64}$'} created_at: {type: string, format: date-time} created_by: {type: string} AdminTrunk: type: object required: - mode - trunk_id - provider_id - latest_revision - active_revision - active_status - status - compatible_cell_ids - latest - active - versions properties: mode: {$ref: '#/components/schemas/Mode'} trunk_id: {type: string} provider_id: {type: string} latest_revision: {type: integer, minimum: 1} active_revision: {type: integer, minimum: 0} active_status: {type: string, enum: [draft, published, disabled]} status: {type: string, enum: [draft, published, disabled]} updated_at: {type: string, format: date-time} compatible_cell_ids: {type: array, items: {type: string}} latest: {$ref: '#/components/schemas/TrunkView'} active: {$ref: '#/components/schemas/TrunkView'} versions: type: array items: $ref: '#/components/schemas/RevisionInfo' TrunkView: allOf: - {$ref: '#/components/schemas/TrunkConfig'} - type: object properties: trunk_id: {type: string} credential_configured: {type: boolean} asterisk_allow: type: array items: {type: string, enum: [alaw, ulaw]} config_sha256: {type: string, pattern: '^[a-f0-9]{64}$'} ReadonlyTrunk: type: object required: - mode - trunk_id - provider_id - revision - status - config properties: mode: {$ref: '#/components/schemas/Mode'} trunk_id: {type: string} provider_id: {type: string} revision: {type: integer, minimum: 1} status: {type: string, const: published} updated_at: {type: string, format: date-time} config: {$ref: '#/components/schemas/TrunkView'} AdminTrunkList: type: object required: [mode, trunks] properties: mode: {$ref: '#/components/schemas/Mode'} trunks: {type: array, items: {$ref: '#/components/schemas/AdminTrunk'}} ReadonlyTrunkList: type: object required: [mode, trunks] properties: mode: {$ref: '#/components/schemas/Mode'} trunks: type: array items: $ref: '#/components/schemas/ReadonlyTrunk' Cell: type: object required: [mode, cell_id, revision, config, updated_at, updated_by] properties: mode: {$ref: '#/components/schemas/Mode'} cell_id: {type: string} revision: {type: integer, minimum: 1} config: {$ref: '#/components/schemas/CellConfig'} cloud_instance_id: {type: string} instance_name: {type: string} region: {type: string} boot_id: {type: string} updated_at: {type: string, format: date-time} updated_by: {type: string} Publication: type: object required: [trunk_id, revision, cell_id, status, updated_at] properties: trunk_id: {type: string} revision: {type: integer, minimum: 1} cell_id: {type: string} status: {type: string, enum: [pending, applied, failed]} error_code: {type: [string, 'null']} applied_at: {type: [string, 'null'], format: date-time} target_digest: {type: string} local_revision: {type: integer, minimum: 0} local_digest: {type: string} operation_id: {type: string} updated_at: {type: string, format: date-time} AuditEntry: type: object required: - audit_id - resource_type - resource_id - action - revision - actor - details_json - created_at properties: audit_id: {type: string} resource_type: {type: string, const: trunk} resource_id: {type: string} action: type: string enum: [ upsert, publish, publish_failed, disable, disable_failed, rollback, rollback_failed, ] revision: {type: integer, minimum: 0} actor: {type: string} request_id: {type: [string, 'null']} details_json: {type: string} created_at: {type: string, format: date-time} ProviderInput: type: object additionalProperties: false required: [display_name, lifecycle] properties: display_name: {type: string, minLength: 1, maxLength: 256} notes: {type: string, maxLength: 2000} lifecycle: {type: string, enum: [active, archived]} Provider: allOf: - {$ref: '#/components/schemas/ProviderInput'} - type: object required: [provider_id, revision, trunk_count, created_at, updated_at] properties: provider_id: {type: string} revision: {type: integer, minimum: 1} trunk_count: {type: integer, minimum: 0} created_at: {type: string, format: date-time} updated_at: {type: string, format: date-time} updated_by: {type: string} ProviderList: type: object required: [mode, providers] properties: mode: {$ref: '#/components/schemas/Mode'} providers: {type: array, items: {$ref: '#/components/schemas/Provider'}} ProviderResponse: type: object required: [mode, provider] properties: mode: {$ref: '#/components/schemas/Mode'} provider: {$ref: '#/components/schemas/Provider'} ObservationInput: type: object additionalProperties: false required: [cell_id, boot_id, sequence, observed_at, source, states] properties: observation_id: {type: string} cell_id: {type: string} trunk_id: {type: string} boot_id: {type: string, minLength: 1} sequence: {type: integer, minimum: 1} observed_at: {type: string, format: date-time} source: {type: string} config_revision: {type: integer, minimum: 0} states: {type: object} occupancy: {type: object} sample_id: {type: string} StatusItem: type: object required: [mode, cell_id, availability, complete, missing_sources] properties: mode: {$ref: '#/components/schemas/Mode'} cell_id: {type: string} availability: {type: string, enum: [healthy, stale, unknown, disabled]} complete: {type: boolean} observed_at: {type: [string, 'null'], format: date-time} received_at: {type: [string, 'null'], format: date-time} observation_age_seconds: {type: [integer, 'null'], minimum: 0} clock_skew: {type: boolean} reason: {type: string} boot_id: {type: string} sequence: {type: integer, minimum: 1} config_revision: {type: integer, minimum: 1} config_status: {type: string} egress_pool_id: {type: string} eligibility: {type: string} missing_sources: {type: array, items: {type: string}} states: {type: object} occupancy: {type: object} trunks: {type: array, items: {type: object}} publication: {type: object} StatusResponse: type: object required: [mode, complete, cells] properties: mode: {$ref: '#/components/schemas/Mode'} complete: {type: boolean} generated_at: {type: string, format: date-time} data_as_of: {type: [string, 'null'], format: date-time} coverage: {type: object} cells: {type: array, items: {$ref: '#/components/schemas/StatusItem'}} StatisticsSummary: type: object required: [mode, from, to, complete, metrics] properties: mode: {$ref: '#/components/schemas/StatsMode'} from: {type: string, format: date-time} to: {type: string, format: date-time} timezone: {type: string} definition_version: {type: string} filters: {type: object} complete: {type: boolean} missing_sources: {type: array, items: {type: string}} unresolved_count: {type: integer, minimum: 0} data_as_of: {type: [string, 'null'], format: date-time} metrics: {type: object} failure_reasons: {type: array, items: {type: object}} realtime: {type: object} TimeseriesResponse: type: object required: [mode, from, to, granularity, complete, series] properties: mode: {$ref: '#/components/schemas/StatsMode'} from: {type: string, format: date-time} to: {type: string, format: date-time} timezone: {type: string} definition_version: {type: string} filters: {type: object} granularity: {type: string, enum: [minute, hour, day]} complete: {type: boolean} series: {type: array, items: {type: object}} ErrorResponse: type: object required: [error] properties: error: type: object required: [code, message] properties: code: {type: string} message: {type: string} fields: {type: object} request_id: {type: string}