Transport Sse

AEP Transport Binding: HTTP SSE

> Status: draft. Part of the AEP 0.1 protocol specification.

Purpose

Define how AEP runs over HTTP Server-Sent Events (SSE), supporting server-to-client event streams with a separate HTTP endpoint for client-to-server messages.

Model

SSE is a unidirectional transport (server → client). AEP over SSE uses two HTTP channels:

ChannelMethodDirectionContent-Type
Event streamGETServer → Clienttext/event-stream
Ingest endpointPOSTClient → Serverapplication/x-ndjson

Event Stream (GET)

The client opens a long-lived GET request to receive AEP events as SSE.

Request

GET /aep/events?session_id=sess_01 HTTP/1.1
Accept: text/event-stream

The session_id query parameter identifies the session. Multiple clients may share a session via distinct SSE connections.

Response

HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

SSE Event Format

Each AEP event is sent as an SSE message:

id: evt_01JZ0000000000000000000000
event: task.progress
data: {"aep_version":"0.1","id":"evt_01JZ0000000000000000000000","type":"task.progress",...}

Rules:

Reconnection

The SSE Last-Event-ID mechanism supports cursor recovery:

Heartbeat

The server sends SSE comments as keep-alive when no AEP events are generated within a negotiated interval:

: heartbeat

Comment lines start with : and are ignored by SSE clients. A client that receives no data (events or comments) for 3 × heartbeat_interval_ms should close and reconnect.

Ingest Endpoint (POST)

The client sends AEP events to the server via HTTP POST.

Request

POST /aep/events?session_id=sess_01 HTTP/1.1
Content-Type: application/x-ndjson

Body: one or more newline-delimited JSON events.

Response

HTTP/1.1 202 Accepted
Content-Type: application/json

{"accepted": 3, "rejected": 0}

The response body summarizes acceptance:

{
  "accepted": 3,
  "rejected": 0,
  "errors": []
}

Rejected events (due to validation or other errors) are listed:

{
  "accepted": 1,
  "rejected": 2,
  "errors": [
    {"event_index": 1, "error": {"code": "invalid_envelope", "message": "missing required field: id"}},
    {"event_index": 2, "error": {"code": "invalid_event_type", "message": "unknown event type: custom.foo"}}
  ]
}

Session Lifecycle

HTTP InteractionSession State
GET event stream establishedOPENED
session.ready received via SSEREADY
GET connection closed (client)CLOSED after grace period
POST receives session.closedCLOSED
Both channels idle > timeoutERROR via session.timeout

A session remains open as long as either the event stream or the ingest endpoint is active. The server may close the session after a configurable idle timeout.

Error Handling

ScenarioResponse
Invalid JSON in POST body400 Bad Request
Unknown session_id404 Not Found
POST to closed session410 Gone
Server internal error500 Internal Server Error with error event on SSE

Implementation Notes