Skip to main content

Querying Data with gRPC

This guide provides practical examples for querying the Sui network using gRPC. For core concepts, see the corresponding concepts page.

  • 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_mask is 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 FieldMask behavior.

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 pathDescription
object_idThe object's unique ID
versionThe object's version (sequence number)
digestThe object's content digest
object_typeThe Move type of the object
ownerOwnership information (address-owned, shared, immutable, or wrapped)
contentsThe object's BCS-encoded content
contents.jsonThe object's content as JSON
previous_transactionDigest of the transaction that last modified this object
storage_rebateStorage rebate in MIST if the object is deleted

LedgerService.GetTransaction / BatchGetTransactions

Field pathDescription
digestThe transaction digest
effectsExecution effects (status, gas used, created/mutated/deleted objects)
eventsEvents emitted during execution
signaturesTransaction signatures
transactionThe transaction data (sender, commands, gas info)
balance_changesBalance changes caused by the transaction
objectsObject mutations (created, mutated, deleted, wrapped, unwrapped)

LedgerService.GetCheckpoint

Field pathDescription
sequence_numberThe checkpoint sequence number
digestThe checkpoint digest
summaryCheckpoint summary (timestamp, gas costs, transaction count)
summary.timestampFinalization timestamp
summary.total_network_transactionsCumulative transaction count up to this checkpoint
transactionsTransaction digests included in this checkpoint

LedgerService.GetEpoch

Field pathDescription
epochThe epoch number
reference_gas_priceReference gas price for this epoch in MIST
startEpoch start timestamp
endEpoch end timestamp (set after epoch ends)
protocol_configProtocol 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 typeDefault valueSource
Connection max age4 hours (server sends GOAWAY)DEFAULT_MAX_CONNECTION_AGE
gRPC timeout (unary)60 secondsDEFAULT_GRPC_TIMEOUT
Subscription buffer1,024 items per subscriberCHECKPOINT_MAILBOX_SIZE
Max subscribers1,024DEFAULT_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.

info

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:

  • Address and ObjectId: Represented as 64 hexadecimal characters with a leading 0x.

  • Digests: Represented as Base58.

  • TypeTag and StructTag: Represented in their canonical string format (such as 0x0000000000000000000000000000000000000000000000000000000000000002::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, or devnet).

  • 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:

ReasonMeaningAction
ITEM_LIMITReturned the requested number of items.Resume from the latest watermark.cursor.
SCAN_LIMITThe 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_TIPReached 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_BOUNDReached the end_checkpoint specified in the request.No more results in this range.
CURSOR_BOUNDReached 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.

Build gRPC clients

info

Use one of the supported SDKs for building gRPC clients. If those SDKs do not satisfy your use case, refer to the examples below.

This example shows how to build a TypeScript client for the Sui gRPC API.

Step 1: Install dependencies

npm init -y
npm install @grpc/grpc-js @grpc/proto-loader
npm i -D tsx

The default project has this structure:

.
├── protos/
│ └── sui/
│ └── node/
│ └── v2/
│ ├── ledger_service.proto
│ └── *.proto
├── client.ts
├── package.json

Download all of the sui/rpc/v2 proto files from Github in the same folder.

Step 2: Edit client.ts to get events and effects details of a particular transaction

import * as grpc from '@grpc/grpc-js';
import * as protoLoader from '@grpc/proto-loader';
import * as path from 'path';

const PROTO_PATH = path.join(__dirname, 'protos/sui/rpc/v2/ledger_service.proto');

// Load proto definitions
const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
includeDirs: [path.join(__dirname, 'protos')],
});

const suiProto = grpc.loadPackageDefinition(packageDefinition) as any;
const LedgerService = suiProto.sui.rpc.v2.LedgerService;

// Create gRPC client
const client = new LedgerService(
'<FULL_NODE_URL>:443',
grpc.credentials.createSsl()
);

// Sample transaction digest in Base58 format
const base58Digest = '3ByWphQ5sAVojiTrTrGXGM5FmCVzpzYmhsjbhYESJtxp';

// Construct the request
const request = {
digest: base58Digest,
read_mask: {
paths: ['events', 'effects'],
},
};

// Make gRPC call
client.GetTransaction(request, (err: any, response: any) => {
if (err) {
console.error('Error:', err);
} else {
console.log('Response:', JSON.stringify(response, null, 2));
}
});

Step 3: Run the sample client

npx tsx c
  • proto-loader handles any nested .proto files. Just make sure paths and imports are correct.

  • The example assumes that gRPC is available on port 443 which requires SSL.

  • Digest in the request is directly provided in the Base58 format, but check if you need to decode from your source format.