token_transfer) or a
Soroban contract event (contract_event). This page lists the fields, shows a
real record of each kind and explains IDs, amounts and coverage.
Activity and webhooks share the same event body. Activity
adds paging_token to every record and rpc_event_id to contract events;
webhook bodies have neither.
Set these once in your terminal. The sample values are real Testnet data, so
the read examples return real results.
Fetch the events of a transaction
fee event and a transfer event. The fee record:
contract_event record, from GET /accounts/$ACCOUNT/contract-events:
Fields
A custom contract event named
transfer is not a verified token movement; check
kind. Token classification lists the shapes that become
token_transfer.
Event IDs
Treatid as an opaque string and deduplicate on (network, id). Its
segments are separated by colons:
op in a contract event ID is zero-based while the operation_index field is
one-based, so operation_index equals op + 1. The event segment can skip
numbers, because events that became token_transfer records keep their
positions.
Activity and webhooks use the same decoder, so the same
on-chain event has the same id in both, for the same decoder release (a
decoder change that renumbers events would be announced). When you store both:
- Key on
(network, id). Do not includegeneration: it is product-specific (the Activity index generation and the webhook chain generation differ). - Ignore the Activity-only
paging_tokenandrpc_event_idwhen you compare bodies.balance.changedandwebhook.testexist only in webhooks. - Ledger numbers and IDs repeat after a Testnet reset: start a new store, or add the reset date to the key.
Paging tokens and RPC event IDs
paging_token has the form {toid}-{index}: a 19-digit TOID and a 10-digit
index. The TOID packs the ledger, the one-based transaction index and the
one-based operation index (0 for fee events). The index is the zero-based
position among the decoded events of that operation, with token-transfer events
numbered before contract events. Use it only as a cursor.
rpc_event_id uses the same layout, but both parts can differ: RPC counts
operations from 0, and its index is the event’s position in the operation’s
full event list (the event segment of id). For example, event
testnet:5330800:ce:8:0:2 has paging_token 0022895611661549569-0000000004
and rpc_event_id 0022895611661549568-0000000002. Always join with RPC on
rpc_event_id; never derive it from paging_token.
Amounts
amount_raw is the exact integer. amount is a decimal rendering; Classic
assets and Stellar Asset Contracts use seven decimal places. Keep raw values and
use integer or decimal libraries; do not reconcile balances with Number or
floating-point columns.
For a custom contract token, asset is absent (not null) and
contract_address identifies the token. Its amount equals amount_raw:
Lumeus does not know the contract’s decimals and applies no scaling. A token’s
symbol is not globally unique.
A Soroban transaction can have a second fee event with a negative amount: the
refund. Sum the fee events of a transaction to get the final fee.
Participants and memos
from and to are the decoded movement roles. issuer marks an issuer action;
the issuer is not a participant in holder-to-holder transfers.
Muxed destinations can include to_muxed_id, to_muxed_address,
to_muxed_text or to_muxed_hash. The transaction memo fields are repeated on
each event so you can route deposits without a second request. Validate the
routing convention of the application you integrate with.
Contract values
JSON cannot represent every ScVal type losslessly. Usetopics_xdr and
data_xdr when typed map keys, integer widths or exact bytes matter.
Coverage
Decoded movements include account creation and merge, payments and path payments, executed trades, claimable-balance movements, liquidity-pool reserve movements, inflation payouts, clawbacks, fees and SAC movements. Operations that move nothing (SetOptions, ChangeTrust, ManageData, sequence bumps, sponsorship-only changes, TTL and footprint maintenance) produce no event. Only successful contract events enter the contract-event stream; diagnostic and system events are excluded. A failed transaction keeps its header and fee events. A muxed source is normalized to its baseG address.
This is decoded event coverage, not every Horizon operation. An unknown future
protocol construct stops indexing rather than publishing incomplete history, so
a new protocol can need a decoder update first. See
service readiness when fresh data stops appearing.