Tailing request-log events — worked samples
GET /api/v1/tail opens a Server-Sent Events (SSE) connection and streams every API request handled for your tenant — status code, latency, and request metadata — sub-second after each response completes. It is the data source behind the Live tail toggle on the developer Request Logs page.
The stream excludes health, readiness, and metrics probes, provider webhook ingress, and the tail endpoint itself, so what you see is your traffic only.
Because the response is an event stream — not a JSON document — this page documents the frames and fields below; copy the cURL sample as written and the stream prints to your terminal.
GET /api/v1/tailX-API-Key) or session JWT. The caller must hold the owner, admin, or developer role. If you cannot send headers — a browser EventSource — pass the credential as the token query parameter instead: a dv_-prefixed value is treated as an API key, any other value as a bearer JWT. From server code, always use the header; a credential in a URL ends up in access logs and proxy history.
Query parameters
Open the stream with cURL
-N disables curl’s output buffering. Without it, the frames arrive but stay invisible until curl’s output buffer fills. The Accept header makes the SSE intent explicit. The query-parameter table above documents token and lastEventId; use headers whenever your client can send them.
Read the stream from Node.js
Usefetch when you need the raw SSE response; the generated SDK request helper buffers responses and cannot consume a never-ending stream. The parser below keeps the { event, id, data } frame shape and sends the latest lastEventId cursor on the next connection.
Read the stream from Python
requests exposes each SSE line as it arrives. Keep event, id, and data until the blank line terminates a frame, then parse the JSON data.
Frame sequence
After connecting, the server sends, in order:- An
event: connectedhandshake frame carrying the organization id. - A backfill of up to the most recent ~100 request rows, each an
event: logframe. - New
event: logrows live, as each request completes.
: heartbeat) arrive every 30 seconds to keep the connection open.
The first frames
{ data, meta } envelope — it is Content-Type: text/event-stream, so every frame above IS the response body.
Log event fields — each log frame’s data: line is one JSON object:
Adding fields is backwards-compatible — ignore keys you don’t recognize.
Subscribe from Node.js with EventSource
Named frames mean a genericonmessage handler never sees the rows — register a log listener:
Resume after a disconnect
Everylog frame carries an id (a stream cursor). To resume without losing rows, reconnect with Last-Event-ID or pass the same value as lastEventId. The loop below rehydrates the cursor after a dropped socket and increases the delay between attempts.
Node.js
EventSource sends Last-Event-ID automatically when it reconnects. For an explicit request, pass the same cursor as lastEventId:
cURL
Subscribe from a browser
EventSource cannot set request headers, so use the documented token query parameter only in browser code. Prefer a short-lived credential and do not use this form in server code, where URLs may be logged.
Browser
Limits and errors
This is a live tail, not durable history. For a longer-horizon export of the same rows, route through your own sink (as in the Node.js sample) instead of polling the stream.
Response sample — first frames as JSON
The SSE stream on the wire is thetext sample above. For tooling that wants the same two frames as a parsed body, treat each frame’s data: line as one JSON object in arrival order:
event: log) carries the per-request row documented in the field table above; id advances so Last-Event-ID resumes cleanly after a reconnect.