Skip to main content

Live updates (Server-Sent Events)

The management API exposes a Server-Sent Events (SSE) stream so open browser sessions can react when configuration changes are saved—without polling and without putting full resource bodies on the event bus.

Endpoint

MethodPathAuth
GET/api/v1/events/streamManagement API OIDC session (same roles as other management routes; viewer and above can connect)

Send the same Bearer access token you use for other management API calls. The response has Content-Type: text/event-stream. The server may send comment lines (: ping) as keep-alives.

Event shape

Each data: line is a JSON object. There is no full resource body in the payload—only identifiers and change hints so clients can decide whether to refetch.

Common fields

FieldMeaning
schema_versionEnvelope version (currently 1).
resource_kindproxy_workflow, collection, proxy, credential, policy, client, profile, or future kinds.
actor_subOIDC sub of the user who performed the persist (when available).
occurred_at_unixUnix seconds when the event was emitted.

When resource_kind is proxy_workflow

FieldMeaning
proxy_idAffected proxy.
definition_changedtrue if the workflow definition content changed.
enabled_changedtrue if the workflow enabled flag changed.
workflow_enabledCurrent enabled state after the persist.

When resource_kind is collection

FieldMeaning
collection_idPrimary collection id for the operation (source id for duplicated).
operationOne of: created, updated, deleted, status_changed, duplicated, imported, openapi_imported.
related_collection_idSet for duplicated — the new collection id.

When resource_kind is proxy

Proxy metadata CRUD (not workflow definition saves—those use proxy_workflow). No full proxy body on the wire.

FieldMeaning
proxy_idAffected proxy.
collection_idCollection that owns the proxy (for client-side filtering).
operationOne of: created, updated, deleted.

When resource_kind is credential

API credentials CRUD (stored secrets metadata—not connection validation). No secrets on the wire.

FieldMeaning
credential_idAffected credential record.
operationOne of: created, updated, deleted.

When resource_kind is policy

API access policies (rate limits / quotas). No policy body on the wire.

FieldMeaning
policy_idAffected policy.
operationOne of: created, updated, deleted, status_changed.

When resource_kind is client

Management API client records (distinct from OAuth client terminology). No client body on the wire.

FieldMeaning
client_idAffected API client id.
operationOne of: created, updated, deleted, status_changed.

When resource_kind is profile

Management access profiles (nested under an API client). No profile body on the wire. The client_id field is the parent API client id (not a resource_kind: client event).

FieldMeaning
profile_idAffected access profile id.
client_idParent API client id (owner).
operationOne of: created, updated, deleted.

What emits events today

Workflow (resource_kind: proxy_workflow)

TriggerEmits
Successful PUT /api/v1/proxies/:id/workflow (save definition and/or toggle enabled)Yes

Validation-only and workflow test/stream endpoints do not emit workflow events.

Collection (resource_kind: collection)

Triggeroperation
POST /api/v1/collectionscreated
PUT /api/v1/collections/:idupdated
DELETE /api/v1/collections/:iddeleted
PUT /api/v1/collections/:id/statusstatus_changed
POST /api/v1/collections/:id/duplicateduplicated (related_collection_id = new id)
POST /api/v1/collections/.../import (multipart import)imported
POST /api/v1/collections/import/openapiopenapi_imported

Read-only routes (list, get, export file, OpenAPI download, bulk export) do not emit.

Proxy metadata (resource_kind: proxy)

Triggeroperation
POST /api/v1/proxiescreated
PUT /api/v1/proxies/:idupdated
DELETE /api/v1/proxies/:iddeleted

Workflow definition updates use proxy_workflow (see above), not proxy.

API credentials (resource_kind: credential)

Triggeroperation
POST /api/v1/credentialscreated
PUT /api/v1/credentials/:idupdated
DELETE /api/v1/credentials/:iddeleted

GET list/detail, POST /api/v1/credentials/validate, and other non-persisting routes do not emit.

API access policies (resource_kind: policy)

