Querying Data with gRPC
This guide provides practical examples for querying the Sui network using gRPC. For core concepts, see the corresponding concepts page.
- Prerequisites
- Obtain access to a gRPC-enabled Sui full node. Check the list of RPC and data providers that support gRPC on their full nodes, and contact a provider directly to request access.
If your provider does not support gRPC, ask them to enable it or contact the Sui Foundation team on Discord or Telegram for help.
Field masks
A FieldMask in protocol buffers is a mechanism used to specify a subset of fields within a message that should be read, updated, or returned. Instead of retrieving the entire object, a client can request only the specific fields they need by providing a list of field paths. This improves performance and reduces unnecessary data transfer.
In the Sui gRPC API, FieldMasks are used in requests like GetTransaction, GetObject, and so on to control which parts are included in the response (like the effects and events of a transaction).
Field masks are defined using google.protobuf.FieldMask and typically appear in the request message as read_mask. You can pass an explicit value of * to request all fields.
If you omit read_mask, the server applies a method-specific default that returns a minimal subset of fields (for example, object_id,version,digest for GetObject). Pass * explicitly to request all fields. See read_mask_defaults.rs for the full list of defaults.
-
Each field path in the mask must match the field structure of the response proto message. Nested fields are supported using dot notation.
-
In batch APIs, only the top-level
read_maskis respected. The API ignores any masks inside sub-requests. -
In some cases, non-terminal repeated fields might be supported in the mask, even if this is atypical per standard
FieldMaskbehavior.
Field path reference
The following tables list commonly used read_mask field paths for each service method. Field paths follow the proto message structure defined in the sui-apis proto source and support dot notation for nested fields.
LedgerService.GetObject / BatchGetObjects
| Field path | Description |
|---|---|
object_id | The object's unique ID |
version | The object's version (sequence number) |
digest | The object's content digest |
object_type | The Move type of the object |
owner | Ownership information (address-owned, shared, immutable, or wrapped) |
contents | The object's BCS-encoded content |
contents.json | The object's content as JSON |
previous_transaction | Digest of the transaction that last modified this object |
storage_rebate | Storage rebate in MIST if the object is deleted |
LedgerService.GetTransaction / BatchGetTransactions
| Field path | Description |
|---|---|
digest | The transaction digest |
effects | Execution effects (status, gas used, created/mutated/deleted objects) |
events | Events emitted during execution |
signatures | Transaction signatures |
transaction | The transaction data (sender, commands, gas info) |
balance_changes | Balance changes caused by the transaction |
objects | Object mutations (created, mutated, deleted, wrapped, unwrapped) |
LedgerService.GetCheckpoint
| Field path | Description |
|---|---|
sequence_number | The checkpoint sequence number |
digest | The checkpoint digest |
summary | Checkpoint summary (timestamp, gas costs, transaction count) |
summary.timestamp | Finalization timestamp |
summary.total_network_transactions | Cumulative transaction count up to this checkpoint |
transactions | Transaction digests included in this checkpoint |
LedgerService.GetEpoch
| Field path | Description |
|---|---|
epoch | The epoch number |
reference_gas_price | Reference gas price for this epoch in MIST |
start | Epoch start timestamp |
end | Epoch end timestamp (set after epoch ends) |
protocol_config | Protocol configuration parameters |
SubscriptionService streams
SubscribeCheckpoints, SubscribeTransactions, and SubscribeEvents accept a read_mask that applies to the checkpoint, transaction, or event payload in each response frame. Use the same field paths as the corresponding Get* or List* methods.
Connection and buffer limits
The following limits are configured in the Sui full node source code and apply to all gRPC endpoints unless the operator overrides them:
| Limit type | Default value | Source |
|---|---|---|
| Connection max age | 4 hours (server sends GOAWAY) | DEFAULT_MAX_CONNECTION_AGE |
| gRPC timeout (unary) | 60 seconds | DEFAULT_GRPC_TIMEOUT |
| Subscription buffer | 1,024 items per subscriber | CHECKPOINT_MAILBOX_SIZE |
| Max subscribers | 1,024 | DEFAULT_MAX_SUBSCRIBERS |
The public Sui Foundation endpoints at fullnode.<network>.sui.io are behind load balancers that impose additional rate limits (requests per second, concurrent streams, and message size caps) beyond what the node itself configures. Contact your provider for their specific limits, or check the full node's grpc configuration section if you operate your own node.
Field presence
When using gRPC with Sui, it's important to understand how field presence works, especially when dealing with proto3 syntax. In proto3, primitive fields like numbers, booleans, and strings are always initialized to a default value if not present in the message. This means you cannot tell whether a value is explicitly set or just left out. To give you that distinction, Sui marks all fields as optional, even if they are required by the API.
As a user of the API, this lets you detect whether a field value is actually provided or just defaulted and write clients that can perform partial updates or simulate intent like distinguishing between an explicitly empty input versus a missing one.
If a field is marked optional in the proto, it might still be required for the request to be valid. This is a protobuf quirk, not an indication of actual business logic.
Encoding
In the Sui gRPC API, identifiers with standard human-readable formats are represented as strings in the proto schema:
-
AddressandObjectId: Represented as 64 hexadecimal characters with a leading0x. -
Digests: Represented as Base58. -
TypeTagandStructTag: Represented in their canonical string format (such as0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>)
Pagination
When using gRPC APIs that return lists of data like account balances, owned objects, and so on, you typically need to handle pagination. These APIs return results in chunks and include tokens to help you request the next batch.
In the request, provide a page_size to control how many items you want returned. If you leave this unset or set it to 0, the API uses a sensible default. You can also include a page_token in the request, which tells the server where to continue from. You get this token from the previous response.
The response includes a list of results and a next_page_token value, which you can pass into your next request to get the next page. When the server returns an empty next_page_token, you have reached the end of the list.
Make sure to keep all other parameters in your request the same between paginated calls. Otherwise, the server might reject the request with an INVALID_ARGUMENT error.
Errors
The Sui gRPC services follow the richer error model defined in AIP-193. When an RPC returns a non-OK status code, detailed error information is typically included in the grpc-status-details-bin header. This header contains a google.rpc.Status message encoded in Base64.
You can decode this message to access structured error details, which might include specific causes, context, or metadata. This makes it easier to understand and handle errors programmatically in your client applications.
HTTP headers
In many gRPC responses, the Sui API includes additional metadata in the form of HTTP headers. These headers provide contextual information about the current network state and might be useful for debugging, telemetry, or understanding the data's freshness.
Here are the headers you might encounter:
-
x-sui-chain-id: The chain ID of the current network. -
x-sui-chain: A human-readable name for the current network (mainnet,testnet, ordevnet). -
x-sui-checkpoint-height: The height of the latest checkpoint at the time of the response. -
x-sui-lowest-available-checkpoint: The earliest checkpoint for which transaction and checkpoint data can still be queried. -
x-sui-lowest-available-checkpoint-objects: The earliest checkpoint from which object data (input and output) is available. -
x-sui-epoch: The current epoch of the network. -
x-sui-timestamp-ms: The network timestamp in milliseconds since the Unix epoch. -
x-sui-timestamp: The network timestamp in milliseconds since the Unix epoch in human-readable RFC 3339 format.
Not all headers are guaranteed to be present in every API response. They are only included when applicable to the given RPC.
Access data using grpcurl
Interact with gRPC by using grpcurl.
List available gRPC services
$ grpcurl <FULL_NODE_URL> list
The port on Sui Foundation managed full nodes is 443.
List available APIs in the LedgerService
$ grpcurl <FULL_NODE_URL> list sui.rpc.v2.LedgerService
Get the events and effects details of a particular transaction
$ grpcurl -d '{ "digest": "J4NvV5iQZQFm1xKPYv9ffDCCPW6cZ4yFKsCqFUiDX5L4" }' <FULL_NODE_URL> sui.rpc.v2.LedgerService/GetTransaction
Get the transactions in a particular checkpoint
$ grpcurl -d '{ "sequence_number": "164329987", "read_mask": { "paths": ["transactions"]} }' <FULL_NODE_URL> sui.rpc.v2.LedgerService/GetCheckpoint
Get the latest information for a coin type
$ grpcurl -d '{ "coin_type": "0x2::sui::SUI" }' <FULL_NODE_URL> sui.rpc.v2.StateService/GetCoinInfo
List the objects owned by a particular address
$ grpcurl -d '{ "owner": "0x94096a6a54129234237759c66e6ef1037224fb3102a0ae29d33b490281c8e4d5" }' <FULL_NODE_URL> sui.rpc.v2.StateService/ListOwnedObjects
List the dynamic fields in a particular object
$ grpcurl -d '{ "parent": "0xb57fba584a700a5bcb40991e1b2e6bf68b0f3896d767a0da92e69de73de226ac" }' <FULL_NODE_URL> sui.rpc.v2.StateService/ListDynamicFields
List transactions matching a filter
Use LedgerService.ListTransactions to query transactions over a checkpoint range with a TransactionFilter. The service returns a server-side stream.
Run the following command:
$ grpcurl -d '{
"start_checkpoint": "1000000",
"end_checkpoint": "1000100",
"filter": {
"terms": [{
"literals": [{
"sender": { "address": "<ADDRESS>" }
}]
}]
}
}' <FULL_NODE_URL> sui.rpc.v2.LedgerService/ListTransactions
List events matching a filter
Use LedgerService.ListEvents to query events over a checkpoint range with an EventFilter.
Run the following command:
$ grpcurl -d '{
"start_checkpoint": "1000000",
"end_checkpoint": "1000100",
"filter": {
"terms": [{
"literals": [{
"event_type": { "event_type": "<PACKAGE>::module::MyEvent" }
}]
}]
}
}' <FULL_NODE_URL> sui.rpc.v2.LedgerService/ListEvents
List checkpoints
Use LedgerService.ListCheckpoints to query a range of checkpoints.
Run the following command:
$ grpcurl -d '{
"start_checkpoint": "1000000",
"end_checkpoint": "1000010",
"read_mask": { "paths": ["digest", "summary"] }
}' <FULL_NODE_URL> sui.rpc.v2.LedgerService/ListCheckpoints
Access streaming data with Buf
grpcurl handles server-side streaming for finite calls like LedgerService.List*. For indefinite SubscriptionService streams, the Buf CLI provides better timeout and reconnection control.
Subscribe to checkpoints
$ buf curl --protocol grpc https://<FULL_NODE_URL>/sui.rpc.v2.SubscriptionService/SubscribeCheckpoints -d '{ "readMask": "sequenceNumber,digest,summary.timestamp" }' --timeout 1m
Subscribe to transactions with a filter
Use SubscriptionService.SubscribeTransactions to stream transactions that match a TransactionFilter from the current tip of the chain.
Run the following command:
$ buf curl --protocol grpc \
https://<FULL_NODE_URL>/sui.rpc.v2.SubscriptionService/SubscribeTransactions \
-d '{
"filter": {
"terms": [{
"literals": [{
"sender": { "address": "<ADDRESS>" }
}]
}]
}
}' \
--timeout 5m
Subscribe to events with a filter
Use SubscriptionService.SubscribeEvents to stream events that match an EventFilter from the current tip of the chain.
Run the following command:
$ buf curl --protocol grpc \
https://<FULL_NODE_URL>/sui.rpc.v2.SubscriptionService/SubscribeEvents \
-d '{
"filter": {
"terms": [{
"literals": [{
"event_type": { "event_type": "<PACKAGE>::module::MyEvent" }
}]
}]
}
}' \
--timeout 5m
Pagination with watermarks
Every response frame in a list API stream includes a watermark with a cursor that records the server's scan position. When the stream ends, the final frame contains a query_end with a reason field indicating why the server stopped:
| Reason | Meaning | Action |
|---|---|---|
ITEM_LIMIT | Returned the requested number of items. | Resume from the latest watermark.cursor. |
SCAN_LIMIT | The server's internal scan budget was exhausted before finding enough results. Common with sparse filters. | Resume from the latest watermark.cursor. The server made progress even if it returned fewer items than requested. |
LEDGER_TIP | Reached the current tip of the chain (no end_checkpoint was specified). | No more results available yet. Poll later or switch to a Subscribe* stream. |
CHECKPOINT_BOUND | Reached the end_checkpoint specified in the request. | No more results in this range. |
CURSOR_BOUND | Reached a cursor-derived boundary. | Resume from the latest watermark.cursor. |
To paginate, take the cursor from the latest watermark in the stream and pass it as options.after (for ascending order) or options.before (for descending order) in your next request. The watermark also tells you how much of the checkpoint range has been covered, which is useful when a sparse filter produces few or no matching items.
For operator-level configuration of these APIs (timeouts, item limits, scan budgets), see Ledger history configuration.