CorebanqCorebanq Developer Docs
Notificationsv1

Server-Sent Events stream

Opens a text/event-stream connection. NOT a JSON route: the 200 body is a stream, not a document. Frames: an initial `event: open` with data {"message": "Connection established"}; one frame per notification; a `: keepalive` comment every notifications.sse.heartbeat_seconds (default 25, and a non-positive configured value falls back to 25); and, on graceful shutdown, a final `event: close` with data {"reason": "server_shutdown"} that the manager flushes to every connected client BEFORE cancelling them. Treat that frame as "do not reconnect immediately" — it exists so a client can back off instead of retrying into a draining server. On connect the server replays system notifications the client missed, in two passes around registration so the handshake window is not skipped. THIS ROUTE HAS TWO 503 SHAPES AND THE SHUTDOWN MAP IS NEITHER. health.LifecycleMiddleware explicitly SKIPS /v1/notifications/sse, so that map never appears here. See the 503 below for the two that do. ACCESS-CONTROL-ALLOW-ORIGIN IS ECHOED FROM THE REQUEST'S Origin HEADER VERBATIM on the stream itself. The handler's OPTIONS branch, however, is dead code and no preflight ever reaches it: auth.CORSMiddleware is mounted on the root router ahead of everything and answers a preflight carrying an Origin itself — a bodiless 200 when the origin is allowed, 403 when it is not — while a preflight WITHOUT an Origin header falls through to chi, which has only GET and POST registered for this pattern and answers 405.

GET
/v1/notifications/sse

Authorization

BearerAuth
AuthorizationBearer <token>

In: header

Response Body

text/event-stream

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/notifications/sse"
"event: open\ndata: {\"message\": \"Connection established\"}\n\n: keepalive\n\nevent: close\ndata: {\"reason\": \"server_shutdown\"}\n\n"
{
  "status": 400,
  "message": "Invalid user id",
  "code": "notifications_m.invalid_user_id",
  "class": "validation"
}
{
  "status": 401,
  "message": "Unauthorized",
  "code": "common.unauthorized",
  "class": "business"
}
{
  "status": 403,
  "message": "No access to the record",
  "code": "common.rbac_no_rec_access",
  "class": "business"
}
{
  "status": 429,
  "message": "Rate limit for 203.0.113.10 to 8f1d2c34-5b6e-4a70-9c81-2d3e4f5a6b7c exceeded.",
  "code": "rate_limits_m.exceeded",
  "class": "temporary",
  "retryable": true
}
{
  "status": 500,
  "message": "Internal server error",
  "code": "common.server_error",
  "class": "business"
}
{
  "status": 503,
  "message": "Internal server error",
  "code": "auth_m.internal_server_error",
  "class": "temporary",
  "retryable": true
}