Triggeroperation
POST /api/v1/policiescreated
PUT /api/v1/policies/:idupdated
PUT /api/v1/policies/:id/toggle-statusstatus_changed
DELETE /api/v1/policies/:iddeleted

GET list/detail do not emit.

API clients (resource_kind: client)

Triggeroperation
POST /api/v1/clientscreated
PUT /api/v1/clients/:idupdated
PUT /api/v1/clients/:id/statusstatus_changed
DELETE /api/v1/clients/:iddeleted

GET list/detail do not emit.

Access profiles (resource_kind: profile)

Triggeroperation
POST /api/v1/clients/:clientId/profilescreated
PUT /api/v1/clients/:clientId/profiles/:idupdated
POST /api/v1/clients/:clientId/profiles/:id/rotateupdated (after a successful rotate; OIDC/mTLS no-op responses do not emit)
PUT /api/v1/clients/:clientId/profiles/:id/auth-typeupdated
DELETE /api/v1/clients/:clientId/profiles/:iddeleted

GET list/detail/credentials and GET /api/v1/auth/config do not emit.

UI behavior (Workflow Builder)

On the proxy Workflow Builder page, if your local editor has no unsaved changes and an event arrives for the same proxy_id and proxy_workflow, the UI refetches the workflow from the API. If you have unsaved edits, the UI shows a non-destructive banner so you can reload when ready or keep editing.

Sessions opened via Zerq Copilot or Management MCP use the same PUT workflow API; saves from those tools produce the same events for other tabs.

UI behavior (Collection detail and edit)

On Collection detail (/collections/:id), matching collection events refetch collection and proxy list data. deleted navigates back to the collection list. duplicated shows a short notice with the new collection id.

A separate subscription uses resource_kind: proxy for the same collection_id: when another session creates, updates, or deletes a proxy in that collection, the page refetches the proxy list only (no full navigation). This keeps the proxy table in sync without conflating workflow-definition saves (proxy_workflow) with proxy CRUD.

On Collection edit, a banner offers Reload to pull the latest server state without silently overwriting an in-progress form.

On the Collections list (/collections), the UI subscribes with useManagementEvents({ collectionList: true }) and silently refetches the list when any resource_kind: collection event arrives (create, update, delete, etc.), so other tabs or users’ changes appear without a manual refresh.

On the API Credentials list (/credentials), the UI subscribes with useManagementEvents({ credentialsList: true }) and silently refetches when any resource_kind: credential event arrives. On Edit credentials (/credentials/edit/:id), a banner with Reload appears when an updated event targets the same credential; deleted navigates back to the list.

On the API Access Policies page (/policies), the UI subscribes with useManagementEvents({ policiesList: true }) and silently refetches the grid when any resource_kind: policy event arrives. The create and edit modals subscribe by policy_id when editing an existing policy: remote updated / status_changed shows a Reload banner; remote deleted closes the modal and refreshes the list.

On the API Clients page (/clients), the UI subscribes with useManagementEvents({ clientsList: true }) and silently refetches clients plus collection/policy dropdown data when any resource_kind: client event arrives. The create and edit modals subscribe by client_id when editing an existing client: remote updated / status_changed shows a Reload banner; remote deleted closes the modal and refreshes the list.

On the Access profiles page for an API client (/clients/:id/profiles), the UI subscribes with useManagementEvents({ accessProfilesForClient: true, parentClientId }) and silently refetches when any resource_kind: profile event targets that parent client. The edit profile modal and authentication modal subscribe by profile_id when open: remote updated shows a Reload banner; remote deleted closes the modal and refreshes the list.

Operational notes

  • With Redis cache enabled, events are also published on a Redis channel so multiple API pods each fan out to their local SSE subscribers.
  • Without Redis, events are delivered in-process only (suitable for single-node dev).

For package layout, Redis channel name, and subscriber roadmap, operators and engineers should read the internal runbook at zerq-docs/docs/_internal/management-domain-events-sse.md in the repository.