Skip to main content

Get Up and Running

This quickstart guide will walk you through installing NEAR API TypeScript and sending your first transaction on the NEAR testnet.
1

Install the Package

Install NEAR API TypeScript using your preferred package manager:
npm install near-api-ts
NEAR API TypeScript requires Node.js 24+ and Zod 4.3.0+. Zod is a peer dependency that you’ll need to install separately.
2

Create a Client

Import and create a client to connect to the NEAR testnet:
import { createTestnetClient } from 'near-api-ts';

const client = createTestnetClient();
The createTestnetClient() function creates a pre-configured client with testnet RPC endpoints and automatic failover.
3

Query Account Information

Use the client to read blockchain data:
const { accountInfo } = await client.getAccountInfo({
  accountId: 'testnet',
  atMomentOf: 'LatestFinalBlock',
});

console.log('Balance (NEAR):', accountInfo.balance.total.near);
console.log('Balance (yoctoNEAR):', accountInfo.balance.total.yoctoNear);
The library provides balance in both human-readable NEAR format and the native yoctoNEAR denomination.
4

Set Up Key Management

To send transactions, you need a key service and signer:
import { 
  createMemoryKeyService,
  createMemorySigner 
} from 'near-api-ts';

// Create a key service with your private key
const keyService = createMemoryKeyService({
  keySource: { privateKey: 'ed25519:your-private-key-here' },
});

// Create a signer
const signer = createMemorySigner({
  signerAccountId: 'your-account.testnet',
  client,
  keyService,
});
Never hardcode private keys in production code. Use environment variables or secure key management systems.
5

Send a Transaction

Send NEAR tokens using the transfer action:
import { transfer, near } from 'near-api-ts';

await signer.executeTransaction({
  intent: {
    action: transfer({ amount: near('1') }),
    receiverAccountId: 'receiver.testnet',
  },
});

console.log('Transfer successful!');
The near() helper converts NEAR tokens to yoctoNEAR automatically.
6

Handle Errors

Use type-safe error handling with isNatError:
import { isNatError } from 'near-api-ts';

try {
  await signer.executeTransaction({
    intent: {
      action: transfer({ amount: near('10000000000') }),
      receiverAccountId: 'receiver.testnet',
    },
  });
} catch (e) {
  if (isNatError(e, 'MemorySigner.ExecuteTransaction.Rpc.Transaction.Signer.Balance.TooLow')) {
    console.error('Insufficient balance');
    console.log('Transaction cost:', e.context.transactionCost);
  } else {
    throw e;
  }
}
The isNatError function provides type-safe error checking with IntelliSense support.
7

Use Safe Mode (Optional)

For functional error handling, use the safe variants:
const result = await client.safeGetBlock({
  blockReference: { blockHeight: 123456789 },
});

if (result.ok) {
  console.log('Block:', result.value.block);
} else {
  console.error('Error:', result.error.kind);
}
Safe variants return Result<T, E> objects instead of throwing errors.

Complete Example

Here’s a complete working example that puts it all together:
import {
  createTestnetClient,
  createMemoryKeyService,
  createMemorySigner,
  transfer,
  near,
  isNatError,
} from 'near-api-ts';

async function main() {
  // 1. Create a client
  const client = createTestnetClient();

  // 2. Query account info
  const { accountInfo } = await client.getAccountInfo({
    accountId: 'testnet',
    atMomentOf: 'LatestFinalBlock',
  });
  console.log('Testnet balance:', accountInfo.balance.total.near);

  // 3. Set up key service and signer
  const keyService = createMemoryKeyService({
    keySource: { 
      privateKey: process.env.NEAR_PRIVATE_KEY || 'ed25519:your-key-here' 
    },
  });

  const signer = createMemorySigner({
    signerAccountId: process.env.NEAR_ACCOUNT_ID || 'your-account.testnet',
    client,
    keyService,
  });

  // 4. Send a transfer
  try {
    await signer.executeTransaction({
      intent: {
        action: transfer({ amount: near('0.1') }),
        receiverAccountId: 'receiver.testnet',
      },
    });
    console.log('Transfer successful!');
  } catch (e) {
    if (isNatError(e, 'MemorySigner.ExecuteTransaction.Rpc.Transaction.Signer.Balance.TooLow')) {
      console.error('Insufficient balance for transfer');
    } else {
      throw e;
    }
  }
}

main().catch(console.error);

Next Steps

Best Practices

Never hardcode private keys in your source code. Always use environment variables or secure key management systems:
const keyService = createMemoryKeyService({
  keySource: { privateKey: process.env.NEAR_PRIVATE_KEY! },
});
Use createTestnetClient() for development and testing, and createMainnetClient() for production:
const client = process.env.NODE_ENV === 'production'
  ? createMainnetClient()
  : createTestnetClient();
Always wrap transaction calls in try-catch blocks and handle specific error types:
try {
  await signer.executeTransaction({ intent });
} catch (e) {
  if (isNatError(e, 'MemorySigner.ExecuteTransaction.Rpc.Transaction.Signer.Balance.TooLow')) {
    // Handle insufficient balance
  } else if (isNatError(e, 'MemorySigner.ExecuteTransaction.Rpc.Transaction.Receiver.Account.NotFound')) {
    // Handle receiver not found
  } else {
    throw e; // Re-throw unknown errors
  }
}