Files
agent-call/docs/contracts/cell-agent.openapi.yaml

226 lines
7.2 KiB
YAML

# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema
openapi: 3.1.0
info:
title: agent-call Cell Agent API
version: 1.0.0
description: >-
Restricted mTLS API used by the SIP management backend to deliver a
versioned Trunk snapshot to one voice Cell. The Cell validates the SHA-256
snapshot, applies it with an atomic file replacement, reloads Asterisk,
restores the previous file on reload failure, and returns applied only
after the reload succeeds. A disabled snapshot removes the Cell-local
Trunk fragment and reloads Asterisk.
servers:
- url: https://cell.internal:9443
description: Cell management network only
tags:
- name: health
- name: trunk-apply
paths:
/healthz/live:
get:
tags: [health]
operationId: live
responses:
'200':
description: Cell Agent is alive
content:
application/json:
schema: {$ref: '#/components/schemas/Health'}
/v1/sip/trunks/{trunk_id}/apply:
parameters:
- {$ref: '#/components/parameters/TrunkId'}
post:
tags: [trunk-apply]
operationId: applyTrunk
security: [{CellManagementMtls: []}]
parameters:
- {$ref: '#/components/parameters/RequestId'}
requestBody:
required: true
content:
application/json:
schema: {$ref: '#/components/schemas/Publication'}
responses:
'200':
description: Asterisk has loaded the exact snapshot
content:
application/json:
schema: {$ref: '#/components/schemas/Acknowledgement'}
'400': {$ref: '#/components/responses/BadRequest'}
'403': {$ref: '#/components/responses/Forbidden'}
'409':
description: Revision is stale or has a gap
content:
application/json:
schema: {$ref: '#/components/schemas/ErrorResponse'}
'502':
description: Asterisk rejected the apply or reload
content:
application/json:
schema: {$ref: '#/components/schemas/ErrorResponse'}
/v1/sip/trunks/{trunk_id}/state:
parameters:
- {$ref: '#/components/parameters/TrunkId'}
get:
tags: [trunk-apply]
operationId: getTrunkState
security: [{CellManagementMtls: []}]
responses:
'200':
description: Durable Cell apply state
content:
application/json:
schema: {$ref: '#/components/schemas/State'}
'404': {$ref: '#/components/responses/NotFound'}
components:
securitySchemes:
CellManagementMtls:
type: mutualTLS
description: Management backend client certificate signed by the Cell CA.
parameters:
TrunkId:
name: trunk_id
in: path
required: true
schema: {type: string, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$'}
RequestId:
name: X-Request-ID
in: header
required: true
schema: {type: string, minLength: 1, maxLength: 128}
schemas:
Health:
type: object
additionalProperties: false
required: [status, mode, cell_id]
properties:
status: {type: string, const: ok}
mode: {type: string, const: real}
cell_id: {type: string}
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, credential_ref]
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, 'null']
description: Secret-store reference only; plaintext is forbidden.
TrunkConfig:
type: object
additionalProperties: false
required:
- display_name
- enabled
- sip
- codec_profile
- caller_ids
- dial_prefix
- egress_pool_id
- max_concurrency
- max_cps
properties:
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}
max_concurrency: {type: integer, minimum: 1}
max_cps: {type: integer, minimum: 1}
Publication:
type: object
additionalProperties: false
required: [mode, cell_id, trunk_id, revision, config, config_sha256]
properties:
mode: {type: string, const: real}
cell_id: {type: string}
trunk_id: {type: string}
revision: {type: integer, minimum: 1}
config: {$ref: '#/components/schemas/TrunkConfig'}
config_sha256:
type: string
pattern: '^[0-9a-f]{64}$'
Acknowledgement:
type: object
additionalProperties: false
required:
[mode, cell_id, trunk_id, revision, config_sha256, status, idempotent]
properties:
mode: {type: string, const: real}
cell_id: {type: string}
trunk_id: {type: string}
revision: {type: integer, minimum: 1}
config_sha256: {type: string, pattern: '^[0-9a-f]{64}$'}
status: {type: string, const: applied}
idempotent: {type: boolean}
State:
type: object
additionalProperties: false
required:
[
mode,
cell_id,
trunk_id,
desired_revision,
applied_revision,
status,
updated_at,
]
properties:
mode: {type: string, const: real}
cell_id: {type: string}
trunk_id: {type: string}
desired_revision: {type: integer, minimum: 1}
applied_revision: {type: integer, minimum: 0}
status: {type: string, enum: [applying, applied, failed]}
last_error: {type: [string, 'null']}
updated_at: {type: string, format: date-time}
ErrorResponse:
type: object
required: [error]
properties:
error:
type: object
required: [code, message]
properties:
code: {type: string}
message: {type: string}
responses:
BadRequest:
description: Invalid publication or hash
content:
application/json:
schema: {$ref: '#/components/schemas/ErrorResponse'}
Forbidden:
description: Certificate or Cell identity is not authorized
content:
application/json:
schema: {$ref: '#/components/schemas/ErrorResponse'}
NotFound:
description: State does not exist
content:
application/json:
schema: {$ref: '#/components/schemas/ErrorResponse'}