kisenon

Streams de eventos

Server-sent events para atividade de organização e projeto.

A Kisenon transmite a atividade de organização e projeto como Server-Sent Events. Abra uma conexão HTTP de vida longa, defina Accept: text/event-stream, e o control plane envia um envelope JSON toda vez que algo muda.

O console alimenta suas visões de atividade ao vivo a partir do mesmo stream.

Endpoints

Duas rotas, ambas SSE:

RotaEscopo
GET /v1/eventsTodo projeto na organização do chamador.
GET /v1/projects/{id}/eventsUm único projeto.

Ambas vivem sob https://api.test.kisenon.com. A rota com escopo de projeto retorna 404 se o projeto não pertencer à sua organização, então a existência nunca vaza entre organizações.

Autenticação

Mesma credencial Bearer de toda outra chamada do control plane: uma chave de API (nsk_…) ou um JWT web assinado pelo cp. Veja Autenticação. O chamador deve ser membro da organização; não membros recebem um 403.

Envelope de evento

Todo evento é um objeto JSON com formato estável:

CampoTipoSignificado
idstringULID (26 chars). Monotônico; também serve como o id do evento SSE.
typestringTipo do evento, ex. operation.updated.v1.
sourcestringSubsistema produtor, ex. operations.
org_idstringOrganização proprietária (texto UUID).
project_idstring?Projeto proprietário; omitido para eventos de nível de organização.
region_idstringRegião que emitiu o evento.
atstringTimestamp RFC 3339.
dataobjectPayload específico do tipo.

O formato do envelope nunca muda de forma incompatível. Novos campos são aditivos, e novas variantes de evento ganham um novo type (ex. um futuro operation.updated.v2) em vez de mutar um existente.

Tipos de evento

Hoje o control plane publica um tipo de evento de aplicação:

  • operation.updated.v1 (source operations) — uma operação mudou de estado de ciclo de vida. data carrega operation_id, action, status, e, quando a linha ainda está presente, branch_id, endpoint_id, error e initiator.

O broker também emite três eventos de controle internos (source _broker):

  • resume.gap.v1 — seu Last-Event-ID é mais antigo que o buffer do broker; eventos foram perdidos. Refaça o fetch do estado completo via REST, depois continue fazendo streaming.
  • overflow.v1 — seu cliente leu lentamente demais e foi descartado; data.dropped conta os eventos perdidos. Reconecte e refaça o fetch do estado completo.
  • error.v1 — um marcador de erro do lado do produtor.

As sources audit, invitations e billing estão reservadas mas ainda não emitem eventos; esta lista cresce conforme essas tracks são entregues.

Retomando

O id de cada evento é o seu id SSE, então um EventSource nativo automaticamente reenvia o último como um header Last-Event-ID na reconexão, e o broker reproduz tudo que foi armazenado após ele. Você também pode passá-lo explicitamente:

Last-Event-ID: 01JX5N4R8ZT2W7Q9V3B1C6D8EF

Se o gap for mais largo que o ring em memória do broker, você recebe um resume.gap.v1 em vez de uma reprodução. Trate isso (e overflow.v1) como "você perdeu eventos": refaça o fetch do estado afetado via API REST, depois retome o streaming a partir do id mais recente.

Exemplo

curl -N -H "Authorization: Bearer $KISENON_API_KEY" \
  -H "Accept: text/event-stream" \
  https://api.test.kisenon.com/v1/events

Um evento transmitido se parece com:

id: 01JX5N4R8ZT2W7Q9V3B1C6D8EF
event: operation.updated.v1
data: {"id":"01JX5N4R8ZT2W7Q9V3B1C6D8EF","type":"operation.updated.v1","source":"operations","org_id":"6f1d2c3b-4a59-4e87-9b10-2d3e4f5a6b7c","project_id":"prj_4c1d9e2a7b3f5c8d0e1f2a3b","region_id":"home-proxmox","at":"2026-06-03T12:00:00Z","data":{"operation_id":"op_77a1","action":"create_branch","status":"finished","branch_id":"br_91c2"}}

Linhas começando com : (ex. : keepalive) são comentários de heartbeat; ignore-os.

No console

As visões de atividade ao vivo do console consomem este mesmo stream (com proxy pela origem do console, já que um EventSource de navegador não pode definir um header Authorization). Em resume.gap.v1 ou overflow.v1 ele refaz o fetch do estado completo via REST — exatamente o contrato acima. Se você está construindo seu próprio consumidor, espelhe esse comportamento.

Relacionado