Elysium batch stream
WebSocket /v1/elysium/batches/stream
Endpoint and plans: Elysium RPC endpoint.
Live (2026-11-08). The public URL is wss://triport.io/v1/elysium/batches/stream. Authenticate the HTTP upgrade with X-API-Key and scope elysium:das. The plan floor is Pro; Free/Basic receive HTTP 403 tier_insufficient before upgrade (verified with a Free key on 2026-11-08). Connections per second: Pro 1, Business 2, Enterprise 5. A frame-level production check with a Pro key is still pending.
This stream follows confirmed batches as they are indexed from the data availability layer. Freshness is batch cadence plus indexing, not real time. For current L2 activity use RPC. No subscription request or first-frame authentication is used on this batch route.
| Query | Default | Meaning |
|---|---|---|
| from_seq | absent | Decimal non-negative sequence, inclusive. Without it, start after the newest indexed/no_data batch. Replay is limited to the most recent 200 batch sequence positions. An older request is clamped forward; inspect hello.from_seq. |
| full | absent | 1 or true returns transactions; otherwise returns transaction_hashes. |
wscat -c "wss://triport.io/v1/elysium/batches/stream?from_seq=1&full=1" \
-H "X-API-Key: $TRIPORT_API_KEY"Frames
JSON text frames are pushed after the upgrade. The following examples use synthetic values, not captured production frames.
First, hello reports the actual start and coverage:
{
"type": "hello",
"from_seq": 1,
"coverage": {
"source": "sequencer_batches",
"complete": false,
"includes": [
"signed transactions posted in Elysium sequencer batches since genesis (batch 1)",
"per transaction: sender, recipient, contract address for a creating transaction, nonce, value, input selector"
],
"excludes": [
"l1_to_l2_messages: deposits and other messages from the parent chain are counted per batch (l1_to_l2_messages) but not indexed per address",
"internal_calls: value transfers and contract creations made inside contract execution",
"execution_status: success or revert, gas used and logs are not part of batch data",
"unconfirmed: transactions accepted by the sequencer but not yet posted in a batch"
],
"from_batch_seq": 1,
"indexed_through": {
"batch_seq": 1,
"l2_block": 9,
"posted_at": "2026-11-08T00:00:00Z",
"posted_at_unix": 1794096000
},
"pending_batches": 0
}
}Next, batch frames arrive in ascending seq order. In full mode, at most 2000 transactions per frame, with part/parts numbered from 1. A batch must be assembled from all parts before advancing the saved cursor:
{
"type": "batch",
"batch": {
"seq": 1,
"status": "indexed",
"data_hash": "0x2222222222222222222222222222222222222222222222222222222222222222",
"tree_hash_verified": true,
"parent_chain": "hyperevm",
"parent_chain_id": 999,
"parent_block": 50000000,
"parent_tx": "0x3333333333333333333333333333333333333333333333333333333333333333",
"posted_at": "2026-11-08T00:00:00Z",
"posted_at_unix": 1794096000,
"l2_block_first": 1,
"l2_block_last": 9,
"messages": 9,
"l1_to_l2_messages": 8,
"l1_to_l2_messages_indexed": false,
"tx_count": 1,
"contract_creations": 0,
"payload_bytes": 256,
"das_expires_at": "2026-11-23T00:00:00Z"
},
"part": 1,
"parts": 1,
"transactions": [
{
"hash": "0x1111111111111111111111111111111111111111111111111111111111111111",
"batch_seq": 1,
"batch_position": 0,
"l2_block": 1,
"type": 2,
"chain_id": 99901,
"from": "0x4444444444444444444444444444444444444444",
"to": "0x5555555555555555555555555555555555555555",
"contract_address": null,
"nonce": 0,
"gas": 21000,
"value": "0x1",
"input_selector": null,
"input_bytes": 0,
"execution_status": "not_available"
}
]
}In hash mode, transaction_hashes replaces transactions; the whole batch's hashes are sent in one frame. Empty arrays can be omitted. Batch frames use the batch and transaction fields, and inherit the hello coverage limitations; they do not contain execution status beyond not_available. coverage is sent in hello, not repeated per batch frame. no_data batches are skipped without a batch frame.
If an unfinished batch, or a missing seq with a later known batch, remains unresolved for 5 minutes, the stream sends gap and moves on:
{
"type": "gap",
"seq": 2,
"status": "pending"
}No gap is emitted just because a future batch has not been posted yet. A gap is not an empty batch. Save it for REST recovery. Server ping control frames are sent about every 30 seconds; use a client that responds with pong. There is no application-level ping message.
Recovery and errors
Persist the last fully processed batch and any gaps. On reconnect, request from_seq = last processed seq + 1, inspect hello.from_seq for replay clamping, and use REST batch pagination for anything outside the replay window. Recover gaps with the batch detail route until status becomes indexed or no_data. Deduplicate by seq/part and transaction hash. Do not discard unresolved gaps when the stream advances.
Before upgrade: ordinary GET returns HTTP 400 websocket_required; bad from_seq returns 400 invalid_from_seq; index failures return 503. Capacity exhaustion returns HTTP 503 stream_capacity with Retry-After (default 30 seconds). After upgrade, an index startup failure can close with 1011 (index unavailable); reconnect with bounded backoff and recover via REST. This route has its own hello/batch/gap protocol; the general Pub/Sub authentication-frame and close-code rules do not apply.