# Querying Data with gRPC

*[Documentation index](/llms.txt) · [Full index](/llms-full.txt)*

This guide provides practical examples for querying the Sui network using gRPC. For core concepts, see the [corresponding concepts page](/develop/accessing-data/grpc/what-is-grpc).

## Prerequisites

Before you begin, ensure you have access to a [gRPC](/develop/accessing-data/grpc)-enabled Sui full node. Check the [list of RPC and data providers](https://www.notion.so/mystenlabs/RPC-providers-offering-future-Sui-data-primitives-2466d9dcb4e980a99a36e9aafd8c17e0?source=copy_link) that support gRPC on their full nodes, and contact a provider directly to request access.

If your provider doesn't yet support gRPC, you can:

- Ask them to enable it.

- Reach out to the Sui Foundation team on Discord or Telegram for help.

## Field masks

A [`FieldMask` in protocol buffers](https://protobuf.dev/reference/protobuf/google.protobuf/#field-mask) 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, `FieldMask`s 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`, it defaults to `*` (all fields), unless documented otherwise.

- 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 presence

When using gRPC with Sui, it's important to understand how [field presence](https://github.com/protocolbuffers/protobuf/blob/main/docs/field_presence.md) 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 `string`s in the proto schema:

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

- `Digest`s: Represented as [Base58](https://learnmeabitcoin.com/technical/keys/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](https://grpc.io/docs/guides/error/#richer-error-model) defined in [AIP-193](https://google.aip.dev/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](https://datatracker.ietf.org/doc/html/rfc3339) 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`](https://github.com/fullstorydev/grpcurl).

### List available gRPC services

```shell
$ grpcurl <full node URL:port> list
```

The port on Sui Foundation managed full nodes is `443`.

### List available APIs in the `LedgerService`

```shell
$ grpcurl <full node URL:port> list sui.rpc.v2.LedgerService
```

### Get the events and effects details of a particular transaction

```shell
$ grpcurl -d '{ "digest": "J4NvV5iQZQFm1xKPYv9ffDCCPW6cZ4yFKsCqFUiDX5L4" }' <full node URL:port> sui.rpc.v2.LedgerService/GetTransaction
```

### Get the transactions in a particular checkpoint

```shell
$ grpcurl -d '{ "sequence_number": "164329987", "read_mask": { "paths": ["transactions"]} }' <full node URL:port> sui.rpc.v2.LedgerService/GetCheckpoint
```

### Get the latest information for a coin type

```shell
$ grpcurl -d '{ "coin_type": "0x2::sui::SUI" }' <full node URL:port> sui.rpc.v2.StateService/GetCoinInfo
```

### List the objects owned by a particular address

```shell
$ grpcurl -d '{ "owner": "0x94096a6a54129234237759c66e6ef1037224fb3102a0ae29d33b490281c8e4d5" }' <full node URL:port> sui.rpc.v2.StateService/ListOwnedObjects
```

### List the dynamic fields in a particular object

```shell
$ grpcurl -d '{ "parent": "0xb57fba584a700a5bcb40991e1b2e6bf68b0f3896d767a0da92e69de73de226ac" }' <full node URL:port> sui.rpc.v2.StateService/ListDynamicFields
```

## Access streaming data with Buf

`grpcurl` does not support server-side streaming RPCs. To test or experiment with `SubscriptionService`, use the [Buf CLI](https://buf.build/docs/cli/) instead.

```shell
$ buf curl --protocol grpc https://<full node URL>/sui.rpc.v2.SubscriptionService/SubscribeCheckpoints -d '{ "readMask": "sequenceNumber,digest,summary.timestamp" }'  --timeout 1m
```

## Build gRPC clients

:::info

Use one of the [supported SDKs](/develop/accessing-data/data-serving#supported-sdks) for building gRPC clients. If those SDKs do not satisfy your use case, refer to the examples below.
:::

## TypeScript

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

#### Step 1: Install dependencies

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

The default project has this structure:

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

Download all of the `sui/rpc/v2` proto files from [Github](https://github.com/MystenLabs/sui-apis/tree/main/proto) in the same folder.

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

```ts

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

```shell
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.

## Golang

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

#### Step 1: Install dependencies

First make sure you have `go` and `protoc` installed in your environment, and then install:

```shell
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
```

#### Step 2: Edit `go.mod`

Add the following content, making sure to update the version numbers to the latest versions:

```go
require (
  google.golang.org/grpc v1.60.0
  google.golang.org/protobuf v1.33.0
)
```

#### Step 3: Generate Go code from proto files

Assuming you have the `v2` proto files from [Github](https://github.com/MystenLabs/sui-apis/tree/main/proto), run:

```shell
protoc --proto_path=./protos --go_out=. --go-grpc_out=. protos/sui/rpc/v2/ledger_service.proto
```

#### Step 4: Edit `main.go` to get events and effects details of a particular transaction

```go
package main

import (
    "context"
    "crypto/tls"
    "fmt"
    "log"
    "time"

    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"

    pb "your_project/sui/rpc/v2" // adjust path based on where your generated .pb.go files are
)

func main() {
    // Set up gRPC connection with TLS (port 443)
		creds := credentials.NewTLS(&tls.Config{})
		conn, err := grpc.Dial("<full node URL>:443", grpc.WithTransportCredentials(creds))
		if err != nil {
			log.Fatalf("failed to connect: %v", err)
		}
		defer conn.Close()

    client := pb.NewLedgerServiceClient(conn)

    // Sample transaction digest in Base58 format
    base58Digest := "3ByWphQ5sAVojiTrTrGXGM5FmCVzpzYmhsjbhYESJtxp"

    // Build request
		req := &pb.GetTransactionRequest{
			Digest: base58Digest,
			ReadMask: &pb.TransactionReadMask{
				Paths: []string{"events", "effects"},
			},
		}

    // Make the request
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    resp, err := client.GetTransaction(ctx, req)
    if err != nil {
        log.Fatalf("GetTransaction failed: %v", err)
    }

    // Print the response
    fmt.Printf("Response:\n%+v\n", resp)
}
```

#### Step 5: Run the sample client

If your `go.mod` is properly set up, and you've already generated the gRPC code (`*.pb.go`, `*_grpc.pb.go`), run:

```shell
go run main.go
```

If you see errors like `cannot find package`, ensure you've generated the proto files and imported them correctly. If your generated files are in a nested directory like `sui/rpc/v2`, your import in `main.go` should match:

```go
import pb "your_project/sui/rpc/v2"
```

You can replace `your_project` with a module name or relative import path depending on how your `go.mod` is defined.

The example assumes that gRPC is available on port `443` which requires SSL. The digest in the request is directly provided in the `Base58` format, but check if you need to decode from your source format.

## Python

This example shows how to build a Python client for the Sui gRPC API. Optionally, refer to [`pysui`](https://github.com/FrankC01/pysui/), a community contributed SDK.

#### Step 1: Install dependencies

First make sure you have `python` and `protoc` installed in your environment, and then install:

```shell
pip install grpcio grpcio-tools protobuf
```

#### Step 2: Generate Python code from proto files

Assuming you have the `v2` proto files from [Github](https://github.com/MystenLabs/sui-apis/tree/main/proto), run:

```shell
python -m grpc_tools.protoc -I./protos --python_out=. --grpc_python_out=. ./protos/sui/rpc/v2/ledger_service.proto
```

#### Step 3: Edit `client.py` to get events and effects details of a particular transaction

```python
import grpc
from sui.rpc.v2 import ledger_service_pb2, ledger_service_pb2_grpc

def main():
    # Create secure channel to port 443
    channel = grpc.secure_channel("<full node URL>:443", grpc.ssl_channel_credentials())
    stub = ledger_service_pb2_grpc.LedgerServiceStub(channel)

    # Sample transaction digest in Base58 format
    base58_digest = "3ByWphQ5sAVojiTrTrGXGM5FmCVzpzYmhsjbhYESJtxp"

    # Build the request
    request = ledger_service_pb2.GetTransactionRequest(
        digest=base58_digest,
        read_mask=ledger_service_pb2.TransactionReadMask(paths=["events", "effects"])
    )

    # Make the RPC call
    response = stub.GetTransaction(request)

    # Print response
    print(response)

if __name__ == "__main__":
    main()
```

#### Step 4: Run the sample client

```shell
python client.py
```

The import paths like `sui.rpc.v2.ledger_service_pb2` depend on your proto structure. You might need to adjust `__init__.py` files or `$PYTHONPATH` to ensure proper module resolution.

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.
