# Sui gRPC API - High Performance Access

## High-Performance Blockchain Data Access

Dwellir's Sui gRPC API provides a high-performance alternative to traditional JSON-RPC for accessing Sui blockchain data. Built on Protocol Buffers and HTTP/2, gRPC offers superior performance, type safety, and efficient binary serialization for demanding applications that require minimal latency and maximum throughput.

**Endpoint** — connect over TLS on port 443:

```
api-sui-mainnet-full.n.dwellir.com:443
```

> Port 443 is typically not required — most gRPC libraries default to it for TLS connections. Some tools like `grpcurl` do require it explicitly.

**Authentication** — pass your API key as gRPC metadata (not as a URL path segment):

```
x-api-key: YOUR_API_TOKEN
```

Get your API token from [dashboard.dwellir.com](https://dashboard.dwellir.com). See [Connection Configuration](#connection-configuration) and [Authentication](#authentication) for full details, or jump straight to [language-specific setup guides](#language-specific-setup).

## Why Use gRPC?

### Performance Advantages

- **Binary Protocol**: Protocol Buffers provide compact binary encoding, reducing payload sizes by up to 70% compared to JSON
- **HTTP/2 Multiplexing**: Multiple concurrent requests over a single connection eliminate connection overhead
- **Streaming Support**: Server-streaming subscriptions deliver checkpoints without polling
- **Efficient Serialization**: Native binary format significantly reduces parsing overhead

### Developer Benefits

- **Strong Typing**: Protocol Buffer definitions provide compile-time type checking
- **Code Generation**: Automatic client generation from `.proto` files eliminates boilerplate
- **Language Support**: Native implementations available for Go, Python, TypeScript, Rust, and more
- **Built-in Features**: Deadlines, cancellation, and load balancing come standard

### Use Cases for gRPC

- **High-frequency trading**: Microsecond-level latency requirements
- **Real-time monitoring**: Live checkpoint, transaction, and event processing
- **Analytics pipelines**: Bulk data extraction and processing
- **Mobile applications**: Reduced bandwidth consumption on limited connections
- **Microservices**: Efficient inter-service communication in distributed architectures

## gRPC vs JSON-RPC Comparison

| Feature             | gRPC                                      | JSON-RPC                                                |
| ------------------- | ----------------------------------------- | ------------------------------------------------------- |
| **Protocol**        | HTTP/2 + Protocol Buffers                 | HTTP/1.1 + JSON                                         |
| **Payload Size**    | Compact binary (\~30% smaller)            | Text-based JSON                                         |
| **Streaming**       | Server-streaming checkpoint subscriptions | Request/response and deprecated WebSocket subscriptions |
| **Type Safety**     | Strong typing via `.proto`                | Runtime validation required                             |
| **Performance**     | 5-10x faster serialization                | Slower text parsing                                     |
| **Browser Support** | Requires gRPC-Web proxy                   | Native browser support                                  |
| **Tooling**         | Code generation required                  | Simpler setup                                           |

## Available Services

The Sui gRPC API is organized into seven specialized services:

### 1. Ledger Service

Access historical blockchain data and core object information:

- Retrieve objects by ID with field masking
- Query transactions with execution details
- Access checkpoint and epoch data
- Batch operations for multiple objects or transactions

### 2. State Service

Query current blockchain state efficiently:

- Check account balances for any coin type
- List owned objects with pagination
- Enumerate dynamic fields
- Retrieve coin metadata and information

### 3. Transaction Execution Service

Execute and broadcast transactions:

- Submit signed transactions for on-chain execution
- Simulate transactions before execution for gas estimation and validation

### 4. Move Package Service

Inspect Move smart contracts and modules:

- Retrieve package information and metadata
- Query function signatures and capabilities
- Inspect data types and structures
- List package version history

### 5. Subscription Service

Real-time checkpoint streaming:

- Subscribe to checkpoint updates as they finalize
- Request only the checkpoint fields needed with a field mask
- Inspect transactions and events client-side as checkpoints arrive

The standard Sui subscription does not support server-side filters for wallets,
Move calls, packages, modules, functions, or event types. It emits every
checkpoint. Use a field mask to reduce each response, then filter the selected
transaction and event data client-side. See
[SubscribeCheckpoints](https://www.dwellir.com/docs/sui/grpc/subscription/subscribe-checkpoints) for
request shapes and filtering examples.

### 6. Signature Verification Service

Cryptographic signature operations:

- Verify transaction signatures off-chain
- Validate multi-sig configurations
- Check signature authenticity

### 7. Name Service

Resolve SuiNS records:

- Resolve a SuiNS name to its record
- Reverse-resolve an address to its default name

## Connection Configuration

### Endpoint Structure

Dwellir's Sui gRPC endpoints follow this format:

```
api-sui-mainnet-full.n.dwellir.com:443
```

**Important Notes:**

- gRPC uses port **443**
- Connections require TLS encryption
- Authentication via metadata headers

### Network Endpoints

| Network     | gRPC Endpoint                             |
| ----------- | ----------------------------------------- |
| **Mainnet** | `api-sui-mainnet-full.n.dwellir.com:443`  |
| **Testnet** | Dedicated node clusters only (contact us) |

> **Note:** Testnet access is currently offered only through dedicated node clusters. Reach out to our team to provision a testnet endpoint.

## Authentication

All gRPC requests to Dwellir's Sui endpoints require sending your API token in the `x-api-key` metadata header:

```
x-api-key: YOUR_API_TOKEN
```

Do **not** append the token as a path segment to the gRPC endpoint.
Retrieve your API token from the [Dwellir dashboard](https://dashboard.dwellir.com) and pass it only via the header.

TypeScript
Python
Go

```typescript
const metadata = new grpc.Metadata();
metadata.add('x-api-key', API_TOKEN);

client.GetObject(request, metadata, (error, response) => { ... });
```

```python
metadata = [('x-api-key', API_TOKEN)]
response = client.GetObject(request, metadata=metadata)
```

```go
ctx := metadata.AppendToOutgoingContext(context.Background(), "x-api-key", apiKey)
resp, err := client.GetServiceInfo(ctx, &pb.GetServiceInfoRequest{})
```

### Security Best Practices

- **Never expose tokens in client-side code**: Use backend services to proxy gRPC requests
- **Rotate tokens periodically**: Generate new tokens through the Dwellir dashboard
- **Use environment variables**: Store tokens outside of source code
- **Monitor usage**: Track API consumption via the Dwellir dashboard

## Quick Start Guide

### Prerequisites

1. **Dwellir API Key**: Obtain from [dashboard.dwellir.com](https://dashboard.dwellir.com)
2. **Protocol Buffers**: Install `protoc` compiler for code generation
3. **gRPC Libraries**: Language-specific gRPC implementation

### Protocol Buffer Files

Download the official Sui proto definitions from the [MystenLabs sui-apis repository](https://github.com/MystenLabs/sui-apis):

```bash
# Clone the Sui API definitions
git clone https://github.com/MystenLabs/sui-apis.git
cd sui-apis
```

Key proto files:

- `ledger_service.proto` - Ledger service definitions
- `state_service.proto` - Current state queries
- `transaction_execution_service.proto` - Transaction execution and simulation
- `move_package_service.proto` - Move package inspection
- `subscription_service.proto` - Checkpoint subscriptions
- `signature_verification_service.proto` - Signature operations
- `name_service.proto` - SuiNS resolution

### Language-Specific Setup

TypeScript
Python
Go

```bash
# Create project directory
mkdir sui-grpc-client && cd sui-grpc-client

# Initialize Node.js project
npm init -y

# Install dependencies
npm install @grpc/grpc-js @grpc/proto-loader
npm install -D @types/node tsx

# Download proto files
mkdir -p protos
# Copy proto files from sui-apis repository to protos/
```

**Basic Client Example:**

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

// Configuration
const ENDPOINT = 'api-sui-mainnet-full.n.dwellir.com:443';
const API_TOKEN = 'your_api_token_here';

// Load proto definition
const packageDefinition = protoLoader.loadSync(
  './protos/sui/rpc/v2/ledger_service.proto',
  {
    keepCase: true,
    longs: String,
    enums: String,
    defaults: true,
    oneofs: true,
    includeDirs: ['./protos']
  }
);

const protoDescriptor = grpc.loadPackageDefinition(packageDefinition) as any;

// Create secure channel with TLS
const credentials = grpc.credentials.createSsl();

// Setup authentication metadata
const metadata = new grpc.Metadata();
metadata.add('x-api-key', API_TOKEN);

// Create client
const client = new protoDescriptor.sui.rpc.v2.LedgerService(
  ENDPOINT,
  credentials
);

// Example: Get object information
const objectId = '0x5';

const request = {
  object_id: objectId,
  read_mask: {
    paths: ['object_id', 'version', 'digest', 'owner', 'object_type']
  }
};

client.GetObject(request, metadata, (error, response) => {
  if (error) {
    console.error('Error:', error.message);
    return;
  }

  console.log('Object data:', JSON.stringify(response, null, 2));
});
```

```bash
# Create project directory
mkdir sui-grpc-client && cd sui-grpc-client

# Create virtual environment
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install dependencies
pip install grpcio grpcio-tools protobuf googleapis-common-protos

# Create protos directory
mkdir protos
# Copy proto files from sui-apis repository to protos/

# Generate Python code from proto files
python -m grpc_tools.protoc \
  --proto_path=./protos \
  --python_out=. \
  --grpc_python_out=. \
  ./protos/sui/rpc/v2/*.proto
```

**Basic Client Example:**

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

# Configuration
ENDPOINT = 'api-sui-mainnet-full.n.dwellir.com:443'
API_TOKEN = 'your_api_token_here'

# Create secure channel with TLS
credentials = grpc.ssl_channel_credentials()
channel = grpc.secure_channel(ENDPOINT, credentials)

# Create client stub
client = ledger_service_pb2_grpc.LedgerServiceStub(channel)

# Setup authentication metadata
metadata = [('x-api-key', API_TOKEN)]

# Example: Get object information
object_id = '0x5'

request = ledger_service_pb2.GetObjectRequest(
    object_id=object_id,
    read_mask=field_mask_pb2.FieldMask(
        paths=['object_id', 'version', 'digest', 'owner', 'object_type']
    )
)

try:
    response = client.GetObject(request, metadata=metadata)
    print(f'Object data: {response}')
except grpc.RpcError as e:
    print(f'Error: {e.code()}: {e.details()}')
finally:
    channel.close()
```

```bash
# Create project directory
mkdir sui-grpc-client && cd sui-grpc-client

# Initialize Go module
go mod init sui-grpc-client

# Install dependencies
go get google.golang.org/grpc
go get google.golang.org/protobuf

# Install protoc plugins for Go code generation
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

# Ensure Go bin is in PATH (add to ~/.zshrc or ~/.bash_profile for persistence)
export PATH="$PATH:$HOME/go/bin"

# Copy proto files from sui-apis repository
mkdir -p protos
cp -r ../proto/* protos/

# Add go_package option to all proto files
find protos/sui/rpc/v2 -name "*.proto" -type f | while read proto_file; do
    if ! grep -q "option go_package" "$proto_file"; then
        sed -i.bak '/^package sui.rpc.v2;$/a\
\
option go_package = "sui-grpc-client/sui/rpc/v2";
' "$proto_file"
    fi
done

# Generate Go code from proto files
protoc --go_out=. --go_opt=paths=source_relative \
  --go-grpc_out=. --go-grpc_opt=paths=source_relative \
  --proto_path=./protos \
  ./protos/sui/rpc/v2/*.proto
```

**Basic Client Example:**

```go
package main

import (
	"context"
	"fmt"
	"log"
	"time"

	pb "sui-grpc-client/sui/rpc/v2"

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

const (
	// Dwellir gRPC endpoint - note: uses .tech domain, not .com
	endpoint = "api-sui-mainnet-full.n.dwellir.com:443"
	apiKey   = "api_key"
)

func main() {
	// Create TLS credentials for secure connection
	creds := credentials.NewClientTLSFromCert(nil, "")

	// Connect to Dwellir Sui gRPC server using NewClient (replaces deprecated Dial)
	conn, err := grpc.NewClient(
		endpoint,
		grpc.WithTransportCredentials(creds),
	)
	if err != nil {
		log.Fatalf("Failed to create client: %v", err)
	}
	defer conn.Close()

	client := pb.NewLedgerServiceClient(conn)

	// Setup authentication metadata with API key
	// Dwellir uses x-api-key header (not authorization or x-api-key)
	ctx := metadata.AppendToOutgoingContext(
		context.Background(),
		"x-api-key", apiKey,
	)

	// Set timeout
	ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
	defer cancel()

	// Get service info
	resp, err := client.GetServiceInfo(ctx, &pb.GetServiceInfoRequest{})
	if err != nil {
		log.Fatalf("GetServiceInfo failed: %v", err)
	}

	fmt.Printf("Connected to Sui Node via Dwellir\n")
	fmt.Printf("Chain: %s\n", resp.GetChain())
	fmt.Printf("Chain ID: %s\n", resp.GetChainId())
	fmt.Printf("Current Epoch: %d\n", resp.GetEpoch())
	fmt.Printf("Checkpoint Height: %d\n", resp.GetCheckpointHeight())
	fmt.Printf("Server: %s\n", resp.GetServer())
}
```

## Field Masking

gRPC requests support field masking to optimize response payloads and reduce bandwidth. Specify only the fields you need:

```typescript
const request = {
  object_id: '0x5',
  read_mask: {
    paths: ['object_id', 'version', 'owner'] // Only return these fields
  }
};
```

**Benefits:**

- Reduced response sizes (up to 80% smaller)
- Faster serialization and network transfer
- Lower bandwidth costs
- Improved application performance

## Error Handling

gRPC provides standardized error codes for consistent error handling:

| Code                      | Description                | Action                |
| ------------------------- | -------------------------- | --------------------- |
| `OK` (0)                  | Success                    | Continue processing   |
| `CANCELLED` (1)           | Client cancelled           | Retry if needed       |
| `INVALID_ARGUMENT` (3)    | Invalid request parameters | Fix request and retry |
| `NOT_FOUND` (5)           | Resource not found         | Verify object IDs     |
| `ALREADY_EXISTS` (6)      | Resource exists            | Handle duplicate      |
| `PERMISSION_DENIED` (7)   | Authentication failed      | Check API token       |
| `RESOURCE_EXHAUSTED` (8)  | Rate limit exceeded        | Implement backoff     |
| `FAILED_PRECONDITION` (9) | System state invalid       | Retry later           |
| `UNAVAILABLE` (14)        | Service unavailable        | Retry with backoff    |
| `DEADLINE_EXCEEDED` (4)   | Request timeout            | Increase timeout      |

### Example Error Handling

TypeScript
Python

```typescript
client.GetObject(request, metadata, (error, response) => {
  if (error) {
    switch (error.code) {
      case grpc.status.NOT_FOUND:
        console.error('Object not found:', error.message);
        break;
      case grpc.status.PERMISSION_DENIED:
        console.error('Authentication failed. Check API token.');
        break;
      case grpc.status.RESOURCE_EXHAUSTED:
        console.error('Rate limit exceeded. Retrying after backoff...');
        // Implement exponential backoff
        break;
      case grpc.status.UNAVAILABLE:
        console.error('Service temporarily unavailable. Retrying...');
        // Retry with backoff
        break;
      default:
        console.error('Unexpected error:', error.message);
    }
    return;
  }

  // Process successful response
  console.log('Success:', response);
});
```

```python
import grpc
import time

def get_object_with_retry(client, request, metadata, max_retries=3):
    """Get object with automatic retry logic"""
    for attempt in range(max_retries):
        try:
            response = client.GetObject(request, metadata=metadata)
            return response
        except grpc.RpcError as e:
            code = e.code()

            if code == grpc.StatusCode.NOT_FOUND:
                print(f'Object not found: {e.details()}')
                return None
            elif code == grpc.StatusCode.PERMISSION_DENIED:
                print(f'Authentication failed: {e.details()}')
                return None
            elif code == grpc.StatusCode.RESOURCE_EXHAUSTED:
                wait_time = 2 ** attempt  # Exponential backoff
                print(f'Rate limited. Retrying in {wait_time}s...')
                time.sleep(wait_time)
            elif code == grpc.StatusCode.UNAVAILABLE:
                wait_time = 2 ** attempt
                print(f'Service unavailable. Retrying in {wait_time}s...')
                time.sleep(wait_time)
            else:
                print(f'Unexpected error: {code}: {e.details()}')
                return None

    print(f'Failed after {max_retries} attempts')
    return None
```

## Performance Optimization

### Connection Pooling

Reuse gRPC channels across requests to avoid connection overhead:

```typescript
// Create a single channel for the application lifecycle
const channel = new grpc.Client(
  ENDPOINT,
  credentials,
  { 'grpc.keepalive_time_ms': 10000 }
);

// Reuse channel for all services
const ledgerClient = new protoDescriptor.sui.rpc.v2.LedgerService(channel);
const stateClient = new protoDescriptor.sui.rpc.v2.StateService(channel);
```

### Batch Requests

Use batch methods when querying multiple items:

```typescript
// Efficient: Single batch request
const batchResponse = await client.BatchGetObjects({
  object_ids: ['0x1', '0x2', '0x3', '0x4', '0x5']
});

// Inefficient: Multiple individual requests
for (const id of objectIds) {
  await client.GetObject({ object_id: id }); // Avoid this pattern
}
```

### Field Masking

Request only necessary fields to minimize payload size:

```typescript
// Efficient: Only request needed fields
const request = {
  object_id: '0x5',
  read_mask: { paths: ['object_id', 'owner'] }
};

// Inefficient: Requesting all fields
const request = { object_id: '0x5' }; // Returns everything
```

### Compression

Enable gRPC compression for large payloads:

```typescript
const options = {
  'grpc.default_compression_algorithm': grpc.compressionAlgorithms.gzip,
  'grpc.default_compression_level': grpc.compressionLevels.high
};

const client = new protoDescriptor.sui.rpc.v2.LedgerService(
  ENDPOINT,
  credentials,
  options
);
```

## Real-Time Streaming

gRPC's streaming capabilities enable real-time blockchain monitoring:

### Checkpoint Subscription Example

```typescript
const subscriptionDefinition = protoLoader.loadSync(
  './protos/sui/rpc/v2/subscription_service.proto',
  {
    keepCase: true,
    longs: String,
    enums: String,
    defaults: true,
    oneofs: true,
    includeDirs: ['./protos']
  }
);
const subscriptionDescriptor = grpc.loadPackageDefinition(
  subscriptionDefinition
) as any;

const request = {
  read_mask: {
    paths: [
      'sequence_number',
      'digest',
      'summary.timestamp',
      'transactions.digest'
    ]
  }
};

const subscriptionClient = new subscriptionDescriptor.sui.rpc.v2.SubscriptionService(
  ENDPOINT,
  credentials
);
const stream = subscriptionClient.SubscribeCheckpoints(request, metadata);

stream.on('data', (response) => {
  const checkpoint = response.checkpoint;
  if (!checkpoint) return;

  console.log('New checkpoint:', {
    sequence: checkpoint.sequence_number,
    digest: checkpoint.digest,
    timestamp: checkpoint.summary?.timestamp,
    txCount: checkpoint.transactions?.length ?? 0
  });
});

stream.on('error', (error) => {
  console.error('Stream error:', error.message);
  // Implement reconnection logic
});

stream.on('end', () => {
  console.log('Stream ended');
});
```

`SubscribeCheckpoints` does not support server-side filters. A field mask only
selects which fields are returned for every checkpoint; it does not select
which checkpoints or transactions the server sends. Request the fields needed
for matching, then filter transactions and events client-side. For example:

- Wallet senders: `transactions.transaction.sender`
- Wallet balance changes: `transactions.balance_changes`
- Move package, module, and function calls: `transactions.transaction.kind`
- Event package, module, sender, and type: `transactions.events.events`

[Sui's native gRPC guidance](https://docs.sui.io/develop/accessing-data/grpc/what-is-grpc)
recommends GraphQL for filtered historical transaction and event queries. It
is useful for backfills and lookups, but it does not replace the live global
checkpoint subscription.

### Stream Management Best Practices

1. **Recover gaps on reconnect**: Persist the last cursor, compare it with the first cursor after reconnecting, and backfill missing checkpoints before processing buffered live data
2. **Handle backpressure**: Process data faster than it arrives or implement buffering
3. **Monitor connection health**: Use keepalive pings and heartbeats
4. **Graceful shutdown**: Close streams properly to avoid resource leaks

## Best Practices

### 1. Use Appropriate Timeouts

Set reasonable timeouts to prevent hanging requests:

```typescript
const deadline = new Date();
deadline.setSeconds(deadline.getSeconds() + 10);

client.GetObject(request, { deadline }, (error, response) => {
  // Handle response
});
```

### 2. Implement Exponential Backoff

Handle rate limits and transient failures gracefully:

```typescript
async function retryWithBackoff(fn, maxRetries = 5) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (i === maxRetries - 1) throw error;

      const waitTime = Math.min(1000 * Math.pow(2, i), 30000);
      await new Promise(resolve => setTimeout(resolve, waitTime));
    }
  }
}
```

### 3. Monitor and Log

Track gRPC performance metrics:

```typescript
const call = client.GetObject(request, metadata, callback);

call.on('status', (status) => {
  console.log('RPC Status:', status.code, status.details);
});

call.on('metadata', (metadata) => {
  console.log('Server metadata:', metadata.getMap());
});
```

### 4. Validate Inputs

Validate request parameters before sending:

```typescript
function isValidObjectId(id: string): boolean {
  return /^0x[a-f0-9]+$/i.test(id);
}

if (!isValidObjectId(objectId)) {
  throw new Error('Invalid object ID format');
}
```

## Migration from JSON-RPC

Transitioning from JSON-RPC to gRPC requires generated clients and explicit
request and response mapping. Use this table as a starting point:

| JSON-RPC                      | gRPC Equivalent                                                                                   |
| ----------------------------- | ------------------------------------------------------------------------------------------------- |
| `sui_getObject`               | `LedgerService.GetObject`                                                                         |
| `suix_getBalance`             | `StateService.GetBalance`                                                                         |
| `sui_executeTransactionBlock` | `TransactionExecutionService.ExecuteTransaction`                                                  |
| `suix_subscribeEvent`         | No direct filtered subscription equivalent; use `SubscribeCheckpoints` with client-side filtering |

### Example Migration

**Before (JSON-RPC):**

```typescript
const response = await fetch(endpoint, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'sui_getObject',
    params: [objectId],
    id: 1
  })
});
const data = await response.json();
```

**After (gRPC):**

```typescript
const response = await new Promise((resolve, reject) => {
  client.GetObject(
    { object_id: objectId },
    metadata,
    (error, response) => {
      if (error) reject(error);
      else resolve(response);
    }
  );
});
```

## Troubleshooting

### Common Issues

**Connection Refused**

- Verify port 443 is used for gRPC
- Check firewall settings allow outbound connections on port 443
- Ensure TLS credentials are properly configured

**Authentication Errors**

- Verify API token is correct and active
- Check token is passed in `x-api-key` metadata header
- Confirm endpoint URL matches your Dwellir account

**Timeout Errors**

- Increase request timeout/deadline
- Check network connectivity and latency
- Verify endpoint availability via Dwellir dashboard

**Protocol Buffer Errors**

- Ensure proto files match server version
- Regenerate client code after proto updates
- Check import paths and dependencies

## Support and Resources

### Documentation

- [Ledger Service Methods](https://www.dwellir.com/docs/sui/grpc/ledger/get-object) - Object and transaction queries
- [State Service Methods](https://www.dwellir.com/docs/sui/grpc/state/get-balance) - Current state queries
- [Subscription Service](https://www.dwellir.com/docs/sui/grpc/subscription/subscribe-checkpoints) - Checkpoint streaming

### Getting Help

- **Email**: <support@dwellir.com>
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)
- **Status Page**: Monitor service health and incidents

### Additional Resources

- [Sui Official Documentation](https://docs.sui.io)

***

*Ready to build with gRPC? [Get your API key](https://dashboard.dwellir.com) and experience the performance difference with Dwellir's enterprise-grade Sui infrastructure.*
