Veto/docs

Events API

Server-Sent Events (SSE) stream for real-time decision, approval, and policy change notifications.

The events API provides a real-time SSE stream of organization-scoped events. The dashboard uses this to update the UI in real time when decisions are made, approvals are resolved, or policies change.

GET /v1/events/stream

Open a persistent SSE connection. The server sends events as they occur and a keepalive ping every 15 seconds.

Headers

HeaderRequiredDescription
X-Veto-API-Key or AuthorizationYesAPI key or Bearer JWT

Query parameters

ParameterTypeRequiredDescription
typesstringNoComma-separated list of event types to subscribe to. Omit to receive all events.

Connection

curl -N https://api.veto.so/v1/events/stream \
  -H "X-Veto-API-Key: veto_abc123..."

With type filtering:

curl -N "https://api.veto.so/v1/events/stream?types=decision,approval" \
  -H "X-Veto-API-Key: veto_abc123..."

Response format

The connection returns standard SSE format. Each event has a named type and a JSON data payload:

:ok

event: decision
data: {"toolName":"transfer_funds","decision":"allow","latencyMs":12,"createdAt":"2025-01-20T14:30:00Z"}

event: decision
data: {"toolName":"send_email","decision":"deny","reason":"Recipient not in allowlist","createdAt":"2025-01-20T14:30:05Z"}

event: approval
data: {"id":"apr_abc123","toolName":"transfer_funds","status":"approved","resolvedBy":"user@company.com","resolvedAt":"2025-01-20T14:31:00Z"}

:ping

Event types

TypeDescriptionData fields
decisionA tool call was validatedtoolName, decision, reason?, latencyMs, mode, createdAt
approvalAn approval status changedid, toolName, status, resolvedBy?, resolvedAt?, createdAt
policyA policy was created, updated, or deletedtoolName, action, version?, updatedAt
toolA tool was registered or removedname, action, createdAt

Keepalive

The server sends a :ping comment line every 15 seconds to keep the connection alive through proxies and load balancers. SSE comment lines (prefixed with :) should be ignored by clients.

Connection lifecycle

  1. Client opens the SSE connection
  2. Server sends :ok to confirm the connection
  3. Events are delivered as they occur, scoped to the authenticated organization
  4. Server sends :ping every 15 seconds
  5. If the connection drops, the client should reconnect (the EventSource API does this automatically)

Errors

StatusCodeDescription
401unauthorizedNo valid authentication provided

JavaScript example

const eventSource = new EventSource(
  'https://api.veto.so/v1/events/stream?types=decision,approval',
  {
    headers: {
      'X-Veto-API-Key': 'veto_abc123...',
    },
  }
);

eventSource.addEventListener('decision', (event) => {
  const data = JSON.parse(event.data);
  console.log(`${data.toolName}: ${data.decision}`);
});

eventSource.addEventListener('approval', (event) => {
  const data = JSON.parse(event.data);
  console.log(`Approval ${data.id}: ${data.status}`);
});

eventSource.onerror = () => {
  console.log('Connection lost, reconnecting...');
};

Infrastructure notes

Events are delivered via Redis pub/sub in multi-instance deployments. In single-instance setups (including self-hosted), events are delivered directly in-process without Redis.

The SSE endpoint does not buffer missed events. If the client disconnects and reconnects, it will only receive events from the point of reconnection. For historical data, use the Decisions API.