Docs / EventSourcingDB / API / read-events

read-events

Reads the events of a subject, or of a subject together with every subject below it.

  • Route: QUERY /api/v2/data/read-events
  • Category: data
  • Authentication: required, with the API token
  • Answer: a stream of NDJSON

A read returns the events of a subject, oldest first unless you ask for the reverse order, and lets you narrow them down by their IDs or start at the latest event of a type. It reads the events up to the latest one at the moment it starts: events written while it runs are not part of it. To receive those as well, observe the subject with observe-events. The tutorial Reading Events walks through it step by step.

Request#

The body is a JSON object, with the content type application/json:

Field Type Required Meaning
subject string yes The subject to read, a slash-separated path such as /books/42.
options.recursive boolean no Whether to read the events of every subject below the given one as well. Defaults to false, which reads the given subject alone.
options.order string no chronological for the oldest event first, or antichronological for the newest first. Defaults to chronological.
options.lowerBound object no The lowest event ID to read. Without it, the range begins at the first event.
options.upperBound object no The highest event ID to read. Without it, the range ends at the latest event.
options.lowerBound.id, options.upperBound.id string yes, in a bound An event ID, a non-negative integer in a string, without a sign or a leading zero, such as "23".
options.lowerBound.type, options.upperBound.type string yes, in a bound inclusive to read the event with that ID as well, or exclusive to leave it out.
options.fromLatestEvent object no Starts the read at the latest event of a type in a subject, that event included, instead of at lowerBound.
options.fromLatestEvent.subject string yes, in fromLatestEvent The subject of that event, exactly that one and not a subject below it.
options.fromLatestEvent.type string yes, in fromLatestEvent The event type of that event.
options.fromLatestEvent.ifEventIsMissing string yes, in fromLatestEvent What to read if there is no such event: read-everything reads as if fromLatestEvent were left out, read-nothing reads no events.

The bounds select a range of event IDs, whichever order you read them in; see Reading a Specific Range. fromLatestEvent cannot be combined with lowerBound or with the order antichronological. It lets a read start at the latest snapshot of a subject, see Reading From the Last Event of a Given Type.

To read the events of /books/42:

curl \
  -X QUERY \
  -H "authorization: Bearer secret" \
  -H "content-type: application/json" \
  -d '{"subject":"/books/42"}' \
  http://localhost:3000/api/v2/data/read-events

Answer#

The answer is a stream of items, one per line. Each event is an event item:

Type Data When
event the event, a CloudEvent with every field it was stored with For every event that the read finds, in the order that options.order asks for.
error code, description, and details When the read cannot go on, see Errors.
heartbeat empty While nothing else is sent for a while, to keep the connection alive.
end empty Once, as the last item, when the stream ends cleanly.

Heartbeats and the end item work as on every stream of the API, see Streams. A subject without events, a range beyond the latest event, and a fromLatestEvent with read-nothing that finds no event are answered with the end item alone.

For a database in which /books/42 holds a book-acquired and a book-borrowed event, the request above is answered with:

{"type":"event","data":{"specversion":"1.0","id":"0","source":"https://library.eventsourcingdb.io","subject":"/books/42","type":"io.eventsourcingdb.library.book-acquired","time":"2026-10-28T04:36:03.031127Z","predecessorhash":"0000000000000000000000000000000000000000000000000000000000000000","datacontenttype":"application/json","data":{"author":"Arthur C. Clarke","isbn":"978-0756906788","title":"2001 – A Space Odyssey"},"traceparent":null,"tracestate":null,"hash":"esdb:hash:v2:0c93c8369291dbce3e786d0427a0b5e94a7be9867d5d7e7357f5b2557ec049cc","signature":null}}
{"type":"event","data":{"specversion":"1.0","id":"1","source":"https://library.eventsourcingdb.io","subject":"/books/42","type":"io.eventsourcingdb.library.book-borrowed","time":"2026-10-28T04:36:07.365416Z","predecessorhash":"esdb:hash:v2:0c93c8369291dbce3e786d0427a0b5e94a7be9867d5d7e7357f5b2557ec049cc","datacontenttype":"application/json","data":{"borrowedBy":"/readers/23","borrowedUntil":"2026-11-22"},"traceparent":null,"tracestate":null,"hash":"esdb:hash:v2:f3785555ef047f8366866f6b1a9da3e1967c0a911ff030779789ae1c5ef5ac88","signature":null}}
{"type":"end","data":{}}

Errors#

The read reports these errors as an error item, followed by the end item:

  • subject-missing: The request leaves out the subject.
  • subject-malformed: The subject to read, or the subject of fromLatestEvent, is not a valid subject, such as books/42 without its leading slash.
  • subject-too-long: The subject to read, or the subject of fromLatestEvent, is longer than 1,024 characters.
  • subject-too-deep: The subject to read, or the subject of fromLatestEvent, has more than 32 segments.
  • order-unknown: options.order is neither chronological nor antichronological.
  • event-id-missing: A bound leaves out its id.
  • event-id-malformed: The id of a bound is not a non-negative integer without a sign or a leading zero, such as -1 or 007.
  • bound-type-missing: A bound leaves out its type.
  • bound-type-unknown: The type of a bound is neither inclusive nor exclusive.
  • from-latest-event-incomplete: fromLatestEvent leaves out its subject, its type, or ifEventIsMissing.
  • if-event-is-missing-unknown: ifEventIsMissing is neither read-everything nor read-nothing.
  • event-type-malformed: The type of fromLatestEvent is not a valid event type.
  • selection-conflicting: The request combines fromLatestEvent with lowerBound, or with the order antichronological.
  • range-unsatisfiable: The bounds leave no event that could match, such as a lowerBound above the upperBound, or the event that fromLatestEvent starts at lies above the upperBound.
  • restore-in-progress: A restore is running, which refuses reads until it has finished.
  • file-unreadable: A file of the store that the read needs is damaged, such as an events file whose checksum no longer matches.
  • store-failed: The store refuses reads for good, after a restore that could not empty it again.
  • server-shutting-down: The server began to shut down while the read was running. Before the stream begins, the server answers with 503 instead.

Status Codes#

Before the stream begins, the server answers with a status code other than 200 where it cannot take the request at all, as described in Errors:

  • 400: The content type of the body is not application/json, or the body is no JSON object of the shape above, for example with a field the route does not know, such as recursive outside of options, with a value of the wrong JSON type, such as an id that is a number rather than a string, or with null as a value.
  • 401: The API token is missing or wrong.
  • 408: The body did not arrive in time.
  • 413: The body is larger than its limit.
  • 429: Too many requests were sent, or the client already holds 256 open streams, see Rate Limiting; the answer says when to try again.
  • 500: The server failed unexpectedly before the stream began. Once it has begun, the stream breaks off without its end item instead.
  • 503: The server is shutting down.