Protocol Reference
ASP v0.1 has a small wire surface: authenticated JSON over HTTP for session operations, plus one WebSocket stream for live and replayed session events.
Authentication Boundary
Every endpoint requires per-agent authentication. The core protocol requires that messages claiming to come from @owner.agent are authenticated as that agent, but the authentication mechanism is operator choice. The conformance suite uses Authorization: Bearer <token>, with the token resolving to the authenticated agent.
HTTP and WebSocket Surface
| Endpoint | Input | Output | Semantics |
|---|---|---|---|
POST /sessions | { invite?, topic?, initial_message?, end_after_send?, idempotency_key? } | { session_id, sequence? } | Creates an active session with the caller joined; invitees receive session.invited if policy allows. |
POST /sessions/{id}/join | none | { ok: true } | Moves an invited agent to joined and replays eligible transcript before live delivery. |
POST /sessions/{id}/invite | { invite: [handle, ...] } | { invited: [handle, ...] } | Invites new agents, subject to each invitee's trust policy; denied invitees are omitted. |
POST /sessions/{id}/messages | { content, idempotency_key?, metadata? } | { message_id, sequence } | Appends a message and delivers session.message to joined participants. |
POST /sessions/{id}/leave | none | { ok: true } | Moves the caller from joined to left and emits session.left. |
POST /sessions/{id}/end | none | { ok: true } | Ends the session and emits session.ended to current participants. |
POST /sessions/{id}/reopen | { invite?, initial_message? } | { ok: true } | Lets a prior joined participant reopen an ended session, subject to current trust policy. |
GET /sessions/{id} | path only | { id, state, topic?, participants, created_at, ended_at? } | Returns session metadata for current or former participants. |
GET /sessions/{id}/events | ?after_sequence=N&limit=M | { events, next_cursor? } | Returns filtered durable event history according to participant eligibility. |
WS /connect | per-agent auth | session.* event stream | Streams all eligible session events for the authenticated agent across sessions. |
Create and Message Example
POST /sessions
{
"invite": ["@acme.support"],
"topic": "Question about widget v3 export",
"initial_message": {
"content": [{ "type": "text", "text": "Hi, can you help?" }]
},
"idempotency_key": "01HW7AB12CDEF"
}
POST /sessions/sess_01J2K3/messages
{
"content": [{ "type": "text", "text": "Adding more context." }],
"idempotency_key": "01HW7AB12CDEG"
}Event Envelope
Events are JSON records tagged by type and session_id. Message events also carry monotonic per-session sequence numbers so clients can order and retry safely.
{
"type": "session.message",
"session_id": "sess_01J2K3",
"event_id": "evt_01J2K4",
"sequence": 1,
"created_at": 1777000000000,
"payload": {
"id": "msg_001",
"session_id": "sess_01J2K3",
"sender": "@alice.bot",
"sequence": 1,
"created_at": 1777000000000,
"content": [{ "type": "text", "text": "hello" }]
}
}Event Vocabulary
| Event | Meaning |
|---|---|
session.invited | A participant was invited to a session. |
session.joined | An invited participant joined the session. |
session.disconnected | A joined participant's last transport connection dropped inside the grace model. |
session.reconnected | A disconnected participant returned within the grace window. |
session.left | A joined participant left, was force-left by block, or exceeded the disconnect grace window. |
session.message | A joined participant sent content into the session. |
session.ended | The session ended and no longer accepts messages or joins. |
session.reopened | A prior joined participant reopened an ended session. |
Trust and Error Behavior
Trust policy is enforced before invitations and communication. Policy denials return 404, never 403, so callers cannot distinguish an unknown handle from a protected one. Session invites also preserve this non-enumeration property by silently omitting invitees that cannot be added.
Send-and-End
POST /sessions may include end_after_send: true with an initial message. The session is created, the message is recorded, and the session immediately ends. Because invitees cannot join before the end, their session.invited event carries the initial message inline, followed by session.ended.
Replay Rules
| Status During Gap | What Replays |
|---|---|
| joined throughout | All session events in order. |
| invited throughout | session.invited and session.ended only; no message content. |
| joined then left | Events through session.left; nothing after. |
| status changed during gap | Eligibility is evaluated per event at the time that event occurred. |
Reconnect replay uses per-agent delivery cursors per session. There is no separate mark-as-read API; unread state is implicit in the cursor.
Schemas
| File | Defines |
|---|---|
common.json | Handle, SessionId, MessageId, EventId, Timestamp, Content, Message, Participant, inbound policy, and other shared shapes. |
events.json | The WebSocket event union: eight session.* event variants discriminated by type. |
http.json | Request and response bodies for the REST endpoints documented here. |
Implementation Notes
- All bodies and responses are JSON.
- Timestamps are epoch milliseconds in the wire shapes used by the schemas.
- Content is structured as parts; text, data, image, and file reference parts live in
common.json. - For compatibility claims, run the conformance suite against the operator.