# FastNear JS monorepo (full)
Prefer https://js.fastnear.com/recipes.json when you need structured task data.
Concise map: https://js.fastnear.com/llms.txt
Version: 2.3.0 — all `@fastnear/*` packages share one version.
## Load it
- Browser: `` defines the `near` global; `` defines `nearWallet`.
- npm: `npm install @fastnear/api @fastnear/wallet`, then `import * as near from "@fastnear/api"`.
- Terminal: `node -e "$(curl -fsSL https://js.fastnear.com/agents.js)"` — no install.
## Packages
- `@fastnear/api`: low-level NEAR RPC and FastNear family APIs, plus `near.recipes` task helpers and `near.explain`
- `@fastnear/wallet`: wallet connection and transaction/signing provider
- `@fastnear/utils`: units, crypto, serialization, storage helpers
- `@fastnear/seed-phrase`: BIP-39 seed phrase generation and recovery, SLIP-0010 ed25519 derivation on NEAR's `m/44'/397'/0'` path
- `@fastnear/ml-dsa-65`: opt-in protocol-v85 ML-DSA-65 account-key generation, encoding, hashing, and transaction signing
- `@fastnear/x402`: official x402 v2 NEAR adapters for paid fetch, local-key clients, resource servers, and facilitators
- `@fastnear/intents`: NEAR Intents: 1Click quotes, NEP-413 intent signing, and verifier deposits/withdrawals
## Unified config
- `near.config({ networkId })`
- `near.config({ apiKey })`
- `near.config({ nodeUrl })`
- `near.config({ retry })`
- `near.config({ batch })`
## Resilience and bulk reads
`@fastnear/api` retries transient RPC failures (HTTP 408/429 and any 5xx, plus JSON-RPC `-429`/`-32000` — except deterministic `HANDLER_ERROR`s such as UNKNOWN_ACCOUNT, which fail fast) with full-jitter backoff, and exposes an explicit bulk read API. Both are configurable through `near.config` and are on by default.
**Retry** — `near.config({ retry })`:
- `enabled` (default `true`) — set `false` for a single attempt. The `timeoutMs` deadline stays armed either way.
- `maxAttempts` (`5`) — total attempts including the first.
- `baseBackoffMs` (`250`) / `maxBackoffMs` (`30000`) — full-jitter exponential backoff bounds.
- `timeoutMs` (`15000`) — per-attempt AbortController timeout (`0` disables it).
- `respectRetryAfter` (`true`) — honor a `Retry-After` header, capped at `maxBackoffMs`.
- `writePolicy` (`"transport-only"`) — how writes (`send_tx` / `broadcast_tx_*`) retry: `"never"`, `"transport-only"` (only pre-response transport/timeout errors, resending identical signed bytes — safe against double-apply), or `"all"`.
**Bulk reads** — concurrency-limited fan-out (NEAR RPC has no array batching, so calls are not merged into one request):
- `near.batch(requests)` — each `{ method, params, useArchival?, network? }` runs as its own retried call, at most `batch.maxConcurrency` (default `30`) in flight. Write methods are rejected per-item.
- `near.view.many(specs)` — the same fan-out for `{ contractId, methodName, args?, argsBase64?, blockId? }` view specs, decoding each ok result like `near.view`.
- `near.config({ batch: { maxConcurrency: 30 } })` tunes the in-flight cap.
Both return **settled** results in input order — one failing call never rejects the set:
```js
const results = await near.view.many([
{ contractId: "token.near", methodName: "ft_balance_of", args: { account_id: "a.near" } },
{ contractId: "token.near", methodName: "ft_balance_of", args: { account_id: "b.near" } },
]);
for (const r of results) {
if (r.status === "ok") near.print(r.result);
else if (r.kind === "contract") console.warn("contract reverted:", r.error);
else console.warn("infra error:", r.kind, r.error);
}
```
Each error item carries a `kind` — `"contract"` (the contract method reverted or failed), `"transport"` (no HTTP response: network or timeout), `"http"` (non-2xx), or `"rpc"` (JSON-RPC error) — so application failures stay distinguishable from infrastructure ones without re-parsing. Thrown errors are `FastNearRpcError` instances exposing the same `kind`, plus `status`, `code`, `data`, and `retryable`.
## Named endpoint types
- `FastNearRecipeDiscoveryEntry`
- `AccessKeyListResponse`
- `RpcStatusResponse`
- `SendTxParams`
- `FastNearApiV1AccountFullResponse`
- `FastNearApiV1AccountFtResponse`
- `FastNearApiV1AccountNftResponse`
- `FastNearApiV1AccountStakingResponse`
- `FastNearApiV1PublicKeyResponse`
- `FastNearApiV1PublicKeyAllResponse`
- `FastNearApiV1FtTopResponse`
- `FastNearTxTransactionsResponse`
- `FastNearTxReceiptResponse`
- `FastNearTxAccountResponse`
- `FastNearTxBlockResponse`
- `FastNearTxBlocksResponse`
- `FastNearTransfersQueryResponse`
- `FastNearNeardataLastBlockFinalResponse`
- `FastNearNeardataLastBlockOptimisticResponse`
- `FastNearNeardataBlockResponse`
- `FastNearNeardataBlockHeadersResponse`
- `FastNearNeardataBlockShardResponse`
- `FastNearNeardataBlockChunkResponse`
- `FastNearNeardataBlockOptimisticResponse`
- `FastNearNeardataFirstBlockResponse`
- `FastNearNeardataHealthResponse`
- `FastNearKvGetLatestKeyResponse`
- `FastNearKvGetHistoryKeyResponse`
- `FastNearKvLatestByAccountResponse`
- `FastNearKvHistoryByAccountResponse`
- `FastNearKvLatestByPredecessorResponse`
- `FastNearKvHistoryByPredecessorResponse`
- `FastNearKvAllByPredecessorResponse`
- `FastNearKvMultiResponse`
## Mental model
- Start with `near.view`, `near.queryAccount`, `near.tx.*`, `near.api.v1.*`, `near.transfers.*`, `near.neardata.*`, and `near.fastdata.kv.*` when you want exact control and raw family response shapes.
- Use `near.recipes.*` when you want the smallest task helper on top of those lower-level surfaces.
- Use `near.recipes.list()` or `near.recipes.toJSON()` when you want to discover the available task helpers at runtime.
## Family chooser
### rpc
Canonical NEAR JSON-RPC defaults for direct contract views, account state, and transaction status checks.
- Auth style: `query`
- Default base URLs: mainnet `https://rpc.mainnet.fastnear.com/`, testnet `https://rpc.testnet.fastnear.com/`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
- Best for:
- Direct contract view calls with exact method names and args.
- Canonical account state and access key reads.
- Low-level RPC questions before you need indexed or aggregated surfaces.
- Entrypoints:
- `near.view`
- `near.queryAccount`
- `near.queryAccessKey`
- `near.queryAccessKeyList`
- `near.queryProtocolVersion`
- `near.queryBlock`
- `near.queryTx`
- `near.gasPrice`
- `near.status`
- `near.validators`
- `near.sendTx`
- `near.ft.balance`
- `near.ft.metadata`
- `near.ft.totalSupply`
- `near.ft.storageBalance`
- `near.nft.metadata`
- `near.nft.token`
- `near.nft.forOwner`
- `near.nft.supplyForOwner`
- `near.nft.totalSupply`
- `near.nft.tokens`
### api
FastNear REST aggregations for account holdings, staking, and public-key oriented lookups.
- Auth style: `bearer`
- Default base URLs: mainnet `https://api.fastnear.com`, testnet `https://test.api.fastnear.com`
- Pagination: page_token; request fields: page_token; response fields: page_token; filters must stay stable: yes
- Best for:
- Combined account snapshots with fungible tokens, NFTs, and staking.
- Public-key-to-account discovery.
- Questions where one aggregated response is better than stitching multiple RPC calls.
- Entrypoints:
- `near.api.v1.accountFull`
- `near.api.v1.accountFt`
- `near.api.v1.accountNft`
- `near.api.v1.accountStaking`
- `near.api.v1.publicKey`
- `near.api.v1.publicKeyAll`
- `near.api.v1.ftTop`
- `near.ft.inventory`
- `near.nft.inventory`
### tx
Indexed transaction and receipt lookups for readable execution history by hash, account, or block.
- Auth style: `bearer`
- Default base URLs: mainnet `https://tx.main.fastnear.com`, testnet `https://tx.test.fastnear.com`
- Pagination: resume_token; request fields: resume_token; response fields: resume_token; filters must stay stable: yes
- Best for:
- Starting from one transaction hash or receipt id.
- Readable execution stories with receipts already joined in.
- Recent account or block-centered transaction history queries.
- Entrypoints:
- `near.tx.transactions`
- `near.tx.receipt`
- `near.tx.account`
- `near.tx.block`
- `near.tx.blocks`
### transfers
Asset-movement-focused history for accounts when the question is specifically about transfers, not full execution.
- Auth style: `bearer`
- Default base URLs: mainnet `https://transfers.main.fastnear.com`, testnet `null`
- Pagination: resume_token; request fields: resume_token; response fields: resume_token; filters must stay stable: yes
- Best for:
- Recent transfer feeds for one account.
- Asset movement summaries across FT, NFT, and native transfers.
- Survey scripting where transfer rows matter more than transaction internals.
- Entrypoints:
- `near.transfers.query`
### neardata
Block and shard documents for recent chain-state inspection without reconstructing shard layouts yourself.
- Auth style: `query`
- Default base URLs: mainnet `https://mainnet.neardata.xyz`, testnet `https://testnet.neardata.xyz`
- Pagination: range; request fields: blockHeight, from_block_height, to_block_height; response fields: none; filters must stay stable: no
- Best for:
- Recent block inspection and shard-aware exploration.
- Questions about network recency or recent transaction volume.
- Walking block-height ranges and chunk layouts.
- Entrypoints:
- `near.neardata.lastBlockFinal`
- `near.neardata.lastBlockOptimistic`
- `near.neardata.block`
- `near.neardata.blockHeaders`
- `near.neardata.blockShard`
- `near.neardata.blockChunk`
- `near.neardata.blockOptimistic`
- `near.neardata.firstBlock`
- `near.neardata.health`
### fastdata.kv
Indexed key-value history for exact keys, predecessor scans, and account-scoped storage exploration.
- Auth style: `bearer`
- Default base URLs: mainnet `https://kv.main.fastnear.com`, testnet `https://kv.test.fastnear.com`
- Pagination: resume_token; request fields: resume_token; response fields: resume_token; filters must stay stable: yes
- Best for:
- Exact-key lookups when you already know the contract, predecessor, and key.
- Storage history scans keyed by predecessor or current account.
- Questions about SocialDB-style writes and indexed storage history.
- Entrypoints:
- `near.fastdata.kv.getLatestKey`
- `near.fastdata.kv.getHistoryKey`
- `near.fastdata.kv.latestByAccount`
- `near.fastdata.kv.historyByAccount`
- `near.fastdata.kv.latestByPredecessor`
- `near.fastdata.kv.historyByPredecessor`
- `near.fastdata.kv.allByPredecessor`
- `near.fastdata.kv.multi`
### wallet
Browser wallet session and signing surface from @fastnear/wallet: connect, send transactions, sign NEP-413 messages, and sign NEP-366 delegate actions.
- Auth style: `wallet-session`
- Default base URLs: none — browser wallet session, not an HTTP service
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
- Best for:
- Anything that needs a user to approve a signature in their own wallet.
- Browser dApps where the key never leaves the wallet.
- Sign-in plus proof-of-ownership in a single prompt via signMessageParams.
- Entrypoints:
- `near.recipes.connect`
- `near.recipes.functionCall`
- `near.recipes.transfer`
- `near.recipes.signMessage`
- `nearWallet.connect`
- `nearWallet.disconnect`
- `nearWallet.restore`
- `nearWallet.sendTransaction`
- `nearWallet.sendTransactions`
- `nearWallet.signMessage`
- `nearWallet.signDelegateActions`
- `nearWallet.addFunctionCallKey`
## Result shapes
- `near.query*` (`queryAccount`, `queryBlock`, `queryAccessKey`, `queryTx`) are JSON-RPC passthroughs and return the raw envelope `{ jsonrpc, result, id }` — read your data from the `.result` field.
- `near.view`, `near.recipes.*`, `near.ft.*`, `near.nft.*` and the indexed REST families (`near.tx.*`, `near.api.v1.*`, `near.transfers.*`, `near.neardata.*`, `near.fastdata.kv.*`) return the flat data shape directly. The recipes layer in particular is what flattens `near.queryAccount` results into `{ amount, block_height, storage_usage, ... }` for `near.recipes.viewAccount`.
- **Wide integers.** What `@fastnear` **decodes** — `@fastnear/borsh` `deserialize`, `near.view`, `near.ft.*`, `near.utils.txToJson` — returns `u64`/`u128` as **decimal strings**. Results relayed straight from the RPC keep NEAR's own types, so yocto fields (`deposit`, `tokens_burnt`, `amount`) are strings while `gas_burnt` and access-key `nonce` are JSON numbers. Constructing a transaction accepts `string | number | bigint` and unit strings like `"100 Tgas"` / `"0.01 NEAR"`; inspect a built transaction with `near.utils.txToJson` rather than `JSON.stringify`-ing a raw `bigint`. You never need `BigInt` to build, send, or read a transaction. (`@fastnear/borsh` `deserialize` takes `{ bigints: "bigint" }` to opt back in.)
## Low-level API entrypoints
- `near.view`
- `near.view.many` (bulk views; settled results)
- `near.batch` (bulk RPC; settled results)
- `near.queryAccount`
- `near.queryAccessKey`
- `near.queryAccessKeyList`
- `near.queryProtocolVersion`
- `near.queryTx`
- `near.sendTx`
- `near.requestSignIn`
- `near.signMessage`
- `near.api.v1.accountFull` / `accountFt` / `accountNft` / `accountStaking` / `publicKey` / `publicKeyAll` / `ftTop`
- `near.tx.transactions` / `receipt` / `account` / `block` / `blocks`
- `near.transfers.query`
- `near.neardata.lastBlockFinal` / `lastBlockOptimistic` / `block` / `blockHeaders` / `blockShard` / `blockChunk` / `blockOptimistic` / `firstBlock` / `health`
- `near.fastdata.kv.getLatestKey` / `getHistoryKey` / `latestByAccount` / `historyByAccount` / `latestByPredecessor` / `historyByPredecessor` / `allByPredecessor` / `multi`
## Wallet entrypoints (`@fastnear/wallet`)
- `nearWallet.connect` / `disconnect` / `restore`: open, close, or rehydrate a session per network. `connect({ network, contractId, manifest })` is the canonical entrypoint; `contractId` mints a function-call key scoped to that contract so zero-deposit calls sign silently.
- `nearWallet.sendTransaction({ receiverId, actions, network })` / `sendTransactions`: dispatch one or many transactions through the connected wallet on the chosen network.
- `nearWallet.signMessage({ message, recipient, nonce, network })`: NEP-413 message signing.
- `nearWallet.signDelegateActions({ delegateActions, signerId?, network? })`: sign NEP-366 delegate actions for gasless relay-based flows. Each request may include `blockHeightTtl`; using it requires a wallet that advertises `signDelegateActionsWithTtl`. The canonical transport result is `{ borshSerializedBase64: string }`, while legacy structured and bare-base64 results remain accepted during the bridge transition.
- `nearWallet.addFunctionCallKey({ contractId, methodNames, allowance, network })` (`@fastnear/wallet@1.1.4+`): grant a second function-call key on another contract after sign-in, so a follow-on zero-deposit call to that contract also signs silently.
- `nearWallet.accountId` / `isConnected` / `connectedNetworks` / `switchNetwork`: per-network session inspection and the active-network cursor.
- `nearWallet.onConnect` / `onDisconnect`: subscribe to session lifecycle.
## Access and chaining
- API key env var: `FASTNEAR_API_KEY`
- Hosted recipe catalog: `https://js.fastnear.com/recipes.json`
- Hosted terminal wrapper: `https://js.fastnear.com/agents.js`
- Hosted topic explainers: `https://js.fastnear.com/transactions.html` (Constructing a transaction), `https://js.fastnear.com/meta-transactions.html` (Gasless meta-transactions), `https://js.fastnear.com/accounts.html` (Keys and accounts), `https://js.fastnear.com/x402.html` (x402 payments on NEAR), `https://js.fastnear.com/post-quantum.html` (Post-quantum ML-DSA-65 keys), `https://js.fastnear.com/retries.html` (Retries and bulk reads), `https://js.fastnear.com/intents.html` (NEAR Intents)
- Free trial credits: `https://dashboard.fastnear.com`
Set `FASTNEAR_API_KEY` before running the authenticated snippets.
### Discovery order
1. Read llms.txt — Start with the concise repo and runtime map.
2. Fetch recipes.json — Use the hosted machine-readable recipe catalog with stable IDs, families, auth, returns, and snippets.
3. Run agents.js — Use the hosted terminal wrapper when you want the FastNear JS surface.
4. Read llms-full.txt — Go here for the complete reference when the concise map is not enough.
5. Fall back to curl + jq — Use raw transport when survey scripting or HTTP-level inspection is more useful.
### Capture and chain one result
Keep the object work in JS, then hand the emitted JSON back to shell tooling when you need one more filter step. Every `near.recipes.*`, `near.view`, `near.ft.*`, and `near.nft.*` accepts a per-call `{ network: "testnet" }` override; see the `connect-testnet` and `function-call-testnet` recipes for the end-to-end testnet flow.
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
ACCOUNT_SUMMARY="$(node -e "$(curl -fsSL https://js.fastnear.com/agents.js)" <<'EOF'
const account = await near.recipes.viewAccount("root.near");
const { block_hash, storage_usage } = account;
near.print({ block_hash, storage_usage });
EOF
)"
BLOCK_HASH="$(printf '%s\n' "$ACCOUNT_SUMMARY" | jq -r '.block_hash')"
STORAGE_USAGE="$(printf '%s\n' "$ACCOUNT_SUMMARY" | jq -r '.storage_usage')"
printf 'block_hash=%s\nstorage_usage=%s\n' "$BLOCK_HASH" "$STORAGE_USAGE"
```
## x402 payments on NEAR
`@fastnear/x402` adapts the official x402 Foundation NEAR mechanism without introducing another wire format.
- Protocol: x402 v2 `exact` on `near:mainnet` and `near:testnet`.
- Authorization: NEP-366 SignedDelegate; asset: NEP-141 fungible tokens.
- Browser global: `nearX402`.
- Runtime: Package-only; not included in agents.js or near.js.
- Browser status: Stable with tested Meteor Wallet support; other wallets must advertise both timeout-aware delegate-signing capabilities and pass the x402 testnet harness before being documented as compatible.
- Required wallet features: `signDelegateActions` and `signDelegateActionsWithTtl`.
- Package guide: [https://github.com/fastnear/js-monorepo/blob/main/packages/x402/README.md](https://github.com/fastnear/js-monorepo/blob/main/packages/x402/README.md).
### Choose by task
- Pay an x402 URL from Node.js: `createLocalNearSigner` + `createNearPaymentFetch` from `@fastnear/x402/node` and `@fastnear/x402` — stable.
- Pay an x402 URL from a browser wallet: `createFastNearWalletSigner` + `createNearPaymentFetch` from `@fastnear/wallet` and `@fastnear/x402` — stable with a compatible timeout-aware wallet; Meteor Wallet is the tested production path.
- Protect a seller resource: `createNearResourceServer` from `@fastnear/x402/server` — requires an explicit facilitator.
- Operate a NEAR facilitator: `createNearFacilitator` from `@fastnear/x402/facilitator` — HTTP framework and secret storage are operator choices.
- Integrate below the paid-fetch helper: `createNearX402Client` from `@fastnear/x402` — lower-level client path.
### Entrypoints
- `@fastnear/x402`: `createFastNearWalletSigner`, `createNearX402Client`, `createNearPaymentFetch` — injected FastNEAR wallet signer, NEAR-only x402 client, and paid fetch.
- `@fastnear/x402/node`: `createLocalNearSigner` — official RPC-backed local full-access-key signer.
- `@fastnear/x402/server`: `createNearResourceServer` — resource server with one or more explicitly configured facilitators.
- `@fastnear/x402/facilitator`: `createNearFacilitator` — self-hosted facilitator registration for concrete NEAR networks.
### Constraints
- Only x402 v2 exact payments on near:mainnet and near:testnet are supported.
- Payments use NEP-141 tokens; native NEAR is not a direct payment asset.
- Wallet and local-key payers require full-access keys, and recipients need token storage registration.
- Resource servers require an explicit facilitator; no x402.org or other default is selected.
- Browser wallet access is injected explicitly and payment occurs only when the application calls the paid fetch function.
### Safe defaults
- Pin near:testnet during development and a concrete NEAR network in production; use near:* only for an intentionally cross-network client.
- Keep payer and relayer secret keys in server-side secret storage, never browser code.
- String and number seller prices use the official USDC contract; wNEAR and custom tokens require an explicit { amount, asset } price.
- Always configure a facilitator explicitly.
### Pay an x402 URL from Node.js
Quickstart ID: `x402-node-paid-fetch`
Use the upstream local full-access-key signer with the high-level paid-fetch helper.
```js
import { createNearPaymentFetch } from "@fastnear/x402";
import { createLocalNearSigner } from "@fastnear/x402/node";
const { NEAR_PAYER_ACCOUNT_ID, NEAR_PAYER_SECRET_KEY, X402_RESOURCE_URL } = process.env;
if (!NEAR_PAYER_ACCOUNT_ID || !NEAR_PAYER_SECRET_KEY || !X402_RESOURCE_URL) {
throw new Error("NEAR_PAYER_ACCOUNT_ID, NEAR_PAYER_SECRET_KEY, and X402_RESOURCE_URL are required");
}
const signer = createLocalNearSigner({
accountId: NEAR_PAYER_ACCOUNT_ID,
secretKey: NEAR_PAYER_SECRET_KEY,
rpcUrls: { "near:testnet": "https://rpc.testnet.fastnear.com" },
});
const paidFetch = createNearPaymentFetch({ signer, network: "near:testnet" });
const response = await paidFetch(X402_RESOURCE_URL);
if (!response.ok) throw new Error(`Paid request failed: ${response.status}`);
console.log(await response.json());
```
### Configure a seller with an explicit remote facilitator
Quickstart ID: `x402-remote-facilitator-seller`
Create the NEAR resource-server core, then pass it to the x402 HTTP framework adapter you choose.
```js
import { createNearResourceServer } from "@fastnear/x402/server";
const { X402_FACILITATOR_URL } = process.env;
if (!X402_FACILITATOR_URL) throw new Error("X402_FACILITATOR_URL is required");
export const resourceServer = createNearResourceServer({
facilitators: { url: X402_FACILITATOR_URL },
});
await resourceServer.initialize();
```
## ML-DSA-65 account-key quickstarts
The opt-in `@fastnear/ml-dsa-65` package provides protocol-v85 account access keys and transaction signatures without pulling the post-quantum backend into `@fastnear/api` or `@fastnear/utils`.
- Runtime: Node.js 20.19+ or a modern browser.
- Scope: NEAR account access keys and transaction signatures only; validator and staking keys remain Ed25519.
- Exact byte lengths: seed 32, public key 1952, expanded secret key 4032, signature 3309.
- Verification charge: 100 Ggas (100000000000 gas) for each outer or delegated ML-DSA-65 signature verification.
- Full key: `ml-dsa-65:`; list handle: `ml-dsa-65-hash:`.
- Handle derivation: SHA3-256 of the ASCII domain tag followed by the raw 1,952-byte public key; domain tag `near:ml-dsa-65-pubkey-hash:v1`.
Use the full public key for AddKey, direct access-key lookup, signing, and DeleteKey. Access-key list responses expose the compact handle; derive it with publicKeyToHandle() before comparing.
### Safety constraints
- Check the selected RPC's active protocol_version and require 85 or later before adding or using an ML-DSA-65 key; do not use node software versions or latest_protocol_version as activation signals.
- Never print or persist generated seeds or expanded secret keys. Keep a temporary recovery record public-only: network, account ID, full public key, and hash handle.
- Public keys, secret keys, and signatures all use the same ml-dsa-65: string prefix, so signer.exportSecretKey() is indistinguishable by shape from signer.publicKey. Distinguish them by decoded byte length (1,952 vs 4,032), never by prefix, and never let a secret reach a log line or a recovery record.
- After an AddKey attempt, do not trust a single absence read: submit a finalized classical DeleteKey nonce barrier, confirm absence at finality, and only then remove the public recovery record.
- ML-DSA-65 public keys are 1,952 bytes and signatures are 3,309 bytes, so transactions and key-management actions are substantially larger than classical equivalents.
- NEAR charges 100 Ggas (100,000,000,000 gas) for each outer or delegated ML-DSA-65 signature verification.
- The selected @noble/post-quantum backend describes itself as self-audited and does not claim constant-time side-channel protection. Prefer a native, WASM, HSM, or hardware TransactionSigner when that threat model requires one.
- destroy() provides best-effort zeroization of package-owned JavaScript buffers, not a hard memory-erasure guarantee. Constrained QuickJS and MCU runtimes are not a v1 compatibility target.
### Generate an in-memory ML-DSA-65 signer
Recipe ID: `ml-dsa-65-generate`
Generate the opt-in signer, retain only public recovery metadata, and always destroy the signer when its lifecycle ends.
```js
import { generateSigner } from "@fastnear/ml-dsa-65";
const signer = generateSigner();
try {
// Public values are safe to retain for enrollment and cleanup.
const recovery = {
network: "testnet",
accountId: "device.testnet",
publicKey: signer.publicKey,
publicKeyHandle: signer.publicKeyHandle,
};
console.log(recovery);
// Never log or persist signer.exportSeed() or signer.exportSecretKey().
} finally {
signer.destroy();
}
```
### Enroll an ML-DSA-65 public key with a classical AddKey
Recipe ID: `ml-dsa-65-enroll`
Add the signer's full public key to the account using an existing classical full-access key. Enrollment always starts from a classical signer; an ML-DSA-65 key cannot add itself.
```js
import {
actions,
queryAccessKey,
queryProtocolVersion,
sendTx,
} from "@fastnear/api";
import { signerFromPrivateKey } from "@fastnear/utils";
export async function enrollMlDsa65Key({ accountId, classicalPrivateKey, signer }) {
const protocolVersion = await queryProtocolVersion({ network: "testnet" });
if (protocolVersion < 85) {
throw new Error(`testnet protocol ${protocolVersion} does not support ML-DSA-65`);
}
// The AddKey itself is signed by an existing classical full-access key.
const classicalSigner = signerFromPrivateKey(classicalPrivateKey);
await sendTx({
signerId: accountId,
signer: classicalSigner,
receiverId: accountId,
// Pass the full ml-dsa-65: key. Never the ml-dsa-65-hash: handle.
actions: [actions.addFullAccessKey({ publicKey: signer.publicKey })],
waitUntil: "FINAL",
network: "testnet",
});
// Read back with the full key: direct access-key lookup accepts it, while
// access-key list responses expose only signer.publicKeyHandle.
return queryAccessKey({
accountId,
publicKey: signer.publicKey,
blockId: "final",
network: "testnet",
});
}
```
### Send with an enrolled ML-DSA-65 signer
Recipe ID: `ml-dsa-65-explicit-send`
Use the explicit-signer branch of sendTx after the signer's full public key has been enrolled on the account.
```js
import {
actions,
queryProtocolVersion,
sendTx,
} from "@fastnear/api";
export async function sendOneYoctoWithMlDsa65({ accountId, signer }) {
const protocolVersion = await queryProtocolVersion({ network: "testnet" });
if (protocolVersion < 85) {
throw new Error(`testnet protocol ${protocolVersion} does not support ML-DSA-65`);
}
return sendTx({
signerId: accountId,
signer,
receiverId: accountId,
actions: [actions.transfer("1")],
waitUntil: "FINAL",
network: "testnet",
});
}
```
### Enroll and delete a temporary testnet key
Recipe ID: `ml-dsa-65-enroll-delete`
Persist public-only recovery metadata, use an authorized classical full-access signer for both mutations, and establish finalized deletion before removing the record.
```js
import {
actions,
queryAccessKeyList,
queryProtocolVersion,
sendTx,
} from "@fastnear/api";
import {
generateSigner,
} from "@fastnear/ml-dsa-65";
export async function withTemporaryMlDsa65Key({
accountId,
classicalSigner,
run,
saveRecovery,
removeRecovery,
}) {
if (!accountId.endsWith(".testnet")) {
throw new Error("This safety-oriented recipe is testnet-only");
}
const protocolVersion = await queryProtocolVersion({ network: "testnet" });
if (protocolVersion < 85) {
throw new Error(`testnet protocol ${protocolVersion} does not support ML-DSA-65`);
}
const signer = generateSigner();
const publicRecovery = {
network: "testnet",
accountId,
publicKey: signer.publicKey,
publicKeyHandle: signer.publicKeyHandle,
};
let addAttempted = false;
async function deleteWithFinalizedBarrier() {
let lastError;
for (let attempt = 1; attempt <= 3; attempt += 1) {
try {
// Submit even when one read says the key is absent. A finalized
// classical transaction prevents an ambiguous earlier AddKey from
// landing later with the same or a lower nonce.
await sendTx({
signerId: accountId,
signer: classicalSigner,
receiverId: accountId,
actions: [actions.deleteKey({ publicKey: signer.publicKey })],
waitUntil: "FINAL",
network: "testnet",
});
const list = await queryAccessKeyList({
accountId,
blockId: "final",
network: "testnet",
});
const stillPresent = list.result.keys.some(
(entry) => entry.public_key === publicRecovery.publicKeyHandle,
);
if (!stillPresent) return;
lastError = new Error("ML-DSA-65 key remains after finalized deletion");
} catch (error) {
lastError = error;
}
}
throw lastError ?? new Error("Could not establish ML-DSA-65 key absence");
}
try {
// Implement these callbacks with durable application storage. On Node,
// create the public-only file with mode 0600. Never include secret bytes.
await saveRecovery(publicRecovery);
addAttempted = true;
await sendTx({
signerId: accountId,
signer: classicalSigner,
receiverId: accountId,
actions: [actions.addFullAccessKey({ publicKey: signer.publicKey })],
waitUntil: "FINAL",
network: "testnet",
});
return await run(signer);
} finally {
try {
if (addAttempted) {
await deleteWithFinalizedBarrier();
await removeRecovery(publicRecovery);
}
} finally {
signer.destroy();
}
}
}
```
### Reconcile a full key with its access-key-list handle
Recipe ID: `ml-dsa-65-reconcile`
Query the full key directly, then match its locally derived hash handle against the compact list response.
```js
import {
queryAccessKey,
queryAccessKeyList,
} from "@fastnear/api";
import { publicKeyToHandle } from "@fastnear/ml-dsa-65";
export async function findMlDsa65AccessKey({ accountId, publicKey }) {
const [direct, list] = await Promise.all([
queryAccessKey({ accountId, publicKey, network: "testnet" }),
queryAccessKeyList({ accountId, network: "testnet" }),
]);
const publicKeyHandle = publicKeyToHandle(publicKey);
const listed = list.result.keys.find(
(entry) => entry.public_key === publicKeyHandle,
);
return { direct: direct.result, publicKeyHandle, listed };
}
```
## NEAR Intents
`@fastnear/intents` integrates the NEAR Intents protocol: the intents.near verifier, the hosted 1Click swap API, and the solver relay.
- Verifier: `intents.near` (mainnet); ledger: NEP-245 multi-token; token ids nep141:, nep171::, nep245::.
- Signing: NEP-413 signed messages (full-access keys only); the verifier also accepts erc191, tip191, raw_ed25519, webauthn, ton_connect, and sep53 payloads.
- 1Click API: `https://1click.chaindefuser.com`; solver relay: `https://solver-relay-v2.chaindefuser.com/rpc`.
- Browser global: `nearIntents`.
- Runtime: Package-only; not included in agents.js or near.js.
- Wallet status: The wallet signing path uses nearWallet.signMessage (NEP-413), which every near-connect executor implements; the funded end-to-end swap path is verified by the mainnet smoke runbook before being documented further.
- Package guide: [https://github.com/fastnear/js-monorepo/blob/main/packages/intents/README.md](https://github.com/fastnear/js-monorepo/blob/main/packages/intents/README.md).
### Choose by task
- Quote and track a swap: `createOneClickClient` from `@fastnear/intents` — stable; keyless use adds a 0.2% platform fee to quotes.
- Sign intents from a browser wallet: `createWalletIntentSigner` from `@fastnear/wallet` and `@fastnear/intents` — NEP-413 via the connected wallet's full-access key; FunctionCall session keys cannot sign intents.
- Sign intents from Node.js or an agent: `createLocalIntentSigner` from `@fastnear/intents/node` — raw full-access key, server-side only.
- Deposit, check balances, withdraw on the verifier: `ftDepositAction` + `wrapNearAction` + `mtBatchBalances` + `ftWithdrawAction` from `@fastnear/intents` and `@fastnear/api` — action builders for near.sendTx plus NEP-245 views over injected near.view.
- Talk to the solver relay directly: `createSolverRelayClient` from `@fastnear/intents/relay` — quotes require a partner API key in practice; the 1Click path is the default.
### Entrypoints
- `@fastnear/intents`: `createOneClickClient`, `createWalletIntentSigner`, `createSolverRelayClient`, `ftDepositAction`, `wrapNearAction`, `ftWithdrawAction`, `mtBalance`, `mtBatchBalances`, `toSignedIntent`, `randomNonce` — browser-safe 1Click client, wallet intent signer, verifier helpers, and relay client.
- `@fastnear/intents/relay`: `createSolverRelayClient` — solver-relay JSON-RPC client (quote, publish_intent, publish_intents, get_status).
- `@fastnear/intents/node`: `createLocalIntentSigner` — local full-access-key NEP-413 intent signer for servers and agents.
### Constraints
- The verifier is intents.near on NEAR mainnet; there is no public testnet deployment of the intents stack.
- NEP-413 intent signatures require a full-access key, and the verifier checks the key is authorized for signer_id.
- Submitted signatures use ed25519: encoding — not the base64 NEAR wallets return; the signers own that conversion.
- Native NEAR is not a verifier asset: wrap to wNEAR before depositing, and exit native NEAR only via the native_withdraw intent.
- Amounts are base-unit strings, and token_diff diffs must net to zero per token across the executed batch.
### Safe defaults
- Quote with dry:true first; commit with dry:false only when ready to fund the deposit address before it expires.
- Keep local signer private keys in server-side secret storage, never browser code.
- Use a partner API key from partners.near-intents.org to remove the 0.2% keyless platform fee.
- Poll /v0/status to a terminal state (SUCCESS, REFUNDED, FAILED) and surface swapDetails on non-success.
- Omit msg on ft_withdraw so failed withdrawals stay refundable.
### Quote a swap and read live pricing
Quickstart ID: `intents-one-click-quote`
Discover assets and price a swap with a free dry-run quote — no auth, no funds, no commitment.
```js
import { createOneClickClient } from "@fastnear/intents";
const oneClick = createOneClickClient();
const tokens = await oneClick.tokens();
const quote = await oneClick.quote({
dry: true,
swapType: "EXACT_INPUT",
slippageTolerance: 100,
originAsset: "nep141:wrap.near",
destinationAsset: "nep141:17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1",
amount: "1000000000000000000000000",
depositType: "ORIGIN_CHAIN",
refundTo: "you.near",
refundType: "ORIGIN_CHAIN",
recipient: "you.near",
recipientType: "DESTINATION_CHAIN",
deadline: new Date(Date.now() + 10 * 60_000).toISOString(),
});
console.log(quote.quote.amountOutFormatted);
```
### Sign a token_diff intent with a browser wallet
Quickstart ID: `intents-wallet-sign`
NEP-413 through the connected wallet, re-encoded to the MultiPayload the verifier accepts.
```js
import { createWalletIntentSigner } from "@fastnear/intents";
// window.nearWallet from https://js.fastnear.com/wallet.js, already connected.
const signer = createWalletIntentSigner({ wallet: nearWallet });
const signed = await signer.signIntents({
intents: [{
intent: "token_diff",
diff: {
"nep141:usdc.near": "-1000000",
"nep141:usdt.near": "1000000",
},
}],
});
// signed = { standard: "nep413", payload, public_key, signature } — submit via
// oneClick.submitIntent, relay.publishIntent, or intents.near execute_intents.
```
### Swap intents.near balances from Node.js
Quickstart ID: `intents-node-swap`
The INTENTS deposit type: 1Click builds the payload, the local signer signs it verbatim, no deposit transaction needed.
```js
import { createOneClickClient } from "@fastnear/intents";
import { createLocalIntentSigner } from "@fastnear/intents/node";
const { NEAR_ACCOUNT_ID, NEAR_PRIVATE_KEY } = process.env;
const oneClick = createOneClickClient();
const signer = createLocalIntentSigner({
accountId: NEAR_ACCOUNT_ID,
privateKey: NEAR_PRIVATE_KEY, // full-access, server-side only
});
// Quote with depositType/refundType/recipientType "INTENTS" — the input
// funds already sit inside intents.near, so no deposit transaction is needed.
const quote = await oneClick.quote({
dry: false,
swapType: "EXACT_INPUT",
slippageTolerance: 100,
originAsset: "nep141:wrap.near",
destinationAsset: "nep141:17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1",
amount: "1000000000000000000000000",
depositType: "INTENTS",
refundTo: NEAR_ACCOUNT_ID,
refundType: "INTENTS",
recipient: NEAR_ACCOUNT_ID,
recipientType: "INTENTS",
deadline: new Date(Date.now() + 10 * 60_000).toISOString(),
});
const { intent } = await oneClick.generateIntent({
signerId: NEAR_ACCOUNT_ID,
depositAddress: quote.quote.depositAddress,
});
// signPayload pins the recipient to intents.near and signs verbatim.
const signed = await signer.signPayload(intent);
const { intentHash } = await oneClick.submitIntent({ signedData: signed });
console.log(intentHash);
```
### Deposit wNEAR and read verifier balances
Quickstart ID: `intents-deposit-balances`
Action builders for near.sendTx plus NEP-245 ledger views over the injected near.view.
```js
import { ftDepositAction, wrapNearAction, mtBatchBalances } from "@fastnear/intents";
await near.sendTx({
receiverId: "wrap.near",
actions: [wrapNearAction({ amountYocto: "1000000000000000000000000" })],
});
await near.sendTx({
receiverId: "wrap.near",
actions: [ftDepositAction({ amount: "1000000000000000000000000" })],
});
const balances = await mtBatchBalances({
accountId: near.accountId(),
tokenIds: ["nep141:wrap.near"],
view: near.view,
});
near.print(balances);
```
## Recipe catalog
## What does this contract method return?
- ID: `view-contract`
- API: `near.recipes.viewContract`
- Service: `rpc`
- Returns: `BerryClubAccountView`
- Network: `mainnet`
- Auth: `none`
- Summary: Start with one view call when you already know the contract, method, and arguments.
- Output keys: `account_id`, `avocado_balance`, `num_pixels`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this when you already know the exact contract method and want the smallest answer quickly.
- Stay on RPC when the question is still about one direct view call rather than indexed history.
Response notes:
- This recipe returns the parsed JSON value from the contract method, not the raw RPC wrapper.
- Use the curl + jq variant when you want to inspect the encoded args or the raw RPC envelope.
Follow-ups:
- If the method output looks wrong, compare it with the canonical account state from near.recipes.viewAccount.
- If you need a broader ownership snapshot, move to near.api.v1.accountFull.
Related recipes:
- `view-account`
- `account-full`
Example inputs:
```json
{
"contractId": "berryclub.ek.near",
"methodName": "get_account",
"args": {
"account_id": "root.near"
}
}
```
### Terminal
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
node -e "$(curl -fsSL https://js.fastnear.com/agents.js)" <<'EOF'
const result = await near.recipes.viewContract({
contractId: "berryclub.ek.near",
methodName: "get_account",
args: { account_id: "root.near" },
});
near.print({
account_id: result.account_id,
avocado_balance: result.avocado_balance,
num_pixels: result.num_pixels,
});
EOF
```
### curl + jq
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
ACCOUNT_ID=root.near
ARGS_BASE64="$(jq -nc --arg account_id "$ACCOUNT_ID" '{account_id: $account_id}' | base64 | tr -d '\n')"
curl -sS "https://rpc.mainnet.fastnear.com?apiKey=$FASTNEAR_API_KEY" -H 'content-type: application/json' --data "$(jq -nc --arg args "$ARGS_BASE64" '{
jsonrpc:"2.0",id:"fastnear",method:"query",
params:{
request_type:"call_function",
finality:"final",
account_id:"berryclub.ek.near",
method_name:"get_account",
args_base64:$args
}
}')" | jq '.result.result | implode | fromjson | {account_id, avocado_balance, num_pixels}'
```
### Browser Global
```js
const result = await near.recipes.viewContract({
contractId: "berryclub.ek.near",
methodName: "get_account",
args: { account_id: "root.near" },
});
near.print({
account_id: result.account_id,
avocado_balance: result.avocado_balance,
num_pixels: result.num_pixels,
});
```
### ESM
```js
import * as near from "@fastnear/api";
near.config({ apiKey: process.env.FASTNEAR_API_KEY || undefined });
const result = await near.recipes.viewContract({
contractId: "berryclub.ek.near",
methodName: "get_account",
args: { account_id: "root.near" },
});
near.print({
account_id: result.account_id,
avocado_balance: result.avocado_balance,
num_pixels: result.num_pixels,
});
```
## What does this account look like on chain?
- ID: `view-account`
- API: `near.recipes.viewAccount`
- Service: `rpc`
- Returns: `RpcViewAccountResponse`
- Network: `mainnet`
- Auth: `none`
- Summary: Use canonical RPC account state when the question is still about one account record.
- Output keys: `amount`, `locked`, `storage_usage`, `block_height`, `block_hash`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this when the question is about one account's chain state rather than token holdings or transfers.
- Use this before reaching for aggregations if you need the raw account state answer first.
Response notes:
- This is the canonical on-chain account record from JSON-RPC.
- The snippet keeps the object work in JS and emits only the fields most useful for survey scripting.
Follow-ups:
- If the account is active but you need holdings, switch to near.api.v1.accountFull.
- If you need recent transfer activity, continue with near.transfers.query.
Related recipes:
- `account-full`
- `transfers-query`
Example inputs:
```json
{
"accountId": "root.near"
}
```
### Terminal
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
node -e "$(curl -fsSL https://js.fastnear.com/agents.js)" <<'EOF'
const account = await near.recipes.viewAccount("root.near");
const { amount, locked, storage_usage, block_height, block_hash } = account;
near.print({
amount,
locked,
storage_usage,
block_height,
block_hash,
});
EOF
```
### curl + jq
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
ACCOUNT_ID=root.near
curl -sS "https://rpc.mainnet.fastnear.com?apiKey=$FASTNEAR_API_KEY" -H 'content-type: application/json' --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{
jsonrpc:"2.0",id:"fastnear",method:"query",
params:{request_type:"view_account",account_id:$account_id,finality:"final"}
}')" | jq '.result | {amount, locked, storage_usage, block_height, block_hash}'
```
### Browser Global
```js
const account = await near.recipes.viewAccount("root.near");
const { amount, locked, storage_usage, block_height, block_hash } = account;
near.print({
amount,
locked,
storage_usage,
block_height,
block_hash,
});
```
### ESM
```js
import * as near from "@fastnear/api";
near.config({ apiKey: process.env.FASTNEAR_API_KEY || undefined });
const account = await near.recipes.viewAccount("root.near");
const { amount, locked, storage_usage, block_height, block_hash } = account;
near.print({
amount,
locked,
storage_usage,
block_height,
block_hash,
});
```
## What happened in this transaction?
- ID: `inspect-transaction`
- API: `near.tx.transactions`
- Service: `tx`
- Returns: `FastNearTxTransactionsResponse`
- Network: `mainnet`
- Auth: `none`
- Summary: Start with the indexed transaction family when all you have is the hash and you want the readable story.
- Output keys: `transactions[].transaction.hash`, `transactions[].transaction.signer_id`, `transactions[].transaction.receiver_id`, `transactions[].execution_outcome.block_height`, `transactions[].receipts`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this when the only durable identifier you have is the transaction hash.
- Prefer this over transfers when you need the execution story, receipts, or included block details.
Response notes:
- The low-level tx family returns raw indexed JSON with receipts already attached.
- This recipe narrows that response to the one transaction row and prints a compact human-readable summary.
Follow-ups:
- If you care only about asset movement, pivot to near.transfers.query.
- If you need a block-centered history scan, continue with near.tx.account or near.tx.blocks.
Related recipes:
- `transfers-query`
- `last-block-final`
Example inputs:
```json
{
"txHashes": [
"7ZKnhzt2MqMNmsk13dV8GAjGu3Db8aHzSBHeNeu9MJCq"
]
}
```
### Terminal
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
node -e "$(curl -fsSL https://js.fastnear.com/agents.js)" <<'EOF'
const tx = await near.recipes.inspectTransaction(
"7ZKnhzt2MqMNmsk13dV8GAjGu3Db8aHzSBHeNeu9MJCq"
);
near.print(
tx
? {
hash: tx.transaction.hash,
signer_id: tx.transaction.signer_id,
receiver_id: tx.transaction.receiver_id,
included_block_height: tx.execution_outcome.block_height,
receipt_count: tx.receipts.length,
}
: null
);
EOF
```
### curl + jq
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
TX_HASH=7ZKnhzt2MqMNmsk13dV8GAjGu3Db8aHzSBHeNeu9MJCq
curl -sS "https://tx.main.fastnear.com/v0/transactions" -H "Authorization: Bearer $FASTNEAR_API_KEY" -H 'content-type: application/json' --data "$(jq -nc --arg tx_hash "$TX_HASH" '{tx_hashes: [$tx_hash]}')" | jq '{
hash: .transactions[0].transaction.hash,
signer_id: .transactions[0].transaction.signer_id,
receiver_id: .transactions[0].transaction.receiver_id,
included_block_height: .transactions[0].execution_outcome.block_height,
receipt_count: (.transactions[0].receipts | length)
}'
```
### Browser Global
```js
const tx = await near.recipes.inspectTransaction(
"7ZKnhzt2MqMNmsk13dV8GAjGu3Db8aHzSBHeNeu9MJCq"
);
near.print(
tx
? {
hash: tx.transaction.hash,
signer_id: tx.transaction.signer_id,
receiver_id: tx.transaction.receiver_id,
included_block_height: tx.execution_outcome.block_height,
receipt_count: tx.receipts.length,
}
: null
);
```
### ESM
```js
import * as near from "@fastnear/api";
near.config({ apiKey: process.env.FASTNEAR_API_KEY || undefined });
const tx = await near.recipes.inspectTransaction(
"7ZKnhzt2MqMNmsk13dV8GAjGu3Db8aHzSBHeNeu9MJCq"
);
near.print(
tx
? {
hash: tx.transaction.hash,
signer_id: tx.transaction.signer_id,
receiver_id: tx.transaction.receiver_id,
included_block_height: tx.execution_outcome.block_height,
receipt_count: tx.receipts.length,
}
: null
);
```
## What does this account own?
- ID: `account-full`
- API: `near.api.v1.accountFull`
- Service: `api`
- Returns: `FastNearApiV1AccountFullResponse`
- Network: `mainnet`
- Auth: `none`
- Summary: Use the FastNear account aggregator when the question is about holdings, NFTs, or staking in one response.
- Output keys: `account_id`, `state.balance`, `tokens`, `nfts`, `pools`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this when you want holdings, NFTs, and staking without stitching multiple calls together.
- Use it after a canonical RPC account check when the next question becomes 'what does this account own?'.
Response notes:
- This is the aggregated account surface for holdings and staking, not a raw RPC account object.
- It is the best one-response answer when the task is portfolio-style discovery.
Follow-ups:
- If you need movement history instead of holdings, continue with near.transfers.query.
- If you need one exact contract state read, go back to near.recipes.viewContract.
Related recipes:
- `view-account`
- `transfers-query`
Example inputs:
```json
{
"accountId": "root.near"
}
```
### Terminal
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
node -e "$(curl -fsSL https://js.fastnear.com/agents.js)" <<'EOF'
const account = await near.api.v1.accountFull({
accountId: "root.near",
});
near.print({
account_id: account.account_id,
near_balance_yocto: account.state.balance,
ft_contracts: account.tokens.length,
nft_contracts: account.nfts.length,
staking_pool_contracts: account.pools.length,
});
EOF
```
### curl + jq
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
ACCOUNT_ID=root.near
curl -sS "https://api.fastnear.com/v1/account/$ACCOUNT_ID/full" -H "Authorization: Bearer $FASTNEAR_API_KEY" | jq '{
account_id,
near_balance_yocto: .state.balance,
ft_contracts: (.tokens | length),
nft_contracts: (.nfts | length),
staking_pool_contracts: (.pools | length)
}'
```
### Browser Global
```js
const account = await near.api.v1.accountFull({
accountId: "root.near",
});
near.print({
account_id: account.account_id,
near_balance_yocto: account.state.balance,
ft_contracts: account.tokens.length,
nft_contracts: account.nfts.length,
staking_pool_contracts: account.pools.length,
});
```
### ESM
```js
import * as near from "@fastnear/api";
near.config({ apiKey: process.env.FASTNEAR_API_KEY || undefined });
const account = await near.api.v1.accountFull({
accountId: "root.near",
});
near.print({
account_id: account.account_id,
near_balance_yocto: account.state.balance,
ft_contracts: account.tokens.length,
nft_contracts: account.nfts.length,
staking_pool_contracts: account.pools.length,
});
```
## What is this account's recent transfer activity?
- ID: `transfers-query`
- API: `near.transfers.query`
- Service: `transfers`
- Returns: `FastNearTransfersQueryResponse`
- Network: `mainnet`
- Auth: `none`
- Summary: Use the transfers family when the question is specifically about asset movement, not the broader execution story.
- Output keys: `transfers[].block_height`, `transfers[].asset_id`, `transfers[].human_amount`, `transfers[].other_account_id`, `transfers[].transaction_id`, `resume_token`
- Pagination: resume_token; request fields: resume_token; response fields: resume_token; filters must stay stable: yes
Choose this when:
- Choose this when the question is about who sent what asset and when.
- Prefer this over near.tx when you do not need receipt details or execution outcomes.
Response notes:
- Transfers answers the asset-movement question directly and returns raw rows plus resume-token pagination when available.
- It is intentionally narrower than the tx family and better suited to feed-style scripting.
Follow-ups:
- If one transfer row needs a deeper execution story, pivot to near.tx.transactions with the related hash.
- If you need holdings instead of movement, switch to near.api.v1.accountFull.
Related recipes:
- `inspect-transaction`
- `account-full`
Example inputs:
```json
{
"accountId": "root.near",
"desc": true,
"limit": 5
}
```
### Terminal
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
node -e "$(curl -fsSL https://js.fastnear.com/agents.js)" <<'EOF'
const feed = await near.transfers.query({
accountId: "root.near",
desc: true,
limit: 5,
});
near.print({
recent: (feed.transfers || []).map((entry) => ({
block_height: entry.block_height,
asset_id: entry.asset_id,
human_amount: entry.human_amount,
other_account_id: entry.other_account_id,
transfer_type: entry.transfer_type,
tx: entry.transaction_id,
})),
});
EOF
```
### curl + jq
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
ACCOUNT_ID=root.near
curl -sS "https://transfers.main.fastnear.com/v0/transfers" -H "Authorization: Bearer $FASTNEAR_API_KEY" -H 'content-type: application/json' --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{account_id: $account_id, desc: true, limit: 5}')" | jq '{
recent: [.transfers[] | {
block_height,
asset_id,
human_amount,
other_account_id,
transfer_type,
tx: .transaction_id
}]
}'
```
### Browser Global
```js
const feed = await near.transfers.query({
accountId: "root.near",
desc: true,
limit: 5,
});
near.print({
recent: (feed.transfers || []).map((entry) => ({
block_height: entry.block_height,
asset_id: entry.asset_id,
human_amount: entry.human_amount,
other_account_id: entry.other_account_id,
transfer_type: entry.transfer_type,
tx: entry.transaction_id,
})),
});
```
### ESM
```js
import * as near from "@fastnear/api";
near.config({ apiKey: process.env.FASTNEAR_API_KEY || undefined });
const feed = await near.transfers.query({
accountId: "root.near",
desc: true,
limit: 5,
});
near.print({
recent: (feed.transfers || []).map((entry) => ({
block_height: entry.block_height,
asset_id: entry.asset_id,
human_amount: entry.human_amount,
other_account_id: entry.other_account_id,
transfer_type: entry.transfer_type,
tx: entry.transaction_id,
})),
});
```
## What block is NEAR on right now?
- ID: `last-block-final`
- API: `near.neardata.lastBlockFinal`
- Service: `neardata`
- Returns: `FastNearNeardataLastBlockFinalResponse`
- Network: `mainnet`
- Auth: `none`
- Summary: Use the NEAR Data family when you want a recent block document without stitching shards together yourself.
- Output keys: `block.header.height`, `block.header.timestamp_nanosec`, `shards[].shard_id`, `shards[].chunk.transactions`
- Pagination: range; request fields: blockHeight, from_block_height, to_block_height; response fields: none; filters must stay stable: no
Choose this when:
- Choose this when the question starts with recent block recency or transaction volume.
- Use the family-level block endpoints when you want to walk heights or inspect one shard or chunk next.
Response notes:
- NEAR Data returns block documents with shard content already grouped for block-level inspection.
- This recipe highlights the smallest useful block recency summary while keeping the full response available in JS.
Follow-ups:
- If one transaction in the block matters, continue with near.tx.transactions.
- If you need a specific historical block, move to near.neardata.block or near.neardata.blockChunk.
Related recipes:
- `inspect-transaction`
Example inputs:
```json
{}
```
### Terminal
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
node -e "$(curl -fsSL https://js.fastnear.com/agents.js)" <<'EOF'
const block = await near.neardata.lastBlockFinal();
// shard.chunk is null when a shard missed this block — guard before reading.
near.print({
height: block.block.header.height,
timestamp_nanosec: block.block.header.timestamp_nanosec,
txs_per_shard: block.shards.map((shard) => ({
shard_id: shard.shard_id,
tx_count: shard.chunk?.transactions.length ?? 0,
})),
total_txs: block.shards.reduce(
(count, shard) => count + (shard.chunk?.transactions.length ?? 0),
0
),
});
EOF
```
### curl + jq
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
curl -sSL "https://mainnet.neardata.xyz/v0/last_block/final?apiKey=$FASTNEAR_API_KEY" | jq '{
height: .block.header.height,
timestamp_nanosec: .block.header.timestamp_nanosec,
txs_per_shard: [.shards[] | {shard_id, tx_count: (.chunk.transactions | length)}],
total_txs: ([.shards[].chunk.transactions[]?] | length)
}'
```
### Browser Global
```js
const block = await near.neardata.lastBlockFinal();
// shard.chunk is null when a shard missed this block — guard before reading.
near.print({
height: block.block.header.height,
timestamp_nanosec: block.block.header.timestamp_nanosec,
txs_per_shard: block.shards.map((shard) => ({
shard_id: shard.shard_id,
tx_count: shard.chunk?.transactions.length ?? 0,
})),
total_txs: block.shards.reduce(
(count, shard) => count + (shard.chunk?.transactions.length ?? 0),
0
),
});
```
### ESM
```js
import * as near from "@fastnear/api";
near.config({ apiKey: process.env.FASTNEAR_API_KEY || undefined });
const block = await near.neardata.lastBlockFinal();
// shard.chunk is null when a shard missed this block — guard before reading.
near.print({
height: block.block.header.height,
timestamp_nanosec: block.block.header.timestamp_nanosec,
txs_per_shard: block.shards.map((shard) => ({
shard_id: shard.shard_id,
tx_count: shard.chunk?.transactions.length ?? 0,
})),
total_txs: block.shards.reduce(
(count, shard) => count + (shard.chunk?.transactions.length ?? 0),
0
),
});
```
## What is the latest indexed value for this exact key?
- ID: `kv-latest-key`
- API: `near.fastdata.kv.getLatestKey`
- Service: `fastdata.kv`
- Returns: `FastNearKvGetLatestKeyResponse`
- Network: `mainnet`
- Auth: `none`
- Summary: Start narrow with KV FastData when you already know the contract, predecessor, and exact storage key.
- Output keys: `entries[].current_account_id`, `entries[].predecessor_id`, `entries[].block_height`, `entries[].key`, `entries[].value`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this when you already know the exact key and want the latest indexed value immediately.
- Use the broader history or predecessor scans only after this exact-key lookup stops being enough.
Response notes:
- KV FastData keeps the exact indexed storage history question narrow and fast when you already know the key.
- The raw response keeps the full entry list; the example snippet extracts the most informative first entry.
Follow-ups:
- If you need history for the same key, continue with near.fastdata.kv.getHistoryKey.
- If you only know the predecessor and need discovery, continue with near.fastdata.kv.allByPredecessor.
Related recipes:
- `view-contract`
Example inputs:
```json
{
"currentAccountId": "social.near",
"predecessorId": "james.near",
"key": "graph/follow/sleet.near"
}
```
### Terminal
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
node -e "$(curl -fsSL https://js.fastnear.com/agents.js)" <<'EOF'
const result = await near.fastdata.kv.getLatestKey({
currentAccountId: "social.near",
predecessorId: "james.near",
key: "graph/follow/sleet.near",
});
const latest = result.entries?.[0] || null;
near.print({
latest: latest
? {
current_account_id: latest.current_account_id,
predecessor_id: latest.predecessor_id,
block_height: latest.block_height,
key: latest.key,
value: latest.value,
}
: null,
});
EOF
```
### curl + jq
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
CURRENT_ACCOUNT_ID=social.near
PREDECESSOR_ID=james.near
KEY='graph/follow/sleet.near'
ENCODED_KEY="$(jq -rn --arg key "$KEY" '$key | @uri')"
curl -sS "https://kv.main.fastnear.com/v0/latest/$CURRENT_ACCOUNT_ID/$PREDECESSOR_ID/$ENCODED_KEY" -H "Authorization: Bearer $FASTNEAR_API_KEY" | jq '{
latest: (
.entries[0]
| {
current_account_id,
predecessor_id,
block_height,
key,
value
}
)
}'
```
### Browser Global
```js
const result = await near.fastdata.kv.getLatestKey({
currentAccountId: "social.near",
predecessorId: "james.near",
key: "graph/follow/sleet.near",
});
const latest = result.entries?.[0] || null;
near.print({
latest: latest
? {
current_account_id: latest.current_account_id,
predecessor_id: latest.predecessor_id,
block_height: latest.block_height,
key: latest.key,
value: latest.value,
}
: null,
});
```
### ESM
```js
import * as near from "@fastnear/api";
near.config({ apiKey: process.env.FASTNEAR_API_KEY || undefined });
const result = await near.fastdata.kv.getLatestKey({
currentAccountId: "social.near",
predecessorId: "james.near",
key: "graph/follow/sleet.near",
});
const latest = result.entries?.[0] || null;
near.print({
latest: latest
? {
current_account_id: latest.current_account_id,
predecessor_id: latest.predecessor_id,
block_height: latest.block_height,
key: latest.key,
value: latest.value,
}
: null,
});
```
## How do I connect a wallet?
- ID: `connect-wallet`
- API: `near.recipes.connect`
- Service: `wallet`
- Returns: `{ accountId: string } | undefined`
- Network: `mainnet`
- Auth: `wallet`
- Summary: Open the wallet picker and attach a signer to the FastNear runtime.
- Output keys: `accountId`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this when the task crosses from read-only inspection into user-approved signing.
- Use it once per browser session before function calls, transfers, or message signatures.
Response notes:
- Wallet-backed recipes are browser-first because they need an interactive signer.
- This recipe is the smallest explicit connect step before sending transactions or signing messages.
Follow-ups:
- After connecting, send one contract action with near.recipes.functionCall.
- If the next step is a simple NEAR payment, continue with near.recipes.transfer.
Related recipes:
- `function-call`
- `transfer`
- `sign-message`
- `sign-delegate-actions`
Example inputs:
```json
{
"contractId": "berryclub.ek.near"
}
```
### Terminal
```bash
# Browser wallet required.
# Opening the wallet picker needs a browser environment.
# Use the browser-global or ESM snippet for this task.
```
### Browser Global
```js
const result = await near.recipes.connect({
contractId: "berryclub.ek.near",
});
near.print(result ?? near.selected());
```
### ESM
```js
import * as near from "@fastnear/api";
import * as nearWallet from "@fastnear/wallet";
near.useWallet(nearWallet);
// The wallet owns the session; near.sendTx reads the signer from
// @fastnear/api's per-network state. Without this bridge every send throws
// "Must sign in" even with an active wallet session.
nearWallet.onConnect((session) =>
near.state.updateAccountState({ accountId: session.accountId }, session.network),
);
// Resume a session the user already approved — no popup. Snippets that call
// near.recipes.connect below open the picker themselves.
await nearWallet.restore({
network: "mainnet",
contractId: "berryclub.ek.near",
});
const result = await near.recipes.connect({
contractId: "berryclub.ek.near",
});
near.print(result ?? near.selected());
```
## How do I send one function call?
- ID: `function-call`
- API: `near.recipes.functionCall`
- Service: `wallet`
- Returns: `WalletTransactionResult`
- Network: `mainnet`
- Auth: `wallet`
- Summary: Sign and broadcast a single contract call with readable gas units.
- Output keys: `transaction`, `outcomes`, `status`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this when you need one contract call and already know the receiver, method, and args.
- Prefer this recipe over the lower-level sendTx path when you want the smallest wallet-backed API surface.
Response notes:
- This is the thinnest wallet-backed transaction recipe and keeps the action declaration explicit.
- The example uses readable unit conversion before handing the transaction to the runtime.
Follow-ups:
- If the user only needs a native NEAR transfer, continue with near.recipes.transfer.
- If you want to preview the action before signing, use near.explain.tx on the same action list.
Related recipes:
- `connect-wallet`
- `transfer`
- `sign-message`
Example inputs:
```json
{
"receiverId": "berryclub.ek.near",
"methodName": "draw",
"args": {
"pixels": [
{
"x": 10,
"y": 20,
"color": 65280
}
]
},
"gas": "100 Tgas",
"deposit": "0"
}
```
### Terminal
```bash
# Browser wallet required.
# Signing and broadcasting a contract call needs a wallet session.
# Use the browser-global or ESM snippet for this task.
```
### Browser Global
```js
const cu = near.utils.convertUnit;
const result = await near.recipes.functionCall({
receiverId: "berryclub.ek.near",
methodName: "draw",
args: {
pixels: [{ x: 10, y: 20, color: 65280 }],
},
gas: cu("100 Tgas"),
deposit: "0",
});
near.print(result);
```
### ESM
```js
import * as near from "@fastnear/api";
import * as nearWallet from "@fastnear/wallet";
near.useWallet(nearWallet);
// The wallet owns the session; near.sendTx reads the signer from
// @fastnear/api's per-network state. Without this bridge every send throws
// "Must sign in" even with an active wallet session.
nearWallet.onConnect((session) =>
near.state.updateAccountState({ accountId: session.accountId }, session.network),
);
// Resume a session the user already approved — no popup. Snippets that call
// near.recipes.connect below open the picker themselves.
await nearWallet.restore({
network: "mainnet",
contractId: "berryclub.ek.near",
});
const cu = near.utils.convertUnit;
const result = await near.recipes.functionCall({
receiverId: "berryclub.ek.near",
methodName: "draw",
args: {
pixels: [{ x: 10, y: 20, color: 65280 }],
},
gas: cu("100 Tgas"),
deposit: "0",
});
near.print(result);
```
## How do I transfer NEAR?
- ID: `transfer`
- API: `near.recipes.transfer`
- Service: `wallet`
- Returns: `WalletTransactionResult`
- Network: `mainnet`
- Auth: `wallet+deposit`
- Summary: Send a simple NEAR transfer with a wallet-backed signature.
- Output keys: `transaction`, `outcomes`, `status`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this when the task is a plain NEAR payment and not a contract method call.
- Use the function-call recipe instead when the receiver expects method args or custom gas settings.
Response notes:
- This recipe keeps a simple NEAR transfer readable without constructing the action list manually.
- The transaction still goes through the same wallet-backed approval flow as other signing tasks.
Follow-ups:
- If you want to explain the transfer before sending it, use near.explain.tx with a Transfer action.
- If the next task is another signed action, keep the same wallet session and continue with near.recipes.functionCall.
Related recipes:
- `connect-wallet`
- `function-call`
Example inputs:
```json
{
"receiverId": "escrow.ai.near",
"amount": "0.1 NEAR"
}
```
### Terminal
```bash
# Browser wallet required.
# Sending NEAR needs a wallet-backed signature flow.
# Use the browser-global or ESM snippet for this task.
```
### Browser Global
```js
const cu = near.utils.convertUnit;
const result = await near.recipes.transfer({
receiverId: "escrow.ai.near",
amount: cu("0.1 NEAR"),
});
near.print(result);
```
### ESM
```js
import * as near from "@fastnear/api";
import * as nearWallet from "@fastnear/wallet";
near.useWallet(nearWallet);
// The wallet owns the session; near.sendTx reads the signer from
// @fastnear/api's per-network state. Without this bridge every send throws
// "Must sign in" even with an active wallet session.
nearWallet.onConnect((session) =>
near.state.updateAccountState({ accountId: session.accountId }, session.network),
);
// Resume a session the user already approved — no popup. Snippets that call
// near.recipes.connect below open the picker themselves.
await nearWallet.restore({
network: "mainnet",
contractId: "berryclub.ek.near",
});
const cu = near.utils.convertUnit;
const result = await near.recipes.transfer({
receiverId: "escrow.ai.near",
amount: cu("0.1 NEAR"),
});
near.print(result);
```
## How do I sign a message?
- ID: `sign-message`
- API: `near.recipes.signMessage`
- Service: `wallet`
- Returns: `WalletMessageSignatureResult`
- Network: `mainnet`
- Auth: `wallet`
- Summary: Request a wallet-backed NEP-413 signature for an app message.
- Output keys: `signature`, `accountId`, `publicKey`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this when you need user-approved application auth without broadcasting a transaction.
- Prefer this over functionCall or transfer when the task is strictly off-chain signing.
Response notes:
- This is the wallet-backed message-signing path for NEP-413 style app messages.
- It stays separate from transaction recipes because no chain write is involved.
Follow-ups:
- If you need to connect the wallet first, start with near.recipes.connect.
- If the flow turns into an on-chain action, move to near.recipes.functionCall or near.recipes.transfer.
Related recipes:
- `connect-wallet`
- `sign-delegate-actions`
Example inputs:
```json
{
"message": "Sign in to FastNear Berry Club"
}
```
### Terminal
```bash
# Browser wallet required.
# Message signing depends on a connected wallet provider.
# Use the browser-global or ESM snippet for this task.
```
### Browser Global
```js
const result = await near.recipes.signMessage({
message: "Sign in to FastNear Berry Club",
recipient: window.location.host,
nonce: crypto.getRandomValues(new Uint8Array(32)),
});
near.print(result);
```
### ESM
```js
import * as near from "@fastnear/api";
import * as nearWallet from "@fastnear/wallet";
near.useWallet(nearWallet);
// The wallet owns the session; near.sendTx reads the signer from
// @fastnear/api's per-network state. Without this bridge every send throws
// "Must sign in" even with an active wallet session.
nearWallet.onConnect((session) =>
near.state.updateAccountState({ accountId: session.accountId }, session.network),
);
// Resume a session the user already approved — no popup. Snippets that call
// near.recipes.connect below open the picker themselves.
await nearWallet.restore({
network: "mainnet",
contractId: "berryclub.ek.near",
});
const result = await near.recipes.signMessage({
message: "Sign in to FastNear Berry Club",
recipient: window.location.host,
nonce: crypto.getRandomValues(new Uint8Array(32)),
});
near.print(result);
```
## How do I sign delegate actions for gasless transactions?
- ID: `sign-delegate-actions`
- API: `nearWallet.signDelegateActions`
- Service: `wallet`
- Returns: `SignDelegateActionsResponse`
- Network: `mainnet`
- Auth: `wallet`
- Summary: Sign NEP-366 delegate actions via the connected wallet so a relayer can submit them on-chain without the user paying gas.
- Output keys: `signedDelegateActions[].borshSerializedBase64`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this when building gasless or relay-based flows where a third party submits the transaction on the user's behalf.
- Prefer sign-message when you only need an off-chain signature, or function-call when the user can pay gas directly.
Response notes:
- The canonical result is { borshSerializedBase64: string }; legacy structured delegates and bare base64 strings remain in the public union for compatibility.
- Returns signed delegate actions that a relayer can submit on-chain, enabling gasless transactions for the user.
- Relay it directly: near.relayDelegate({ signedDelegate: result.signedDelegateActions[0] }). Under the hood near.utils.parseSignedDelegate turns the wallet's borshSerializedBase64 into the { delegateAction, signature } shape relayDelegate needs — decoding the borsh yourself via near.exp.borsh.deserialize(near.exp.borshSchema.SignedDelegate, bytes) yields chain-schema action shapes the action builders reject with 'Not implemented action: undefined', so prefer parseSignedDelegate.
- The wallet must support the signDelegateActions feature (check WalletFeatures.signDelegateActions).
- Requests that include blockHeightTtl additionally require WalletFeatures.signDelegateActionsWithTtl.
Follow-ups:
- Relay the result with near.relayDelegate({ signedDelegate: result.signedDelegateActions[0], relayerSigner, relayerId }) to submit it on-chain without the signer paying gas.
- To inspect or transform the delegate first, near.utils.parseSignedDelegate(result.signedDelegateActions[0]) returns the { delegateAction, signature } pair (plus borshBase64).
- If the flow does not need a relayer, use near.recipes.functionCall for a standard wallet-signed transaction instead.
Related recipes:
- `connect-wallet`
- `sign-message`
- `function-call`
Example inputs:
```json
{
"delegateActions": [
{
"receiverId": "berryclub.ek.near",
"actions": [
{
"type": "FunctionCall",
"methodName": "draw",
"args": {
"pixels": [
{
"x": 10,
"y": 20,
"color": 65280
}
]
},
"gas": "100 Tgas",
"deposit": "0"
}
]
}
]
}
```
### Terminal
```bash
# Browser wallet required.
# Signing delegate actions depends on a connected wallet provider.
# Use the browser-global or ESM snippet for this task.
```
### Browser Global
```js
const cu = near.utils.convertUnit;
const result = await nearWallet.signDelegateActions({
delegateActions: [
{
receiverId: "berryclub.ek.near",
actions: [
{
type: "FunctionCall",
methodName: "draw",
args: { pixels: [{ x: 10, y: 20, color: 65280 }] },
gas: cu("100 Tgas"),
deposit: "0",
},
],
},
],
});
near.print({
count: result.signedDelegateActions.length,
first_delegate_borsh_base64:
result.signedDelegateActions[0]?.borshSerializedBase64,
});
```
### ESM
```js
import * as near from "@fastnear/api";
import * as nearWallet from "@fastnear/wallet";
near.useWallet(nearWallet);
// The wallet owns the session; near.sendTx reads the signer from
// @fastnear/api's per-network state. Without this bridge every send throws
// "Must sign in" even with an active wallet session.
nearWallet.onConnect((session) =>
near.state.updateAccountState({ accountId: session.accountId }, session.network),
);
// Resume a session the user already approved — no popup. Snippets that call
// near.recipes.connect below open the picker themselves.
await nearWallet.restore({
network: "mainnet",
contractId: "berryclub.ek.near",
});
const cu = near.utils.convertUnit;
const result = await nearWallet.signDelegateActions({
delegateActions: [
{
receiverId: "berryclub.ek.near",
actions: [
{
type: "FunctionCall",
methodName: "draw",
args: { pixels: [{ x: 10, y: 20, color: 65280 }] },
gas: cu("100 Tgas"),
deposit: "0",
},
],
},
],
});
near.print({
count: result.signedDelegateActions.length,
first_delegate_borsh_base64:
result.signedDelegateActions[0]?.borshSerializedBase64,
});
```
## How do I connect a wallet and sign a message in one step?
- ID: `connect-and-sign-message`
- API: `near.recipes.connect`
- Service: `wallet`
- Returns: `{ accountId: string; publicKey?: string; signedMessage?: SignedMessage } | undefined`
- Network: `mainnet`
- Auth: `wallet`
- Summary: Combine sign-in and NEP-413 message signing into a single wallet popup instead of two.
- Output keys: `accountId`, `signedMessage.accountId`, `signedMessage.publicKey`, `signedMessage.signature`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this when a session needs both a connected wallet and a proof-of-ownership signature, and you want one prompt rather than two.
- Prefer plain connect-wallet when no signature is needed, or sign-message when the wallet is already connected.
Response notes:
- signedMessage is only present when signMessageParams was supplied and the wallet completed both steps.
- The wallet picker is filtered to wallets advertising the signInAndSignMessage feature, so fewer wallets are offered than a plain connect.
- Read the signing key from signedMessage.publicKey — several wallets omit publicKey on the account itself in this flow.
- Verify the signature with near.utils.verifyNep413Signature before trusting it as proof of account ownership.
Follow-ups:
- Verify the returned signature with near.utils.verifyNep413Signature to authenticate the session server-side.
- Once connected, send contract actions with near.recipes.functionCall.
Related recipes:
- `connect-wallet`
- `sign-message`
- `function-call`
Example inputs:
```json
{
"contractId": "berryclub.ek.near",
"signMessageParams": {
"message": "Sign in to FastNear Berry Club",
"recipient": "example.com",
"nonce": "(32-byte Uint8Array)"
}
}
```
### Terminal
```bash
# Browser wallet required.
# Connecting and signing a message needs a browser environment with a wallet.
# Use the browser-global or ESM snippet for this task.
```
### Browser Global
```js
const result = await near.recipes.connect({
contractId: "berryclub.ek.near",
signMessageParams: {
message: "Sign in to FastNear Berry Club",
recipient: window.location.host,
nonce: crypto.getRandomValues(new Uint8Array(32)),
},
});
near.print(result);
```
### ESM
```js
import * as near from "@fastnear/api";
import * as nearWallet from "@fastnear/wallet";
near.useWallet(nearWallet);
// The wallet owns the session; near.sendTx reads the signer from
// @fastnear/api's per-network state. Without this bridge every send throws
// "Must sign in" even with an active wallet session.
nearWallet.onConnect((session) =>
near.state.updateAccountState({ accountId: session.accountId }, session.network),
);
// Resume a session the user already approved — no popup. Snippets that call
// near.recipes.connect below open the picker themselves.
await nearWallet.restore({
network: "mainnet",
contractId: "berryclub.ek.near",
});
const result = await near.recipes.connect({
contractId: "berryclub.ek.near",
signMessageParams: {
message: "Sign in to FastNear Berry Club",
recipient: window.location.host,
nonce: crypto.getRandomValues(new Uint8Array(32)),
},
});
near.print(result);
```
## How do I build and preview a transaction before signing?
- ID: `explain-transaction`
- API: `near.explain.tx`
- Service: `api`
- Returns: `ExplainedTransaction`
- Network: `mainnet`
- Auth: `none`
- Summary: Declare actions with readable unit gas/deposit and get a stable JSON summary from near.explain.tx — no wallet, no network, no BigInt.
- Output keys: `kind`, `signerId`, `receiverId`, `actionCount`, `actions`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this to sanity-check exactly what you are about to sign before handing actions to a wallet or sendTx.
- Use near.explain.action for a single action, or near.utils.txToJson to JSON-serialize a full signed transaction object.
Response notes:
- near.explain.tx is a pure function — it never opens a wallet or hits the network.
- Wide integers (gas, deposit, amounts) are decimal strings in and out; you never need BigInt to build or inspect a transaction.
- Gas and deposit are echoed exactly as written, including unit strings like "100 Tgas" — convert with near.utils.convertUnit only if you need the yocto value.
Follow-ups:
- Sign and broadcast the same actions with near.recipes.functionCall (wallet) or sendTx (local key).
- See the hosted /transactions explainer for the full construct-and-send flow.
Related recipes:
- `function-call`
- `transfer`
- `sign-delegate-actions`
Example inputs:
```json
{
"signerId": "root.near",
"receiverId": "berryclub.ek.near",
"actions": [
{
"type": "FunctionCall",
"methodName": "draw",
"args": {
"pixels": [
{
"x": 10,
"y": 20,
"color": 65280
}
]
},
"gas": "100 Tgas",
"deposit": "0"
}
]
}
```
### Terminal
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
node -e "$(curl -fsSL https://js.fastnear.com/agents.js)" <<'EOF'
// Build actions with readable units — string, number, or bigint all work.
const actions = [
near.actions.functionCall({
methodName: "draw",
args: { pixels: [{ x: 10, y: 20, color: 65280 }] },
gas: "100 Tgas",
deposit: "0",
}),
];
// Preview before signing: a pure, JSON-safe summary — no network, no wallet.
// Wide integers stay decimal strings, so this never trips on BigInt.
near.print(near.explain.tx({
signerId: "root.near",
receiverId: "berryclub.ek.near",
actions,
}));
EOF
```
### Browser Global
```js
// Build actions with readable units — string, number, or bigint all work.
const actions = [
near.actions.functionCall({
methodName: "draw",
args: { pixels: [{ x: 10, y: 20, color: 65280 }] },
gas: "100 Tgas",
deposit: "0",
}),
];
// Preview before signing: a pure, JSON-safe summary — no network, no wallet.
// Wide integers stay decimal strings, so this never trips on BigInt.
near.print(near.explain.tx({
signerId: "root.near",
receiverId: "berryclub.ek.near",
actions,
}));
```
### ESM
```js
import * as near from "@fastnear/api";
near.config({ apiKey: process.env.FASTNEAR_API_KEY || undefined });
// Build actions with readable units — string, number, or bigint all work.
const actions = [
near.actions.functionCall({
methodName: "draw",
args: { pixels: [{ x: 10, y: 20, color: 65280 }] },
gas: "100 Tgas",
deposit: "0",
}),
];
// Preview before signing: a pure, JSON-safe summary — no network, no wallet.
// Wide integers stay decimal strings, so this never trips on BigInt.
near.print(near.explain.tx({
signerId: "root.near",
receiverId: "berryclub.ek.near",
actions,
}));
```
## What is this account's FT balance?
- ID: `ft-balance`
- API: `near.ft.balance`
- Service: `rpc`
- Returns: `string`
- Network: `mainnet`
- Auth: `none`
- Summary: Read a NEP-141 token balance with a one-line wrapper that fills in the standard method name.
- Output keys: `raw_balance`, `symbol`, `decimals`, `human_amount`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this when you already know the FT contract and want one account's balance.
- Use ft-inventory instead when you need every FT balance an account holds.
Response notes:
- near.ft.balance returns the raw integer balance string from ft_balance_of, scaled by the token's decimals.
- Pair with near.ft.metadata to format the human-readable amount in one shot.
- Convert raw to human with near.utils.scaleDecimal(raw, -decimals) — it shifts the decimal point on the string and returns an exact decimal string. Number(raw) / 10 ** decimals silently rounds any balance above 2^53, which is most real balances; scaleDecimal also trims trailing zeros, so pad the fraction yourself if you need fixed width.
Follow-ups:
- If you need every token the account holds, switch to near.ft.inventory.
- If you need a historical balance, add useArchival: true and a blockId — see archival-snapshot.
Related recipes:
- `ft-metadata`
- `ft-inventory`
- `archival-snapshot`
Example inputs:
```json
{
"contractId": "berryclub.ek.near",
"accountId": "root.near"
}
```
### Terminal
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
node -e "$(curl -fsSL https://js.fastnear.com/agents.js)" <<'EOF'
const balance = await near.ft.balance({
contractId: "berryclub.ek.near",
accountId: "root.near",
});
const meta = await near.ft.metadata({ contractId: "berryclub.ek.near" });
near.print({
raw_balance: balance,
symbol: meta.symbol,
decimals: meta.decimals,
// scaleDecimal shifts the decimal point on the STRING. Number(balance)
// would round anything past 2^53 — most real FT balances.
human_amount: near.utils.scaleDecimal(balance, -meta.decimals),
});
EOF
```
### curl + jq
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
ACCOUNT_ID=root.near
ARGS_BASE64="$(jq -nc --arg account_id "$ACCOUNT_ID" '{account_id: $account_id}' | base64 | tr -d '\n')"
curl -sS "https://rpc.mainnet.fastnear.com?apiKey=$FASTNEAR_API_KEY" -H 'content-type: application/json' --data "$(jq -nc --arg args "$ARGS_BASE64" '{
jsonrpc:"2.0",id:"fastnear",method:"query",
params:{
request_type:"call_function",
finality:"final",
account_id:"berryclub.ek.near",
method_name:"ft_balance_of",
args_base64:$args
}
}')" | jq -r '.result.result | implode'
```
### Browser Global
```js
const balance = await near.ft.balance({
contractId: "berryclub.ek.near",
accountId: "root.near",
});
const meta = await near.ft.metadata({ contractId: "berryclub.ek.near" });
near.print({
raw_balance: balance,
symbol: meta.symbol,
decimals: meta.decimals,
// scaleDecimal shifts the decimal point on the STRING. Number(balance)
// would round anything past 2^53 — most real FT balances.
human_amount: near.utils.scaleDecimal(balance, -meta.decimals),
});
```
### ESM
```js
import * as near from "@fastnear/api";
near.config({ apiKey: process.env.FASTNEAR_API_KEY || undefined });
const balance = await near.ft.balance({
contractId: "berryclub.ek.near",
accountId: "root.near",
});
const meta = await near.ft.metadata({ contractId: "berryclub.ek.near" });
near.print({
raw_balance: balance,
symbol: meta.symbol,
decimals: meta.decimals,
// scaleDecimal shifts the decimal point on the STRING. Number(balance)
// would round anything past 2^53 — most real FT balances.
human_amount: near.utils.scaleDecimal(balance, -meta.decimals),
});
```
## What does this NEP-141 token call itself?
- ID: `ft-metadata`
- API: `near.ft.metadata`
- Service: `rpc`
- Returns: `{ name: string; symbol: string; decimals: number; icon?: string; reference?: string; reference_hash?: string }`
- Network: `mainnet`
- Auth: `none`
- Summary: Fetch name, symbol, decimals, and icon for a fungible token in one call.
- Output keys: `name`, `symbol`, `decimals`, `icon`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this when you need to format a balance, label a token, or display branding.
- Pair with ft-balance whenever you also need a human-readable amount.
Response notes:
- Wraps the standard NEP-141 ft_metadata view call so the method name does not have to be remembered.
- Decimals comes back as a number; multiply or divide raw balances accordingly.
Follow-ups:
- If you also need an account balance, continue with near.ft.balance.
- If you want a portfolio view across all tokens, use near.ft.inventory.
Related recipes:
- `ft-balance`
- `ft-inventory`
Example inputs:
```json
{
"contractId": "berryclub.ek.near"
}
```
### Terminal
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
node -e "$(curl -fsSL https://js.fastnear.com/agents.js)" <<'EOF'
const meta = await near.ft.metadata({
contractId: "berryclub.ek.near",
});
near.print({
name: meta.name,
symbol: meta.symbol,
decimals: meta.decimals,
icon_present: !!meta.icon,
});
EOF
```
### curl + jq
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
EMPTY_ARGS_BASE64="$(printf '{}' | base64)"
curl -sS "https://rpc.mainnet.fastnear.com?apiKey=$FASTNEAR_API_KEY" -H 'content-type: application/json' --data "$(jq -nc --arg args "$EMPTY_ARGS_BASE64" '{
jsonrpc:"2.0",id:"fastnear",method:"query",
params:{
request_type:"call_function",
finality:"final",
account_id:"berryclub.ek.near",
method_name:"ft_metadata",
args_base64:$args
}
}')" | jq '.result.result | implode | fromjson | {name, symbol, decimals}'
```
### Browser Global
```js
const meta = await near.ft.metadata({
contractId: "berryclub.ek.near",
});
near.print({
name: meta.name,
symbol: meta.symbol,
decimals: meta.decimals,
icon_present: !!meta.icon,
});
```
### ESM
```js
import * as near from "@fastnear/api";
near.config({ apiKey: process.env.FASTNEAR_API_KEY || undefined });
const meta = await near.ft.metadata({
contractId: "berryclub.ek.near",
});
near.print({
name: meta.name,
symbol: meta.symbol,
decimals: meta.decimals,
icon_present: !!meta.icon,
});
```
## Which fungible tokens does this account hold?
- ID: `ft-inventory`
- API: `near.ft.inventory`
- Service: `api`
- Returns: `{ tokens: Array<{ contract_id: string; balance: string; last_update_block_height?: number }> }`
- Network: `mainnet`
- Auth: `bearer`
- Summary: List every NEP-141 contract the account holds via the FastNear indexer in one call.
- Output keys: `ft_contract_count`, `preview[].contract_id`, `preview[].balance`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this when the question is 'what tokens does this account own?' rather than one specific contract.
- Use ft-balance instead when you already know the contract id.
Response notes:
- near.ft.inventory hits the FastNear indexer (api.fastnear.com) — set near.config({ apiKey }) to avoid the public rate limit.
- Returns one row per FT contract the account currently holds; balances are raw integer strings.
Follow-ups:
- If you need NFTs as well, switch to near.nft.inventory.
- If you need staking and aggregate state too, use near.api.v1.accountFull.
Related recipes:
- `ft-balance`
- `nft-inventory`
- `account-full`
Example inputs:
```json
{
"accountId": "root.near"
}
```
### Terminal
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
node -e "$(curl -fsSL https://js.fastnear.com/agents.js)" <<'EOF'
// Tip: `near.config({ apiKey: "" })` raises rate limits.
const inventory = await near.ft.inventory({
accountId: "root.near",
});
near.print({
ft_contract_count: inventory.tokens.length,
preview: inventory.tokens.slice(0, 5).map((entry) => ({
contract_id: entry.contract_id,
balance: entry.balance,
})),
});
EOF
```
### curl + jq
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
ACCOUNT_ID=root.near
curl -sS "https://api.fastnear.com/v1/account/$ACCOUNT_ID/ft" -H "Authorization: Bearer $FASTNEAR_API_KEY" | jq '{
ft_contract_count: (.tokens | length),
preview: [.tokens[0:5][] | {contract_id, balance}]
}'
```
### Browser Global
```js
// Tip: `near.config({ apiKey: "" })` raises rate limits.
const inventory = await near.ft.inventory({
accountId: "root.near",
});
near.print({
ft_contract_count: inventory.tokens.length,
preview: inventory.tokens.slice(0, 5).map((entry) => ({
contract_id: entry.contract_id,
balance: entry.balance,
})),
});
```
### ESM
```js
import * as near from "@fastnear/api";
near.config({ apiKey: process.env.FASTNEAR_API_KEY || undefined });
// Tip: `near.config({ apiKey: "" })` raises rate limits.
const inventory = await near.ft.inventory({
accountId: "root.near",
});
near.print({
ft_contract_count: inventory.tokens.length,
preview: inventory.tokens.slice(0, 5).map((entry) => ({
contract_id: entry.contract_id,
balance: entry.balance,
})),
});
```
## Which NFTs does this account own on this contract?
- ID: `nft-for-owner`
- API: `near.nft.forOwner`
- Service: `rpc`
- Returns: `Array<{ token_id: string; owner_id: string; metadata?: { title?: string; media?: string; description?: string } }>`
- Network: `mainnet`
- Auth: `none`
- Summary: List the tokens an account owns under one NEP-171 contract with metadata included.
- Output keys: `count`, `preview[].token_id`, `preview[].title`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this when you already know the NFT contract and want one account's collection on it.
- Use nft-inventory instead when you want NFTs across every contract for an account.
Response notes:
- Wraps NEP-171 nft_tokens_for_owner; the contract decides what metadata fields to embed.
- Pass from_index and limit (numbers, sometimes strings depending on the contract) for pagination.
Follow-ups:
- If you need contract-level metadata, call near.nft.metadata.
- If you need cross-contract NFT discovery, switch to near.nft.inventory.
Related recipes:
- `nft-inventory`
Example inputs:
```json
{
"contractId": "x.paras.near",
"accountId": "root.near",
"limit": 5
}
```
### Terminal
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
node -e "$(curl -fsSL https://js.fastnear.com/agents.js)" <<'EOF'
const tokens = await near.nft.forOwner({
contractId: "x.paras.near",
accountId: "root.near",
limit: 5,
});
near.print({
count: tokens.length,
preview: tokens.map((token) => ({
token_id: token.token_id,
title: token.metadata?.title,
})),
});
EOF
```
### curl + jq
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
ACCOUNT_ID=root.near
ARGS_BASE64="$(jq -nc --arg account_id "$ACCOUNT_ID" '{account_id: $account_id, limit: 5}' | base64 | tr -d '\n')"
curl -sS "https://rpc.mainnet.fastnear.com?apiKey=$FASTNEAR_API_KEY" -H 'content-type: application/json' --data "$(jq -nc --arg args "$ARGS_BASE64" '{
jsonrpc:"2.0",id:"fastnear",method:"query",
params:{
request_type:"call_function",
finality:"final",
account_id:"x.paras.near",
method_name:"nft_tokens_for_owner",
args_base64:$args
}
}')" | jq '.result.result | implode | fromjson | [.[] | {token_id, title: .metadata.title}]'
```
### Browser Global
```js
const tokens = await near.nft.forOwner({
contractId: "x.paras.near",
accountId: "root.near",
limit: 5,
});
near.print({
count: tokens.length,
preview: tokens.map((token) => ({
token_id: token.token_id,
title: token.metadata?.title,
})),
});
```
### ESM
```js
import * as near from "@fastnear/api";
near.config({ apiKey: process.env.FASTNEAR_API_KEY || undefined });
const tokens = await near.nft.forOwner({
contractId: "x.paras.near",
accountId: "root.near",
limit: 5,
});
near.print({
count: tokens.length,
preview: tokens.map((token) => ({
token_id: token.token_id,
title: token.metadata?.title,
})),
});
```
## Which NFT contracts does this account hold tokens on?
- ID: `nft-inventory`
- API: `near.nft.inventory`
- Service: `api`
- Returns: `{ tokens: Array<{ contract_id: string; last_update_block_height: number | null }> }`
- Network: `mainnet`
- Auth: `bearer`
- Summary: Discover every NEP-171 contract the account holds tokens under via the FastNear indexer.
- Output keys: `contract_count`, `preview[].contract_id`, `preview[].last_update_block_height`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this when the question is 'what NFT contracts does this account hold tokens on?'.
- Use nft-for-owner when you already know the specific contract id.
Response notes:
- near.nft.inventory hits the FastNear indexer — set near.config({ apiKey }) to avoid the public rate limit.
- One row per NFT contract the account holds — contract ids only, no per-token ids; follow up with nft-for-owner per contract for token details.
Follow-ups:
- Drill into one contract with near.nft.forOwner for the per-token details.
- Pull holdings + staking + native NEAR with near.api.v1.accountFull.
Related recipes:
- `nft-for-owner`
- `ft-inventory`
- `account-full`
Example inputs:
```json
{
"accountId": "root.near"
}
```
### Terminal
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
node -e "$(curl -fsSL https://js.fastnear.com/agents.js)" <<'EOF'
// Tip: `near.config({ apiKey: "" })` raises rate limits.
const inventory = await near.nft.inventory({
accountId: "root.near",
});
// The inventory endpoint returns contract-level rows only (no per-token
// ids) — use the nft-for-owner recipe to list tokens on one contract.
near.print({
contract_count: inventory.tokens.length,
preview: inventory.tokens.slice(0, 3).map((entry) => ({
contract_id: entry.contract_id,
last_update_block_height: entry.last_update_block_height,
})),
});
EOF
```
### curl + jq
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
ACCOUNT_ID=root.near
curl -sS "https://api.fastnear.com/v1/account/$ACCOUNT_ID/nft" -H "Authorization: Bearer $FASTNEAR_API_KEY" | jq '{
contract_count: (.tokens | length),
preview: [.tokens[0:3][] | {contract_id, last_update_block_height}]
}'
```
### Browser Global
```js
// Tip: `near.config({ apiKey: "" })` raises rate limits.
const inventory = await near.nft.inventory({
accountId: "root.near",
});
// The inventory endpoint returns contract-level rows only (no per-token
// ids) — use the nft-for-owner recipe to list tokens on one contract.
near.print({
contract_count: inventory.tokens.length,
preview: inventory.tokens.slice(0, 3).map((entry) => ({
contract_id: entry.contract_id,
last_update_block_height: entry.last_update_block_height,
})),
});
```
### ESM
```js
import * as near from "@fastnear/api";
near.config({ apiKey: process.env.FASTNEAR_API_KEY || undefined });
// Tip: `near.config({ apiKey: "" })` raises rate limits.
const inventory = await near.nft.inventory({
accountId: "root.near",
});
// The inventory endpoint returns contract-level rows only (no per-token
// ids) — use the nft-for-owner recipe to list tokens on one contract.
near.print({
contract_count: inventory.tokens.length,
preview: inventory.tokens.slice(0, 3).map((entry) => ({
contract_id: entry.contract_id,
last_update_block_height: entry.last_update_block_height,
})),
});
```
## What did this account look like at a specific block?
- ID: `archival-snapshot`
- API: `near.queryAccount`
- Service: `rpc`
- Returns: `RpcViewAccountResponse`
- Network: `mainnet`
- Auth: `none`
- Summary: Read canonical account state at a historical block by setting useArchival on the query.
- Output keys: `amount`, `storage_usage`, `block_hash`, `block_height`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this when blockId predates the regular RPC's retention window or you specifically want a historical snapshot.
- Combine with the FT or NFT helpers (`useArchival: true` is forwarded) when you need a historical token balance.
Response notes:
- useArchival: true routes a single call to NEAR's archival RPC (archival-rpc.{mainnet,testnet}.near.org) which retains state past the regular RPC's ~5-epoch window.
- The same flag works on near.view, near.queryAccount, near.queryBlock, near.queryAccessKey, near.queryTx, and the lower-level near.sendRpc — falls back to the regular RPC if archival isn't configured for the network.
Follow-ups:
- Pair with near.ft.balance({ blockId, useArchival: true }) for a historical token balance.
- If you need a full holdings snapshot at a block, walk near.api.v1.accountFull with the blockId once it's supported on that surface.
Related recipes:
- `view-account`
- `ft-balance`
Example inputs:
```json
{
"accountId": "root.near",
"blockId": 100000000,
"useArchival": true
}
```
### Terminal
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
node -e "$(curl -fsSL https://js.fastnear.com/agents.js)" <<'EOF'
// Reads canonical account state at a specific historical block via the
// archival RPC. Add useArchival to any view/query when blockId predates
// the regular RPC's retention window (~5 epochs / a few days).
const past = await near.queryAccount({
accountId: "root.near",
blockId: 100_000_000,
useArchival: true,
});
// near.query* returns the raw JSON-RPC envelope — the data lives in .result.
const acct = past.result;
near.print({
amount: acct.amount,
storage_usage: acct.storage_usage,
block_hash: acct.block_hash,
block_height: acct.block_height,
});
EOF
```
### curl + jq
```bash
# NEAR's public archival RPC — no apiKey required.
ACCOUNT_ID=root.near
BLOCK_ID=100000000
curl -sS "https://archival-rpc.mainnet.near.org" -H 'content-type: application/json' --data "$(jq -nc --arg account_id "$ACCOUNT_ID" --argjson block "$BLOCK_ID" '{
jsonrpc:"2.0",id:"fastnear",method:"query",
params:{request_type:"view_account",account_id:$account_id,block_id:$block}
}')" | jq '.result | {amount, storage_usage, block_height, block_hash}'
```
### Browser Global
```js
// Reads canonical account state at a specific historical block via the
// archival RPC. Add useArchival to any view/query when blockId predates
// the regular RPC's retention window (~5 epochs / a few days).
const past = await near.queryAccount({
accountId: "root.near",
blockId: 100_000_000,
useArchival: true,
});
// near.query* returns the raw JSON-RPC envelope — the data lives in .result.
const acct = past.result;
near.print({
amount: acct.amount,
storage_usage: acct.storage_usage,
block_hash: acct.block_hash,
block_height: acct.block_height,
});
```
### ESM
```js
import * as near from "@fastnear/api";
near.config({ apiKey: process.env.FASTNEAR_API_KEY || undefined });
// Reads canonical account state at a specific historical block via the
// archival RPC. Add useArchival to any view/query when blockId predates
// the regular RPC's retention window (~5 epochs / a few days).
const past = await near.queryAccount({
accountId: "root.near",
blockId: 100_000_000,
useArchival: true,
});
// near.query* returns the raw JSON-RPC envelope — the data lives in .result.
const acct = past.result;
near.print({
amount: acct.amount,
storage_usage: acct.storage_usage,
block_hash: acct.block_hash,
block_height: acct.block_height,
});
```
## How do I open a testnet wallet session alongside mainnet?
- ID: `connect-testnet`
- API: `near.recipes.connect`
- Service: `wallet`
- Returns: `{ accountId: string; network?: "mainnet" | "testnet" } | undefined`
- Network: `testnet`
- Auth: `wallet`
- Summary: Use the per-network connect parameter to keep mainnet and testnet sessions side by side.
- Output keys: `connected.accountId`, `connected.network`, `active_networks`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this when the task spans both networks in the same page (mainnet read + testnet write, or A/B testing).
- Use connect-wallet when one network at a time is enough.
Response notes:
- @fastnear/wallet 1.1.0 keys session state per network, so signing in on testnet does not evict an active mainnet session.
- @fastnear/api 1.1.1 added a `network` parameter to near.recipes.connect (and signOut) — earlier versions silently used near.config().networkId.
- nearWallet.connectedNetworks() returns the list of networks with an active session.
Follow-ups:
- Send a function call on the testnet contract with near.recipes.functionCall({ network: "testnet", … }) — see the function-call-testnet recipe.
- Read the active session per network with nearWallet.accountId({ network: "testnet" }) and nearWallet.getActiveNetwork().
Related recipes:
- `connect-wallet`
- `function-call`
- `function-call-testnet`
Example inputs:
```json
{
"network": "testnet",
"contractId": "guest-book.testnet"
}
```
### Terminal
```bash
# Browser wallet required.
# Opening the wallet picker needs a browser environment.
# Use the browser-global or ESM snippet for this task.
```
### Browser Global
```js
// near.recipes.connect honors a per-call network override
// (@fastnear/api 1.1.1+), so this opens a testnet session alongside any
// existing mainnet session — wallet state is keyed per network.
const result = await near.recipes.connect({
network: "testnet",
contractId: "guest-book.testnet",
});
near.print({
connected: result,
active_networks: nearWallet.connectedNetworks(),
});
```
### ESM
```js
import * as near from "@fastnear/api";
import * as nearWallet from "@fastnear/wallet";
near.useWallet(nearWallet);
// The wallet owns the session; near.sendTx reads the signer from
// @fastnear/api's per-network state. Without this bridge every send throws
// "Must sign in" even with an active wallet session.
nearWallet.onConnect((session) =>
near.state.updateAccountState({ accountId: session.accountId }, session.network),
);
// Resume a session the user already approved — no popup. Snippets that call
// near.recipes.connect below open the picker themselves.
await nearWallet.restore({
network: "testnet",
contractId: "guest-book.testnet",
});
// near.recipes.connect honors a per-call network override
// (@fastnear/api 1.1.1+), so this opens a testnet session alongside any
// existing mainnet session — wallet state is keyed per network.
const result = await near.recipes.connect({
network: "testnet",
contractId: "guest-book.testnet",
});
near.print({
connected: result,
active_networks: nearWallet.connectedNetworks(),
});
```
## How do I send a function call on testnet without losing my mainnet session?
- ID: `function-call-testnet`
- API: `near.recipes.functionCall`
- Service: `wallet`
- Returns: `{ outcomes?: any[] } | { rejected: true } | undefined`
- Network: `testnet`
- Auth: `wallet`
- Summary: Pair near.recipes.connect({ network: "testnet" }) with near.recipes.functionCall({ network: "testnet" }) — connect honors the per-network override added in 1.1.1; functionCall does the same thanks to per-network account state in 1.1.2.
- Output keys: `outcomes[].transaction.hash`, `outcomes[].status`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this when an action lives on testnet but the page also holds a live mainnet session.
- Use function-call when only one network is involved.
Response notes:
- @fastnear/api 1.1.2 keys account state per network, so near.recipes.functionCall reads the testnet signer from its testnet slot regardless of which network is currently active.
- Local-signing also honors the network override in 1.1.2 — the RPC helpers, queryAccessKey/queryBlock/sendTxToRpc, and the nonce/block caches are all keyed per network.
- nearWallet.connectedNetworks() returns the list of networks with an active session if you want to gate the call on testnet being signed in first.
Follow-ups:
- Sign a NEP-413 message with the testnet session via near.recipes.signMessage(message, { network: "testnet" }).
- Send NEAR with near.recipes.transfer({ network: "testnet", … }) — same per-network surface.
Related recipes:
- `connect-testnet`
- `function-call`
- `transfer`
Example inputs:
```json
{
"network": "testnet",
"receiverId": "guest-book.testnet",
"methodName": "add_message",
"args": {
"text": "hello from a per-network call"
},
"gas": "30000000000000",
"deposit": "0"
}
```
### Terminal
```bash
# Browser wallet required.
# Signing a transaction needs the wallet picker, which needs a browser.
# Use the browser-global or ESM snippet for this task.
```
### Browser Global
```js
// near.recipes.functionCall accepts a per-call network override
// (@fastnear/api 1.1.2+) — once a testnet session is open, the api reads
// the testnet account from its per-network state map and dispatches the
// signed transaction through the wallet's testnet slot. The mainnet
// session, if any, is untouched.
await near.recipes.connect({
network: "testnet",
contractId: "guest-book.testnet",
});
const result = await near.recipes.functionCall({
network: "testnet",
receiverId: "guest-book.testnet",
methodName: "add_message",
args: { text: "hello from a per-network call" },
gas: "30000000000000",
deposit: "0",
});
near.print(result);
```
### ESM
```js
import * as near from "@fastnear/api";
import * as nearWallet from "@fastnear/wallet";
near.useWallet(nearWallet);
// The wallet owns the session; near.sendTx reads the signer from
// @fastnear/api's per-network state. Without this bridge every send throws
// "Must sign in" even with an active wallet session.
nearWallet.onConnect((session) =>
near.state.updateAccountState({ accountId: session.accountId }, session.network),
);
// Resume a session the user already approved — no popup. Snippets that call
// near.recipes.connect below open the picker themselves.
await nearWallet.restore({
network: "testnet",
contractId: "guest-book.testnet",
});
// near.recipes.functionCall accepts a per-call network override
// (@fastnear/api 1.1.2+) — once a testnet session is open, the api reads
// the testnet account from its per-network state map and dispatches the
// signed transaction through the wallet's testnet slot. The mainnet
// session, if any, is untouched.
await near.recipes.connect({
network: "testnet",
contractId: "guest-book.testnet",
});
const result = await near.recipes.functionCall({
network: "testnet",
receiverId: "guest-book.testnet",
methodName: "add_message",
args: { text: "hello from a per-network call" },
gas: "30000000000000",
deposit: "0",
});
near.print(result);
```
## What is the current gas price?
- ID: `gas-price`
- API: `near.gasPrice`
- Service: `rpc`
- Returns: `{ result: { gas_price: string } }`
- Network: `mainnet`
- Auth: `none`
- Summary: Read the current gas price from the RPC with a one-line wrapper; retries and 429-handling are built in.
- Output keys: `result.gas_price`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this to estimate transaction fees or to show the live network gas price.
- Use near.status for node/sync info or near.validators for the validator set.
Response notes:
- near.gasPrice returns the raw JSON-RPC envelope; read the value from result.gas_price.
- gas_price is a yoctoNEAR-per-gas decimal string — multiply by gas to estimate a fee, no BigInt required beyond your own math.
- Omit the argument for the latest block, or pass { blockId } to price a specific height or hash.
Follow-ups:
- Build and preview a transaction with near.explain.tx, then sign it with sendTx or a wallet.
- Inspect broader chain state with near.status() and near.validators().
Related recipes:
- `explain-transaction`
- `last-block-final`
- `function-call`
Example inputs:
```json
{}
```
### Terminal
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
node -e "$(curl -fsSL https://js.fastnear.com/agents.js)" <<'EOF'
// Current gas price straight from the RPC.
// Retries and 429-handling are on by default (see near.config({ retry })).
near.print(await near.gasPrice());
EOF
```
### Browser Global
```js
// Current gas price straight from the RPC.
// Retries and 429-handling are on by default (see near.config({ retry })).
near.print(await near.gasPrice());
```
### ESM
```js
import * as near from "@fastnear/api";
near.config({ apiKey: process.env.FASTNEAR_API_KEY || undefined });
// Current gas price straight from the RPC.
// Retries and 429-handling are on by default (see near.config({ retry })).
near.print(await near.gasPrice());
```
## How do I show a yoctoNEAR balance as human-readable NEAR?
- ID: `format-near-amount`
- API: `near.utils.formatNearAmount`
- Service: `api`
- Returns: `string`
- Network: `mainnet`
- Auth: `none`
- Summary: Render a yoctoNEAR integer as a human NEAR string with near.utils.formatNearAmount — the reverse of convertUnit, no BigInt.
- Output keys:
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this to display a balance read from near.view / near.ft.balance / decoded borsh as human NEAR.
- Use near.utils.convertUnit for the other direction ("1.5 NEAR" -> yocto).
Response notes:
- near.utils.formatNearAmount is pure — no network, no wallet.
- IN accepts a decimal string or bigint yoctoNEAR value; OUT is always a decimal string like "1.5", never a number or BigInt.
- Pass { fracDigits } to cap decimals, or { trimZeros: false } to pad; formatUnit(amount, unit) formats other units (e.g. "tgas").
Follow-ups:
- Read a balance to format with near.ft.balance or near.queryAccount.
- Construct a transfer of a parsed amount with near.actions.transfer(near.utils.convertUnit("1.5 NEAR")).
Related recipes:
- `ft-balance`
- `transfer`
- `explain-transaction`
Example inputs:
```json
{
"yocto": "1500000000000000000000000"
}
```
### Terminal
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
node -e "$(curl -fsSL https://js.fastnear.com/agents.js)" <<'EOF'
// Reverse of near.utils.convertUnit: render a yoctoNEAR integer as human NEAR.
// Wide integers are decimal strings in and out — you never touch BigInt.
const yocto = "1500000000000000000000000";
near.print(near.utils.formatNearAmount(yocto)); // "1.5"
EOF
```
### Browser Global
```js
// Reverse of near.utils.convertUnit: render a yoctoNEAR integer as human NEAR.
// Wide integers are decimal strings in and out — you never touch BigInt.
const yocto = "1500000000000000000000000";
near.print(near.utils.formatNearAmount(yocto)); // "1.5"
```
### ESM
```js
import * as near from "@fastnear/api";
near.config({ apiKey: process.env.FASTNEAR_API_KEY || undefined });
// Reverse of near.utils.convertUnit: render a yoctoNEAR integer as human NEAR.
// Wide integers are decimal strings in and out — you never touch BigInt.
const yocto = "1500000000000000000000000";
near.print(near.utils.formatNearAmount(yocto)); // "1.5"
```
## How do I sign a gasless delegate transaction without a wallet?
- ID: `sign-delegate-local`
- API: `near.signDelegate`
- Service: `rpc`
- Returns: `{ delegateAction, signature, signatureBytes, borshBase64 }`
- Network: `mainnet`
- Auth: `local-key`
- Summary: Sign a NEP-366 delegate action with a local key so a relayer can broadcast it and pay the gas — the meta-transaction path for servers and agents.
- Output keys: `delegateAction.senderId`, `delegateAction.nonce`, `delegateAction.maxBlockHeight`, `signature`, `borshBase64`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this to build gasless / meta-transactions from a server or agent that holds a key but shouldn't pay gas.
- Use nearWallet.signDelegateActions when a browser wallet holds the key, or near.sendTx to sign and pay yourself.
Response notes:
- near.signDelegate signs locally — it never opens a wallet. The sender's nonce comes from its access key; maxBlockHeight defaults to the final block height plus blockHeightTtl (600).
- nonce and maxBlockHeight are returned as decimal strings; borshBase64 is the NEP-366 SignedDelegate a relayer transports.
- Hand the result to near.relayDelegate (or any relayer) to broadcast — the relayer's full-access key pays the gas, not the sender.
- A WALLET-signed delegate (nearWallet.signDelegateActions → borshSerializedBase64) relays the same way: pass it as near.relayDelegate({ signedDelegate }), or normalize it first with near.utils.parseSignedDelegate. Both signers converge on the same { delegateAction, signature } shape.
Follow-ups:
- Broadcast the signed delegate with near.relayDelegate({ delegateAction, signature, relayerSigner, relayerId }).
- Preview the wrapped actions first with near.explain.tx.
Related recipes:
- `sign-delegate-actions`
- `explain-transaction`
- `function-call`
Example inputs:
```json
{
"receiverId": "guest-book.near",
"actions": [
{
"type": "FunctionCall",
"methodName": "add_message",
"args": {
"text": "gasless hello"
},
"gas": "30 Tgas",
"deposit": "0"
}
],
"blockHeightTtl": 600
}
```
### Terminal
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
node -e "$(curl -fsSL https://js.fastnear.com/agents.js)" <<'EOF'
// Sign a NEP-366 delegate action with a local key — no wallet. A relayer
// broadcasts it and pays the gas. Requires a signed-in local key
// (near.config + near.state) or an explicit { signer, signerId }.
const signed = await near.signDelegate({
receiverId: "guest-book.near",
actions: [
near.actions.functionCall({
methodName: "add_message",
args: { text: "gasless hello" },
gas: "30 Tgas",
deposit: "0",
}),
],
blockHeightTtl: 600,
});
// nonce and maxBlockHeight come back as decimal strings; borshBase64 is what
// a relayer transports. Hand it to near.relayDelegate (or any relayer).
near.print(signed.delegateAction);
EOF
```
### Browser Global
```js
// Sign a NEP-366 delegate action with a local key — no wallet. A relayer
// broadcasts it and pays the gas. Requires a signed-in local key
// (near.config + near.state) or an explicit { signer, signerId }.
const signed = await near.signDelegate({
receiverId: "guest-book.near",
actions: [
near.actions.functionCall({
methodName: "add_message",
args: { text: "gasless hello" },
gas: "30 Tgas",
deposit: "0",
}),
],
blockHeightTtl: 600,
});
// nonce and maxBlockHeight come back as decimal strings; borshBase64 is what
// a relayer transports. Hand it to near.relayDelegate (or any relayer).
near.print(signed.delegateAction);
```
### ESM
```js
import * as near from "@fastnear/api";
near.config({ apiKey: process.env.FASTNEAR_API_KEY || undefined });
// Sign a NEP-366 delegate action with a local key — no wallet. A relayer
// broadcasts it and pays the gas. Requires a signed-in local key
// (near.config + near.state) or an explicit { signer, signerId }.
const signed = await near.signDelegate({
receiverId: "guest-book.near",
actions: [
near.actions.functionCall({
methodName: "add_message",
args: { text: "gasless hello" },
gas: "30 Tgas",
deposit: "0",
}),
],
blockHeightTtl: 600,
});
// nonce and maxBlockHeight come back as decimal strings; borshBase64 is what
// a relayer transports. Hand it to near.relayDelegate (or any relayer).
near.print(signed.delegateAction);
```
## How do I create and fund a new testnet account?
- ID: `create-testnet-account`
- API: `near.createFundedTestnetAccount`
- Service: `rpc`
- Returns: `{ account_id?: string }`
- Network: `testnet`
- Auth: `none`
- Summary: Generate a key and create + fund a fresh testnet account through the NEAR testnet helper faucet — the common agent onboarding step. Testnet only.
- Output keys: `account_id`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this for the 'make me a testnet account' onboarding step in an agent or script.
- For an existing account, add a key instead of creating one; for mainnet, fund the account another way.
Response notes:
- near.createFundedTestnetAccount is testnet-only — it POSTs to the NEAR testnet helper faucet; there is no mainnet equivalent.
- Generate the key with near.utils.privateKeyFromRandom + near.utils.publicKeyFromPrivate, or recover one from a seed phrase (see account-from-seed-phrase).
- After creation, persist the private key with near.state.updateAccountState so near.sendTx signs locally for that account (@fastnear/api 2.1.1+). A full-access key signs any action; a slot that also sets accessKeyContractId is treated as a function-call key and only signs zero-deposit calls to that contract.
- Account state is keyed per network and the default active network is mainnet, so pass "testnet" as the second argument to updateAccountState and network: "testnet" to sendTx — otherwise the testnet key is written to the mainnet slot and the send signs against mainnet RPC for an account that does not exist there.
Follow-ups:
- Sign a transaction locally with the new key via near.sendTx.
- Derive a recoverable key from a seed phrase with account-from-seed-phrase.
Related recipes:
- `account-from-seed-phrase`
- `function-call`
- `explain-transaction`
Example inputs:
```json
{
"newAccountId": "my-agent.testnet"
}
```
### Terminal
```bash
# Assumes FASTNEAR_API_KEY is already set in your shell.
node -e "$(curl -fsSL https://js.fastnear.com/agents.js)" <<'EOF'
// Make a key, then create + fund a fresh testnet account via the faucet.
const privateKey = near.utils.privateKeyFromRandom();
const publicKey = near.utils.publicKeyFromPrivate(privateKey);
const result = await near.createFundedTestnetAccount({
newAccountId: "my-agent.testnet",
publicKey,
});
// Account state is keyed per network and the default is mainnet, so pass
// "testnet" explicitly — otherwise the testnet key lands in the mainnet
// slot. Then near.sendTx signs locally from here on, no wallet, no popup:
// await near.sendTx({ network: "testnet", receiverId, actions: [near.actions.transfer(cu("0.1 NEAR"))] });
near.state.updateAccountState({ accountId: "my-agent.testnet", privateKey }, "testnet");
near.print(result);
EOF
```
### Browser Global
```js
// Make a key, then create + fund a fresh testnet account via the faucet.
const privateKey = near.utils.privateKeyFromRandom();
const publicKey = near.utils.publicKeyFromPrivate(privateKey);
const result = await near.createFundedTestnetAccount({
newAccountId: "my-agent.testnet",
publicKey,
});
// Account state is keyed per network and the default is mainnet, so pass
// "testnet" explicitly — otherwise the testnet key lands in the mainnet
// slot. Then near.sendTx signs locally from here on, no wallet, no popup:
// await near.sendTx({ network: "testnet", receiverId, actions: [near.actions.transfer(cu("0.1 NEAR"))] });
near.state.updateAccountState({ accountId: "my-agent.testnet", privateKey }, "testnet");
near.print(result);
```
### ESM
```js
import * as near from "@fastnear/api";
near.config({ apiKey: process.env.FASTNEAR_API_KEY || undefined });
// Make a key, then create + fund a fresh testnet account via the faucet.
const privateKey = near.utils.privateKeyFromRandom();
const publicKey = near.utils.publicKeyFromPrivate(privateKey);
const result = await near.createFundedTestnetAccount({
newAccountId: "my-agent.testnet",
publicKey,
});
// Account state is keyed per network and the default is mainnet, so pass
// "testnet" explicitly — otherwise the testnet key lands in the mainnet
// slot. Then near.sendTx signs locally from here on, no wallet, no popup:
// await near.sendTx({ network: "testnet", receiverId, actions: [near.actions.transfer(cu("0.1 NEAR"))] });
near.state.updateAccountState({ accountId: "my-agent.testnet", privateKey }, "testnet");
near.print(result);
```
## How do I create or recover a key from a seed phrase?
- ID: `account-from-seed-phrase`
- API: `generateSeedPhrase`
- Service: `api`
- Returns: `{ seedPhrase, publicKey, privateKey }`
- Network: `mainnet`
- Auth: `local-key`
- Summary: Generate a BIP-39 seed phrase and its NEAR key, or recover the key from an existing phrase, with @fastnear/seed-phrase — byte-identical to near-cli.
- Output keys: `seedPhrase`, `publicKey`, `privateKey`
- Pagination: none; request fields: none; response fields: none; filters must stay stable: no
Choose this when:
- Choose this to onboard or recover an account key from a human-writable phrase.
- Use near.utils.privateKeyFromRandom when you don't need a recovery phrase.
Response notes:
- @fastnear/seed-phrase is a separate package (not on the near global) so the bip39 wordlist never bloats @fastnear/api; load it as the NearSeedPhrase global or import it in ESM/Node.
- Derivation matches near-seed-phrase / near-cli (SLIP-0010 ed25519 at m/44'/397'/0'), so a phrase recovers the same key across every NEAR tool.
- generateSeedPhrase(256) makes a 24-word phrase; hand both accountId and privateKey to near.state.updateAccountState and near.sendTx signs locally with it (@fastnear/api 2.1.1+) — a slot holding a key but no accountId has nobody to sign as and throws Must sign in. Or pass near.utils.signerFromPrivateKey(privateKey) with a matching signerId to sign without touching stored state.
Follow-ups:
- Create + fund a testnet account for the derived key with create-testnet-account.
- Sign a transaction locally with near.sendTx once the key is in account state.
Related recipes:
- `create-testnet-account`
- `sign-delegate-local`
- `function-call`
Example inputs:
```json
{
"seedPhrase": "shoot island position soft burden budget tooth cruel issue economy destroy above"
}
```
### Browser Global
```js
// Load @fastnear/seed-phrase (the NearSeedPhrase global) next to near.js.
// Create a fresh key pair and its 12-word recovery phrase.
const { seedPhrase, publicKey, privateKey } = NearSeedPhrase.generateSeedPhrase();
// Recover the exact same keys later — byte-identical to near-cli / near-seed-phrase.
const recovered = NearSeedPhrase.parseSeedPhrase(seedPhrase);
// Store the recovered full-access key; near.sendTx signs locally from here on.
near.state.updateAccountState({ accountId: "you.near", privateKey: recovered.privateKey });
near.print({ seedPhrase, publicKey });
```
### ESM
```js
import { generateSeedPhrase, parseSeedPhrase } from "@fastnear/seed-phrase";
import * as near from "@fastnear/api";
// Create a fresh key pair and its 12-word recovery phrase.
const { seedPhrase, publicKey, privateKey } = generateSeedPhrase();
// Recover the exact same keys later — byte-identical to near-cli / near-seed-phrase.
const recovered = parseSeedPhrase(seedPhrase);
near.state.updateAccountState({ accountId: "you.near", privateKey: recovered.privateKey });
near.print({ seedPhrase, publicKey });
```
## Explain surface
### near.explain.action
Normalize one action into a stable JSON summary.
```json
{
"kind": "action",
"type": "FunctionCall",
"methodName": "draw",
"gas": "100000000000000",
"deposit": "0",
"args": {
"pixels": [
{
"x": 10,
"y": 20,
"color": 65280
}
]
},
"argsBase64": null,
"params": {
"methodName": "draw",
"gas": "100000000000000",
"deposit": "0",
"args": {
"pixels": [
{
"x": 10,
"y": 20,
"color": 65280
}
]
},
"argsBase64": null
}
}
```
### near.explain.tx
Summarize a signer, receiver, and action list into stable JSON.
```json
{
"kind": "transaction",
"signerId": "root.near",
"receiverId": "berryclub.ek.near",
"actionCount": 1,
"actions": [
{
"kind": "action",
"type": "FunctionCall",
"methodName": "draw",
"gas": "100000000000000",
"deposit": "0",
"args": {
"pixels": [
{
"x": 10,
"y": 20,
"color": 65280
}
]
},
"argsBase64": null,
"params": {
"methodName": "draw",
"gas": "100000000000000",
"deposit": "0",
"args": {
"pixels": [
{
"x": 10,
"y": 20,
"color": 65280
}
]
},
"argsBase64": null
}
}
]
}
```
### near.explain.error
Turn thrown RPC, wallet, or transport failures into a predictable JSON object.
```json
{
"kind": "rpc_error",
"code": -32000,
"name": "FastNearError",
"message": "Server error",
"data": {
"name": "HANDLER_ERROR"
},
"retryable": true
}
```