Skip to main content
GET
/
streams
/
{stream}
/
records
Read records.
curl --request GET \
  --url https://{basin}.b.s2.dev/v1/streams/{stream}/records \
  --header 'Authorization: Bearer <token>'
{
  "records": [
    {
      "seq_num": 1,
      "timestamp": 1,
      "body": "<string>",
      "headers": [
        [
          "<string>"
        ]
      ]
    }
  ],
  "tail": {
    "seq_num": 1,
    "timestamp": 1
  }
}

Documentation Index

Fetch the complete documentation index at: https://s2.dev/docs/llms.txt

Use this file to discover all available pages before exploring further.

Read concepts

Understand starting points, bounds, wait behavior, and sessions.

Reading SDK

Use single-batch reads, read sessions, and check-tail calls.
Use this endpoint for a single-batch read or a streaming read session. Streaming sessions may be S2S-based (used by SDK readSession APIs) or SSE responses.

Parameters

Query parameters choose where the read starts, what bounds apply, and whether the read waits at the tail.

Starting point

A request can specify at most one starting selector. If no selector is provided, the start is equivalent to tail_offset=0.
Query parameterUnitStarts at
seq_numSequence numberThe first record whose sequence number is greater than or equal to seq_num.
timestampMilliseconds since Unix epochThe first record whose timestamp is greater than or equal to timestamp.
tail_offsetRecord countThe position tail.seq_num - tail_offset, saturated at the start of the stream.
tail_offset=0 starts at the tail. The tail is the next sequence number that will be assigned, so there is no existing record at that position. If a requested seq_num or timestamp is beyond the current tail, clamp=true moves the start to the current tail. This is most useful with wait > 0, where the read can then wait for future records. Without clamp, starts beyond the tail return 416 Range Not Satisfiable.

Bounds

Bounds limit how far a read may continue after its starting point.
Query parameterUnitBehavior
countRecordsStop after this many records. For single-batch reads, the effective maximum is 1000 records.
bytesBytesLimit the total metered bytes returned. For single-batch reads, the effective maximum is 1 MiB.
untilTimestampStop before records whose timestamp is greater than or equal to until.
When multiple bounds are present, the read stops at the first bound reached.

Waiting at the tail

wait is how many seconds the read may wait at the tail for new records after all immediately available records have been returned.
Request modeDefault waitTail behavior
Single-batch read0Return immediately unless wait > 0.
Session with count, bytes, or until0Stop when a bound is reached or when the session catches up to the current tail, unless wait > 0.
Session without count, bytes, or untilInfiniteFollow the stream indefinitely, waiting at the tail for new records.
A single-batch read with wait > 0 may long poll for up to 60 seconds. If the wait elapses before records arrive, the response is an empty batch. For sessions, wait applies throughout the session while still respecting any count, bytes, or until bound.

When reads return 416

A read returns 416 Range Not Satisfiable when it cannot return records under the request’s effective wait and clamp behavior. The 416 response body is a TailResponse containing the current tail.
Request behavior416 when
Effective wait > 0The start is beyond the tail and clamp is omitted or false: seq_num > tail.seq_num or timestamp > tail.timestamp.
Effective wait = 0No record is available immediately: the stream is empty, tail_offset = 0, seq_num >= tail.seq_num, or timestamp > tail.timestamp.
Starting exactly at the tail is valid; with wait > 0, the read waits for future records, and with wait = 0, it returns 416 because no record exists at the tail yet.
clamp=true only changes starts that are beyond the tail. It moves the start to the current tail, not to the last existing record.

SSE

Server push with Server-Sent-Events (SSE) is supported. Clients can request an SSE response by setting the Accept: text/event-stream header.
curl --request GET \
  --url 'https://hello-world.b.s2.dev/v1/streams/test/records?seq_num=0' \
  --header "Authorization: Bearer ${S2_ACCESS_TOKEN}" \
  --header 'Accept: text/event-stream'
event: batch
id: 4,5,74
data: {"records":[{"seq_num":4,"timestamp":1750101582144,"body":"hello"}],"tail":{"seq_num":5,"timestamp":1750101582144}}
Any error message will terminate the stream.

Authorizations

Authorization
string
header
required

Bearer authentication header of the form Bearer <token>, where <token> is your access token.

Headers

s2-format
enum<string>

Defines the interpretation of record data (header name, header value, and body) with the JSON content type. Use raw (default) for efficient transmission and storage of Unicode data — storage will be in UTF-8. Use base64 for safe transmission with efficient storage of binary data.

Available options:
raw,
base64
s2-encryption-key
string

Encryption key material for append and read operations. Provide base64-encoded key when stream encryption is enabled.

Path Parameters

stream
string
required

Stream name.

Required string length: 1 - 512

Query Parameters

seq_num
integer<int64>

Start from a sequence number.

Required range: x >= 0
timestamp
integer<int64>

Start from a timestamp.

Required range: x >= 0
tail_offset
integer<int64>

Start from number of records before the next sequence number.

Required range: x >= 0
clamp
boolean

Start reading from the tail if the requested position is beyond it. Otherwise, a 416 Range Not Satisfiable response is returned.

count
integer<int64>

Record count limit. Non-streaming reads are capped by the default limit of 1000 records.

Required range: x >= 0
bytes
integer

Metered bytes limit. Non-streaming reads are capped by the default limit of 1 MiB.

Required range: x >= 0
until
integer<int64>

Exclusive timestamp to read until.

Required range: x >= 0
wait
integer<int32>

Duration in seconds to wait for new records. The default duration is 0 if there is a bound on count, bytes, or until, and otherwise infinite. Non-streaming reads are always bounded on count and bytes, so you can achieve long poll semantics by specifying a non-zero duration up to 60 seconds. In the context of an SSE or S2S streaming read, the duration will bound how much time can elapse between records throughout the lifetime of the session.

Required range: x >= 0

Response

records
object[]
required

Records that are durably sequenced on the stream, retrieved based on the requested criteria. This can only be empty in response to a unary read (i.e. not SSE), if the request cannot be satisfied without violating an explicit bound (count, bytes, or until).

tail
object

Sequence number that will be assigned to the next record on the stream, and timestamp of the last record. This will only be present when reading recent records.