> ## Documentation Index
> Fetch the complete documentation index at: https://developers.stellar.org/llms.txt
> Use this file to discover all available pages before exploring further.

# queryEvents

> Returns events for a ledger range, ascending or descending, with cursors that do not expire (beta)

> [!WARNING]
>
> **Beta feature**
>
> The `queryEvents` method is available only on RPC nodes that enable it's new storage engine, which is currently in beta. Standard Stellar RPC nodes do not support this method. To use it, run RPC from the [`archive-node-beta`](https://github.com/stellar/stellar-rpc/releases/tag/archive-node-beta) tag or connect to a provider that offers one.
>
> This method is in beta and may change before general availability.

Returns contract and system events that match the specified filters within a ledger range. Results are paginated; each response contains a page of events and, when the scan is not complete, a cursor for continuing the query.

Set `order` to `asc` to scan forward from `minLedger`, or to `desc` to scan backward from `maxLedger`. If omitted, `maxLedger` defaults to the latest ledger.

To start a query, specify the applicable ledger bounds, scan order, and optional filters. To retrieve the next page, send the `cursor` returned in the previous response without repeating `minLedger`, `maxLedger`, `order`, or `filters`. The cursor preserves those query parameters. `limit` and `xdrFormat` are not stored in the cursor and may be specified on each request.

Use `scanStatus` to determine whether to request another page, wait for additional ledgers, or stop. An empty `events` array does not necessarily mean the scan is complete.

## Params (7)

> [!TIP]
>
> Please note that parameter structure within the request must contain named parameters as a by-name object, and not as positional arguments in a by-position array

**minLedger** `number`

The first ledger in the range (inclusive). Required for ascending scans (`order: asc`) and optional for descending scans. Specify this parameter only when starting a query, not when continuing with a cursor.

Sequence number of the ledger.

**maxLedger** `number`

The last ledger in the range (inclusive). Optional. Without `maxLedger`, an ascending scan continues toward newly closed ledgers and reports `WAITING_FOR_LEDGERS` when it catches up to the chain. A descending scan starts at the latest ledger. Specify this parameter only when starting a query.

Sequence number of the ledger.

**order** `string`

The direction of the scan. `asc` (default) scans forward from `minLedger`; `desc` scans backward from `maxLedger`. Specify this parameter only when starting a query.

Available options: `asc`, `desc`

**filters** `object[]`

An array of 1 to 256 event filters. An event matches if it satisfies at least one filter; within a filter, all specified fields must match. Omit `filters` to match all events. Specify this parameter only when starting a query.

For example, to match either `transfer` or `mint` events from one contract, send two filters with the same `contractId` and a different `topic0`. The first example below does this.

