Skip to main content

Overview

The Client is the foundational component of the NEAR API TypeScript library. It provides a strongly-typed interface to interact with NEAR RPC endpoints, handling network communication, caching, and error management.

Architecture

The Client follows a dual-variant pattern, offering both throwable and safe versions of every method:
  • Throwable variants: Traditional methods that throw errors (e.g., getAccountInfo)
  • Safe variants: Return a Result<T, E> type for explicit error handling (e.g., safeGetAccountInfo)
type Client = {
  // Throwable variants
  getAccountInfo: GetAccountInfo;
  getAccountAccessKey: GetAccountAccessKey;
  getAccountAccessKeys: GetAccountAccessKeys;
  callContractReadFunction: CallContractReadFunction;
  getBlock: GetBlock;
  getRecentBlockHash: GetRecentBlockHash;
  sendSignedTransaction: SendSignedTransaction;
  
  // Safe variants
  safeGetAccountInfo: SafeGetAccountInfo;
  safeGetAccountAccessKey: SafeGetAccountAccessKey;
  safeGetAccountAccessKeys: SafeGetAccountAccessKeys;
  safeCallContractReadFunction: SafeCallContractReadFunction;
  safeGetBlock: SafeGetBlock;
  safeGetRecentBlockHash: SafeGetRecentBlockHash;
  safeSendSignedTransaction: SafeSendSignedTransaction;
};

Creating a Client

Basic Client Creation

import { createClient } from '@near-api/client';

const client = createClient({
  transport: {
    rpcEndpoints: {
      archival: [{ url: 'https://rpc.testnet.near.org' }]
    }
  }
});

Using Preset Clients

For convenience, the library provides preset configurations for testnet and mainnet:
import { createTestnetClient, createMainnetClient } from '@near-api/client';

// Testnet client with default configuration
const testnetClient = createTestnetClient();

// Mainnet client with default configuration
const mainnetClient = createMainnetClient();

Safe Client Creation

import { safeCreateClient } from '@near-api/client';

const result = safeCreateClient({
  transport: {
    rpcEndpoints: {
      archival: [{ url: 'https://rpc.testnet.near.org' }]
    }
  }
});

if (result.ok) {
  const client = result.value;
  // Use client
} else {
  // Handle error
  console.error(result.error.kind);
}

Client Methods

Account Methods

Fetch account information including balance, storage usage, and code hash.
const accountInfo = await client.getAccountInfo({
  accountId: 'alice.near',
  atMomentOf: 'LatestFinalBlock'
});

console.log(accountInfo.balance); // Account balance in yoctoNEAR
console.log(accountInfo.storage_usage); // Storage used in bytes
Safe variant:
const result = await client.safeGetAccountInfo({
  accountId: 'alice.near'
});

if (!result.ok) {
  if (result.error.kind === 'Client.GetAccountInfo.Rpc.Account.NotFound') {
    console.log('Account does not exist');
  }
}

Contract Methods

callContractReadFunction

Call a read-only contract function (view call):
const result = await client.callContractReadFunction({
  contractAccountId: 'counter.near',
  functionName: 'get_count',
  atMomentOf: 'LatestFinalBlock'
});

console.log(result); // Function return value
With arguments:
const balance = await client.callContractReadFunction({
  contractAccountId: 'token.near',
  functionName: 'ft_balance_of',
  functionArgs: {
    account_id: 'alice.near'
  }
});
Custom serialization:
const result = await client.callContractReadFunction({
  contractAccountId: 'contract.near',
  functionName: 'custom_function',
  functionArgs: myCustomData,
  options: {
    serializeArgs: (args) => myCustomSerializer(args.functionArgs),
    deserializeResult: (result) => myCustomDeserializer(result)
  }
});

Block Methods

getBlock

Retrieve block information:
// Latest block
const latestBlock = await client.getBlock({
  blockReference: 'LatestFinalBlock'
});

// Specific block by height
const block = await client.getBlock({
  blockReference: { blockHeight: 12345678 }
});

// Specific block by hash
const block = await client.getBlock({
  blockReference: { blockHash: '...' }
});

getRecentBlockHash

Get a recent block hash for transaction creation:
const blockHash = await client.getRecentBlockHash();
The block hash is cached internally to reduce RPC calls when creating multiple transactions.

Transaction Methods

sendSignedTransaction

Submit a signed transaction to the network:
const result = await client.sendSignedTransaction({
  signedTransaction: mySignedTransaction
});

console.log(result.transaction_outcome.outcome.status);

Client Context

Internally, the Client maintains a context with shared resources:
type ClientContext = {
  sendRequest: SendRequest;  // Transport layer for RPC calls
  cache: Cache;              // Caches recent block hashes
};
The cache optimizes transaction creation by reducing redundant RPC calls for block hashes.

Error Handling

The Client implements comprehensive error types through the NatError system:
interface ClientPublicErrorRegistry {
  'CreateClient.Args.InvalidSchema': InvalidSchemaErrorContext;
  'CreateClient.Internal': InternalErrorContext;
  'Client.GetAccountInfo.Args.InvalidSchema': InvalidSchemaErrorContext;
  'Client.GetAccountInfo.Rpc.Account.NotFound': { accountId: string };
  'Client.GetAccountInfo.Rpc.Block.NotFound': { blockReference: BlockReference };
  // ... and many more
}

Using Safe Variants for Error Handling

const result = await client.safeGetAccountInfo({
  accountId: 'maybe-exists.near'
});

if (!result.ok) {
  switch (result.error.kind) {
    case 'Client.GetAccountInfo.Rpc.Account.NotFound':
      console.log('Account not found:', result.error.context.accountId);
      break;
    case 'Client.GetAccountInfo.Args.InvalidSchema':
      console.log('Invalid arguments:', result.error.context.zodError);
      break;
    default:
      console.log('Unknown error:', result.error.kind);
  }
}

Transport Configuration

The Client supports flexible transport configuration with policies:
const client = createClient({
  transport: {
    rpcEndpoints: {
      archival: [
        { url: 'https://rpc.mainnet.near.org' },
        { url: 'https://rpc.mainnet.internal.near.org' }
      ]
    },
    policy: {
      retries: 3,
      timeout: 10000,
      backoff: 'exponential'
    }
  }
});

Best Practices

Choose the Right Variant

  • Use throwable variants for rapid prototyping and simple scripts
  • Use safe variants in production code for explicit error handling
  • Mix both variants based on your error handling needs per use case

Reuse Client Instances

Create one client instance and reuse it throughout your application. The Client manages internal caching and connection pooling.

Handle Block References Carefully

Different block references have different guarantees:
  • LatestOptimisticBlock - Fastest, but may be rolled back
  • LatestNearFinalBlock - Balanced speed and finality
  • LatestFinalBlock - Slowest, but guaranteed finality