Contract events
Query decoded events, inspect their transaction context, and paginate with REST or GraphQL.
Explore an event before writing code
The contract-events explorer lets you enter a contract address, choose a ledger interval, and filter by event type, transaction hash, transaction outcome, and contract-call outcome. Use Link to this query to share the topic, search, order, page size, and selected window together.
Open an imported example. Inspect decoded topics and payloads, follow Open transaction for its operations and related events, then use Next events to continue. The example is historical; it is not a live feed.
For your own query, choose an interval from the dataset catalog’s completed ranges. An empty response outside imported coverage does not establish that a contract had no activity.
1. Request the first event page
(
trap - EXIT INT TERM
trap 'exit 130' INT
trap 'exit 143' TERM
temporary=$(mktemp './page-1.json.partial.XXXXXX') || exit
trap 'rm -f -- "$temporary"' EXIT
status=$(curl -q --fail-with-body --connect-timeout 5 --max-time 70 \
--write-out '%{http_code}:%header{x-stellaratlas-fallback}' \
'https://api.stellaratlas.io/v1/analytics/contracts/CA526Y2NQWGWVVQ7RFFPGAZMU66PSYJ3UC2MTVAV4ZU7OM5BOPHDXUSG/events?limit=10&min_ledger=64877635&max_ledger=64877698&view=typed' --output "$temporary") || exit
if [[ $status != 2[0-9][0-9]: ]]; then
printf '%s\n' "Expected a live HTTP success, got $status" >&2
exit 22
fi
jq -es 'length == 1 and (.[0] | type == "object")' "$temporary" >/dev/null || exit
mv -fT -- "$temporary" './page-1.json'
)These Bash examples use curl 7.84 or newer, jq, mktemp and GNU mv. Each invocation replaces the saved page only after an HTTP success without a fallback marker and a body that parses as one JSON object. It cleans up its temporary. On failure, retain the previous file as saved data and stop; do not paginate from an unsuccessful refresh.
The dynamic route is GET /v1/analytics/contracts/{contractId}/events. Use view=typed for items, decoded JSON, classification, coverage, and nextCursor. The interactive endpoint reference includes all parameters and the response schema.
type_code- 0: system; 1: contract; 2: diagnostic. Omit to include all types.
transaction_hash- Restrict the contract’s events to one transaction.
successful- The enclosing transaction’s outcome. Set false to inspect failed transactions.
in_successful_contract_call- The recorded call-success flag. This is distinct from the transaction outcome.
topic / order / limit- Filter by an exact named topic, such as
transfer. Choosedesc(newest first, the default) orasc. The explorer supports 10, 25, 50, or 100 rows per page. Topic buttons and counts describe the selected imported window, not all network history. q / include_summary- Search for one exact G/C address, transaction hash, or ledger number. Set
include_summary=truefor indexed event and topic counts; the number of items in a page is not the total count. The explorer loads rows without this aggregation by default; use “Load totals & topics” when needed. Cursor paging does not repeat that aggregation. min_ledger / max_ledger- Inclusive bounds. The Explorer limits its window to 1,000,000 ledgers. Keep API requests narrow and consult the endpoint reference for API bounds.
start_time / end_time- Optional additional timestamp filters: inclusive start, exclusive end, in UTC ending in Z. They constrain the ledger window rather than replace it.
2. Interpret the response
Read items as this page’s event records and summary.total as the indexed count for the query, when requested. Check coverage and the watermark before drawing conclusions about missing events; see coverage and pagination rules. A non-null nextCursor is the continuation token for step 3, not an event ID or a ledger number.
id · contractId · transactionHash · ledgerSequence · closedAt- Identify the event, emitting contract, transaction, ledger and close time.
topicsJson · dataJson- Decoded topics and payloads retained as strings. Payloads may be JSON or the literal
voidfor a return with no value; check for that sentinel before JSON parsing. Preserve large integer tokens; JavaScript Number may round them. Do not assume asset decimals from an event payload. tokenContext- Optional token units for recognized Stellar Asset Contract events. The API verifies the asset’s SDK-derived mainnet SAC address against the emitter before supplying identity and seven decimals. Unknown contracts remain unscaled. The explorer shows human amounts and keeps exact raw integers in Details and the original record.
classification- Describes the recorded transaction kind, event kind, execution evidence and provenance. A system event or native fee does not by itself establish Soroban execution.
Contract events are application-defined. An event is not automatically a token transfer, balance update, or proof that a call succeeded. Use the success flags, decoded payload, and transaction context together. The explorer retains the original record/XDR in an expandable section.
For recorded contract key/value changes, use contract state history. That endpoint is not a complete state snapshot at an arbitrary height.
3. Request the second page
After saving page-1.json, use this command with jq installed to save page-2.json. It reads the first page’s opaque cursor and keeps the same filters. A missing, null or unusable cursor stops the command before it sends a request.
(
trap - EXIT INT TERM
trap 'exit 130' INT
trap 'exit 143' TERM
after=$(jq -er '.nextCursor | strings | select(length > 0)' './page-1.json') || exit
temporary=$(mktemp './page-2.json.partial.XXXXXX') || exit
trap 'rm -f -- "$temporary"' EXIT
status=$(curl -q --fail-with-body --connect-timeout 5 --max-time 70 \
--write-out '%{http_code}:%header{x-stellaratlas-fallback}' \
'https://api.stellaratlas.io/v1/analytics/contracts/CA526Y2NQWGWVVQ7RFFPGAZMU66PSYJ3UC2MTVAV4ZU7OM5BOPHDXUSG/events?limit=10&min_ledger=64877635&max_ledger=64877698&view=typed' --get --data-urlencode "after=$after" --output "$temporary") || exit
if [[ $status != 2[0-9][0-9]: ]]; then
printf '%s\n' "Expected a live HTTP success, got $status" >&2
exit 22
fi
jq -es 'length == 1 and (.[0] | type == "object")' "$temporary" >/dev/null || exit
mv -fT -- "$temporary" './page-2.json'
)Copy nextCursor into after and preserve the contract and all filters. Do not send offset with the typed view. Stop when nextCursor is null. Changing filters starts a new query without the old cursor. Use Link to this page to reopen the same event cursor. Transaction and ledger links retain that event page as their return destination. A reopened cursor does not contain earlier-page history; use First pageto restart the result set.
Pages follow the requested order (descending by default), with stable source-row identifiers as tie-breakers. The watermark identifies the queried interval; it does not freeze the warehouse. Later ingestion can add events inside previously queried history, so a complete historical export also needs coverage checks and a later reconciliation pass. For freshness hints, see WebSocket updates.
HTTP 400 indicates invalid parameters or cursor. HTTP 503 indicates unavailable analytics service—not evidence that the contract has no events. The explorer keeps a successful page visible if the next request fails and offers Retry.
Query the same events with GraphQL
Open the GraphQL runner, select Historical contract events with decoded topics and data, and execute. Its schema explorer documents the available fields.
query ContractEvents($contractId: String!, $input: HubbleContractEventInput) {
hubbleContractEvents(contractId: $contractId, input: $input) {
contractId limit nextCursor
items { id contractId ledgerSequence transactionHash type typeCode successful topicsJson dataJson classification { transactionKind eventKind sorobanExecutionEvidence provenance } }
summary { total topics { topic count } }
coverage { contiguousLastLedger maximumLedger gapCount }
watermark { minimumLedger maximumLedger observedAt coverage }
}
}Variables
{
"contractId": "CA526Y2NQWGWVVQ7RFFPGAZMU66PSYJ3UC2MTVAV4ZU7OM5BOPHDXUSG",
"input": {
"minLedger": 64877635,
"maxLedger": 64877698,
"typeCode": 1,
"topic": "REDSTONE",
"order": "desc",
"includeSummary": true,
"limit": 2
}
}Use the returned cursor as input.after, keeping the other input fields unchanged. The preset has its own topic and page-size filters; preserve those when continuing it. REST and GraphQL read the same parsed dataset; they do not perform separate ingestion.
Contract source and build provenance
GET /v1/contracts/{contractId}/provenance reads the deployed executable from our RPC. The response includes its observed ledger, Wasm SHA-256, embedded source repository, and available signed build record.
build.status=verified requires the artifact digest, repository, source commit, GitHub workflow identity, certificate and transparency evidence to match. build.record then links to the exact source commit, workflow and build run. This is build provenance, not a security audit or an independent reproducible build.
Other statuses distinguish missing metadata, unpublished builds, unsupported metadata, verification failures and unavailable evidence. A missing contract at the reported ledger is not a claim that it was never deployed. Contract upgrades can change the Wasm hash.
Follow the builder publication and verification workflow for a copyable lookup, supported evidence and status-specific next steps.