Topic values are Base64-encoded XDR `ScVal`s, not plain strings. Use the [JSON to XDR](https://lab.stellar.org/xdr/to) page in the Lab to encode a value.

A query may use at most 15 distinct index terms by default; node operators can configure this limit. Each distinct `contractId` is one term, each distinct `type` is one term, and each distinct value at a given topic position is one term. The same value at the same position counts once no matter how many filters repeat it. The same value at two different positions counts twice. For example, `[{ topic0: transfer, topic1: me }, { topic0: transfer, topic2: me }]` uses 3 terms. A query over the budget returns `invalid_params` with `termsUsed` and `termBudget` in `error.data`.

**items**

**type** `string`

The type of emitted event.

Available options: `contract`, `system`

**contractId** `string`

The emitting contract address in StrKey format (`C...`).

**topic0** `string`

The Base64-encoded XDR `ScVal` that the first event topic must match.

**topic1** `string`

The Base64-encoded XDR `ScVal` that the second event topic must match.

**topic2** `string`

The Base64-encoded XDR `ScVal` that the third event topic must match.

**topic3** `string`

The Base64-encoded XDR `ScVal` that the fourth event topic must match.

**cursor** `string`

The cursor returned by the previous response, used to continue a query. It preserves the ledger bounds, scan order, and filters. Do not combine `cursor` with `minLedger`, `maxLedger`, `order`, or `filters`; doing so returns an error.

**limit** `number`

The maximum number of events to return per page, from 1 to 1,000. Defaults to 100. This setting is not stored in the cursor; include it on each request to retain a nondefault value.

**xdrFormat** `string`

Controls how XDR values are represented in the response: decoded JSON or Base64-encoded XDR. Do not depend on a fixed schema for the JSON representation, as it may change with the underlying XDR.

Specifies whether XDR should be encoded as Base64 (default or 'base64') or JSON ('json').

## Result

*(queryEventsResult)*

**events** `object[]` *required*

Events returned on this page, up to the configured `limit`. The array may be empty even when more pages remain; check `scanStatus`.

**items**

**type** `string`

The type of emitted event.

Available options: `contract`, `system`

**ledger** `number`

The sequence number of the ledger in which the event was emitted.

**ledgerClosedAt** `string`

The ledger close time, formatted as an ISO 8601 timestamp.

**contractId** `string`

The address of the contract that emitted the event, in StrKey format.

**id** `string`

A unique event identifier consisting of a 19-character TOID and a 10-character, zero-padded event index, separated by a hyphen.

**transactionIndex** `number`

The index of the event's transaction within the ledger.

**operationIndex** `number`

The index of the operation that emitted the event within its transaction.

**topic** `string[]`

The event topics, each represented as a Base64-encoded XDR `ScVal`.

**value** `string`

The event data, represented as a Base64-encoded XDR `ScVal`.

**txHash** `string`

The hash of the transaction that triggered the event.

**cursor** `string`

An opaque cursor for retrieving the next page. It preserves the original ledger bounds, scan order, and filters and does not expire. The cursor is absent only when `scanStatus` is `COMPLETE`.

**scanStatus** `string` *required*

Indicates the state of the scan and the next action.

* `HAS_MORE`: more data can be scanned immediately; request the next page.
* `WAITING_FOR_LEDGERS`: the scan needs ledgers the node does not yet hold; wait and retry with the same cursor.
* `OLDEST_REACHED`: a descending scan reached the oldest ledger available on this node before reaching the requested lower bound; stop or use a node with deeper history.
* `COMPLETE`: the requested range has been fully scanned; no cursor is returned.

Available options: `HAS_MORE`, `WAITING_FOR_LEDGERS`, `OLDEST_REACHED`, `COMPLETE`

**scannedLedger** `number` *required*

A scan checkpoint indicating that all matching events from the scan's starting bound through this ledger have been delivered. If a page ends partway through a ledger, this field identifies the last fully scanned ledger; the cursor resumes within the partially scanned ledger. Before any ledger has been fully scanned, the value is `minLedger - 1` for ascending scans or `maxLedger + 1` for descending scans.

**oldestLedger** `number` *required*

The sequence number of the oldest ledger available to the RPC node when it processed the request.

**latestLedger** `number` *required*

The sequence number of the latest ledger known to the RPC node when it processed the request.

## Examples

> [tab] Newest transfer or mint events
>
> Starts a query for the newest `transfer` or `mint` events from one contract, two per page. With `order: desc` and no ledger bounds, the scan starts at the latest ledger and walks back. The two filters share a `contractId` and differ in `topic0`, so an event matches either. Ledger numbers and hashes are illustrative.
>
> **Request**
>
> ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
> curl -X POST \
> -H 'Content-Type: application/json' \
> -d '{
>   "jsonrpc": "2.0",
>   "id": 8675309,
>   "method": "queryEvents",
>   "params": {
>     "order": "desc",
>     "filters": [
>       {
>         "contractId": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
>         "topic0": "AAAADwAAAAh0cmFuc2Zlcg=="
>       },
>       {
>         "contractId": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
>         "topic0": "AAAADwAAAARtaW50"
>       }
>     ],
>     "limit": 2
>   }
> }' \
> https://soroban-testnet.stellar.org | jq
> ```
>
> ```js JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
> let requestBody = {
>   jsonrpc: "2.0",
>   id: 8675309,
>   method: "queryEvents",
>   params: {
>     order: "desc",
>     filters: [
>       {
>         contractId: "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
>         topic0: "AAAADwAAAAh0cmFuc2Zlcg==",
>       },
>       {
>         contractId: "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
>         topic0: "AAAADwAAAARtaW50",
>       },
>     ],
>     limit: 2,
>   },
> };
> let res = await fetch("https://soroban-testnet.stellar.org", {
>   method: "POST",
>   headers: {
>     "Content-Type": "application/json",
>   },
>   body: JSON.stringify(requestBody),
> });
> let json = await res.json();
> console.log(json);
> ```
>
> ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
> import json, requests
> res = requests.post("https://soroban-testnet.stellar.org", json={
>     "jsonrpc": "2.0",
>     "id": 8675309,
>     "method": "queryEvents",
>     "params": {
>         "order": "desc",
>         "filters": [
>             {
>                 "contractId": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
>                 "topic0": "AAAADwAAAAh0cmFuc2Zlcg=="
>             },
>             {
>                 "contractId": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
>                 "topic0": "AAAADwAAAARtaW50"
>             }
>         ],
>         "limit": 2
>     }
> })
> print(json.dumps(res.json(), indent=4))
> ```
>
> ```json JSON theme={"theme":{"light":"github-light","dark":"github-dark"}}
> {
>   "jsonrpc": "2.0",
>   "id": 8675309,
>   "method": "queryEvents",
>   "params": {
>     "order": "desc",
>     "filters": [
>       {
>         "contractId": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
>         "topic0": "AAAADwAAAAh0cmFuc2Zlcg=="
>       },
>       {
>         "contractId": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
>         "topic0": "AAAADwAAAARtaW50"
>       }
>     ],
>     "limit": 2
>   }
> }
> ```
>
> **Result**
>
> ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
> {
>   "jsonrpc": "2.0",
>   "id": 8675309,
>   "result": {
>     "events": [
>       {
>         "type": "contract",
>         "ledger": 1189981,
>         "ledgerClosedAt": "2024-04-25T17:52:46Z",
>         "contractId": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
>         "id": "0005110929477865472-0000000000",
>         "transactionIndex": 1,
>         "operationIndex": 0,
>         "txHash": "5bd25a1a8fd1fe8ec99ab1fdd57af9a6f0e4c7c8a3c1b7d2e9f0a1b2c3d4e5f6",
>         "topic": [
>           "AAAADwAAAAh0cmFuc2Zlcg==",
>           "AAAAEgAAAAAAAAAAeo0X4ISuIjuArAyYXR0z8qyj0x0MHpv92CTtN4PONek=",
>           "AAAAEgAAAAAAAAAAfn3koV5C+Z6q8U1LfPwlofeZ3jnWI6Iudfg5NOEmOtg="
>         ],
>         "value": "AAAACgAAAAAAAAAAAAAAAAX14QA="
>       },
>       {
>         "type": "contract",
>         "ledger": 1189977,
>         "ledgerClosedAt": "2024-04-25T17:52:26Z",
>         "contractId": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
>         "id": "0005110912298004480-0000000000",
>         "transactionIndex": 3,
>         "operationIndex": 0,
>         "txHash": "e1f2a3b4c5d6e7f8091a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4d5e6f70",
>         "topic": [
>           "AAAADwAAAAh0cmFuc2Zlcg==",
>           "AAAAEgAAAAAAAAAAfn3koV5C+Z6q8U1LfPwlofeZ3jnWI6Iudfg5NOEmOtg=",
>           "AAAAEgAAAAAAAAAAeo0X4ISuIjuArAyYXR0z8qyj0x0MHpv92CTtN4PONek="
>         ],
>         "value": "AAAACgAAAAAAAAAAAAAAAACYloA="
>       }
>     ],
>     "cursor": "gec1_AQEAAAASJnIAAAASJm0AAAAB...",
>     "scanStatus": "HAS_MORE",
>     "scannedLedger": 1189978,
>     "oldestLedger": 2,
>     "latestLedger": 1190004
>   }
> }
> ```

> [tab] Next page
>
> Continues the query above by sending only the `cursor` from the previous response and `limit`. The order and filters come from the cursor. The scan has no lower bound, so it reports `HAS_MORE` until it reaches the oldest ledger the node holds. Keep sending the cursor until `scanStatus` is `OLDEST_REACHED` or `COMPLETE`.
>
> **Request**
>
> ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
> curl -X POST \
> -H 'Content-Type: application/json' \
> -d '{
>   "jsonrpc": "2.0",
>   "id": 8675309,
>   "method": "queryEvents",
>   "params": {
>     "cursor": "gec1_AQEAAAASJnIAAAASJm0AAAAB...",
>     "limit": 2
>   }
> }' \
> https://soroban-testnet.stellar.org | jq
> ```
>
> ```js JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
> let requestBody = {
>   jsonrpc: "2.0",
>   id: 8675309,
>   method: "queryEvents",
>   params: {
>     cursor: "gec1_AQEAAAASJnIAAAASJm0AAAAB...",
>     limit: 2,
>   },
> };
> let res = await fetch("https://soroban-testnet.stellar.org", {
>   method: "POST",
>   headers: {
>     "Content-Type": "application/json",
>   },
>   body: JSON.stringify(requestBody),
> });
> let json = await res.json();
> console.log(json);
> ```
>
> ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
> import json, requests
> res = requests.post("https://soroban-testnet.stellar.org", json={
>     "jsonrpc": "2.0",
>     "id": 8675309,
>     "method": "queryEvents",
>     "params": {
>         "cursor": "gec1_AQEAAAASJnIAAAASJm0AAAAB...",
>         "limit": 2
>     }
> })
> print(json.dumps(res.json(), indent=4))
> ```
>
> ```json JSON theme={"theme":{"light":"github-light","dark":"github-dark"}}
> {
>   "jsonrpc": "2.0",
>   "id": 8675309,
>   "method": "queryEvents",
>   "params": {
>     "cursor": "gec1_AQEAAAASJnIAAAASJm0AAAAB...",
>     "limit": 2
>   }
> }
> ```
>
> **Result**
>
> ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
> {
>   "jsonrpc": "2.0",
>   "id": 8675309,
>   "result": {
>     "events": [
>       {
>         "type": "contract",
>         "ledger": 1189977,
>         "ledgerClosedAt": "2024-04-25T17:52:26Z",
>         "contractId": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
>         "id": "0005110912298004481-0000000000",
>         "transactionIndex": 3,
>         "operationIndex": 1,
>         "txHash": "e1f2a3b4c5d6e7f8091a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4d5e6f70",
>         "topic": [
>           "AAAADwAAAARtaW50",
>           "AAAAEgAAAAAAAAAAfn3koV5C+Z6q8U1LfPwlofeZ3jnWI6Iudfg5NOEmOtg="
>         ],
>         "value": "AAAACgAAAAAAAAAAAAAAAAX14QA="
>       },
>       {
>         "type": "contract",
>         "ledger": 1189950,
>         "ledgerClosedAt": "2024-04-25T17:50:11Z",
>         "contractId": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
>         "id": "0005110796333883392-0000000000",
>         "transactionIndex": 2,
>         "operationIndex": 0,
>         "txHash": "0a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f9",
>         "topic": [
>           "AAAADwAAAAh0cmFuc2Zlcg==",
>           "AAAAEgAAAAAAAAAAeo0X4ISuIjuArAyYXR0z8qyj0x0MHpv92CTtN4PONek=",
>           "AAAAEgAAAAAAAAAAfn3koV5C+Z6q8U1LfPwlofeZ3jnWI6Iudfg5NOEmOtg="
>         ],
>         "value": "AAAACgAAAAAAAAAAAAAAAAJiWgA="
>       }
>     ],
>     "cursor": "gec1_AQEAAAASJj4AAAASJj0AAAAA...",
>     "scanStatus": "HAS_MORE",
>     "scannedLedger": 1189951,
>     "oldestLedger": 2,
>     "latestLedger": 1190004
>   }
> }
> ```

### Errors

Invalid requests return JSON-RPC error code `-32602`. Because the human-readable error message may vary, use `error.data.reason` to identify the cause. Additional fields in `error.data` depend on the reason.

| `error.data.reason` | Other fields in `error.data` | Cause |
| - | - | - |
| `invalid_params` | `termsUsed` and `termBudget` when the filter term budget is exceeded | An unknown field, invalid value, combination of initial-query and cursor parameters, or too many filter terms. |
| `ledger_out_of_range` | `missingLedger`, `oldestLedger`, `latestLedger` | A requested range boundary or cursor position is outside the ledgers available on this node. If below `oldestLedger`, restart from the oldest available ledger or use a node with deeper history. If above `latestLedger`, retry when that ledger becomes available. |
| `cursor_malformed` | `oldestLedger`, `latestLedger` | The cursor is invalid or cannot be parsed. Start a new query. |

Other failures return a JSON-RPC internal error without additional error data.
