Tracking your transactions
The received → forwarded → acked → landed/reverted lifecycle, and how 0block measures landing speed with slot_delta (and landing_ms).
Beta — rolling out now. The dashboard and its control-plane API are in active rollout. The contract documented here is stable, but availability may vary by deployment.
Every submission made with an API key is telemetered.
0block records where it is in its lifecycle and — once it lands — how long that took, which leader
produced its block, and whether the program succeeded. You read this back through
GET /transactions and
GET /stats.
The lifecycle
A transaction moves through these statuses:
received ─▶ forwarded ─▶ acked ─┬▶ landed
├▶ reverted
├▶ failed
└▶ expired| Status | Meaning | Timestamp set |
|---|---|---|
received | 0block accepted the tipped submission and recorded it (noting the current chain slot as submitted_slot). | received_at |
forwarded | The raw bytes were forwarded to the staked upstream. | forwarded_at |
acked | The upstream acknowledged the submission (a JSON-RPC result). This is a submission-ack, not landing. | acked_at |
landed | Confirmed on-chain and the program succeeded. | landed_at (+ slot, slot_delta, landing_ms, landed_leader) |
reverted | Landed in a block, but the program reverted — included on-chain yet did not succeed. onchain_err and program_error_code are populated. Carries the same slot / slot_delta / landing_ms as a landed tx. | landed_at (+ slot, slot_delta, landing_ms, landed_leader) |
failed | The submission failed — the upstream returned an error, or a pre-check rejected it. Never made it into a block. error_code is populated. | — |
expired | Still not landed after the tracking window (90 seconds). 0block stops polling. | — |
acked is not confirmation. It only means the upstream accepted the transaction for
forwarding. The only landing signals are landed and reverted, which 0block derives
independently — never from the submission response.
landed and reverted are both on-chain inclusions — the difference is execution: landed
succeeded, reverted was included but the program returned an error. failed and expired never
made it into a block.
How landing is detected
0block does not treat a submission-ack as finality. On receipt it notes the current chain slot as
submitted_slot. Landing is then detected one of two ways, recorded per-transaction in
latency_source:
grpc— a real-time Geyser gRPC stream reports the exact slot from the transaction's first shred. This is precise:submitted_slot,slot, andlanding_msare all exact.poll— a fallback landing poller batches the signatures of in-flight transactions into a singlegetSignatureStatusescall (roughly every couple of seconds). Detection is bounded by that ~2s cadence, andsubmitted_slotis a processed + 1 estimate, so poll-modeslot_deltaandlanding_msare approximate.
Anything still unlanded after 90 seconds is marked expired and polling stops. An expired
transaction may still have landed later on-chain — it just fell outside 0block's tracking window,
so confirm independently if it matters.
Measuring landing speed
slot_delta is the primary landing-speed metric. It counts how many slots after the one you
sent during the transaction landed:
slot_delta = max(0, slot - submitted_slot)0— landed in the same slot it was sent during. This is the best possible outcome.1,2, … — that many slots later.null— the transaction hasn't landed, or its landing slot couldn't be observed.
This matches the slot-latency convention used by ping-thing
and validators.app. Its accuracy depends on submitted_slot: exact under grpc (first-shred slot),
an estimate under poll (processed + 1). Because it's counted in slots, slot_delta is immune to
wall-clock jitter — it's the metric to watch for execution quality, and it's what
GET /stats aggregates into same_slot_rate
and slot_distribution. Reverted transactions landed in a block too, so they carry a real
slot_delta and count toward these inclusion metrics.
landing_ms is wall-clock milliseconds from when 0block received the submission to when it
detected the landing. It is precise when latency_source is grpc (real-time detection);
under poll it includes up to ~2s of polling granularity and therefore overstates true landing
latency, so treat it as an upper bound and prefer slot_delta.
relay_ms is a separate number: 0block's own processing overhead — leader ack minus receipt,
typically ~40–90 ms. It's the latency the gateway itself adds, distinct from how long the network
took to land the transaction.
Which leader landed it
Two leader identities are recorded, and they can differ:
target_leader— the leader of the slot you aimed at (the producer ofsubmitted_slot).landed_leader— the validator that actually produced the block the transaction landed in. Only set once landed/reverted.
They match when a transaction lands within its target leader's window, and differ when it lands a
few slots late and crosses into the next leader's window. landed_leader is the real
block producer — it's what you'd cross-reference on an explorer.
When a transaction reverts
A reverted transaction was included on-chain but the program returned an error. It is a
distinct terminal status from failed (which never made it into a block):
onchain_err— the raw serialized Solana transaction error, e.g.{"InstructionError":[3,{"Custom":6062}]}.program_error_code— the parsed custom program error code (e.g.6062) when the error carries one;nullotherwise.
A reverted transaction still has slot, slot_delta, landing_ms, and landed_leader — it was
included, it just didn't succeed.
Reading the data
Each transaction record carries the full set of lifecycle fields:
{
"id": "e2b1…",
"signature": "5t4eBfVv8A3tN6d2zjZphqStjc6b4YbTL7Yt8Y6XWf9",
"key_prefix": "0b_ab12cd34",
"status": "landed",
"error_code": null,
"received_at": "2026-07-05T18:22:31.010Z",
"forwarded_at": "2026-07-05T18:22:31.014Z",
"acked_at": "2026-07-05T18:22:31.068Z",
"landed_at": "2026-07-05T18:22:31.422Z",
"submitted_slot": 265470112,
"slot": 265470112,
"slot_delta": 0,
"landing_ms": 412,
"relay_ms": 58,
"latency_source": "grpc",
"target_leader": "Fd7btgySLzy5S4YfF6RQXbTHfMehFAJujFhH7QoZWZ2",
"landed_leader": "Fd7btgySLzy5S4YfF6RQXbTHfMehFAJujFhH7QoZWZ2",
"onchain_err": null,
"program_error_code": null
}This example landed in the same slot it was sent during (slot_delta 0) — the best case —
and was detected in real time (latency_source grpc), so landing_ms 412 is exact.
relay_ms 58 is 0block's own overhead. target_leader equals landed_leader, so it landed
inside its target leader's window.
- Filter by lifecycle stage with
?status=(e.g.?status=landed,?status=reverted, or?status=expired). - Aggregate landing quality over a window with
GET /stats:same_slot_rate(share of included transactions atslot_delta0),slot_distribution(how landings spread across0…5+), and latency percentiles (p50/p90/p99) for bothlanding_msandrelay_ms.
See the Transactions & Stats reference for the full field list and query parameters.