The experimental contract
sipx-host uses this contract with document-mode webhooks and authenticated full-duplex sessions.
The Rust vocabulary and interpreter are Supported under the pre-1.0 policy, but the wire shape may
change without a migration path. An embedded handler and packaged language SDK are not implemented.
The normative definition, including validation, ordering, failure semantics, authentication, and
test vectors, is
docs/specs/app-contract.md.
This page is a non-normative tour.
Event envelope
An event identifies the contract version and sequence and carries a call snapshot:
{
"contract": "sipx.app.v1",
"seq": 4,
"at": "2026-07-28T09:15:04.221Z",
"call": {
"id": "b7c1…",
"direction": "inbound",
"state": "answered",
"from": "sip:alice@example.com",
"to": "sip:support@example.net",
"media": { "encrypted": true, "on_hold": false, "muted": false }
},
"event": { "type": "call.dtmf", "digit": "5", "duration_ms": 160 }
}
The vocabulary covers incoming, ringing, answered, and ended calls; DTMF; playback, gather, recording, and dial completion; transfer progress; bridge state; and hold state.
Instruction program
Customer code answers with an ordered program. Its instruction identifiers are echoed by the corresponding completion events:
{
"contract": "sipx.app.v1",
"instructions": [
{ "id": "p1", "do": "play", "source": { "file": "welcome.wav" }, "interruptible": true },
{ "id": "g1", "do": "gather", "max": 4, "terminators": "#", "timeout_ms": 10000 }
]
}
The vocabulary includes answer, ring, reject, play, gather, record, DTMF, dial, bridge, hold, mute, transfer, pause, tag, and hangup operations. A word in the contract is not itself evidence that the current host or public call API can perform that operation end to end.
Replacement and ordering
In webhook mode, a response replaces the entire pending program. Responding to a digit event with a new program therefore removes queued prompt work without a separate cancel instruction. At most one callback is outstanding per call; events that happen meanwhile queue and are delivered in sequence with a current snapshot.
Session mode is full duplex for actions that need not alternate with callbacks, such as originating a call or acting on an external command. The embedded mode is intended to preserve the same session semantics without a wire boundary.
The host implements both rules: document-mode webhook responses replace the pending program, and a
session controller may send correlated replacement documents without waiting for a callback.
Session calls remain pinned to one authenticated connection, and an app granted originate may
place a call through that connection. Embedded mode remains an intended carrier, not a shipped one.
Failure policy
The configuration declares a callback timeout and an action for timeout, an unreachable app, and 4xx or 5xx responses. Depending on the condition, the policy may continue the current program, hang up, or reject the call. The default preserves already-scripted work instead of ending an active call merely because the next callback cannot be reached.
This policy is active in the current host. Webhook connection, timeout, and HTTP failures are fed
to the interpreter; session loss applies on_unreachable independently to every pinned call. An
embedded handler cannot be selected as a working binding because no embedded runtime is shipped.
See the application host overview for the implementation boundary and the supported alternatives available today.