Skip to content

NEAR

NEAR is the “user-owned AI” chain (its co-founder co-authored the Transformer paper), with both Circle USDC and Tether USDT native on-chain. Name chain: 'near' and the driver auto-mounts on first use — a pure-EVM install never downloads its library.

NEAR is unusual in PipRail: it uses both proof templates. Native NEAR is digest-bound (the easy, zero-setup path); the NEP-141 token path is memo-bound and needs a one-time storage_deposit. Both are covered below.

The NEAR library is an optional peer, lazy-loaded the first time you name chain: 'near':

Terminal window
npm install near-api-js

A NEAR wallet is { accountId, privateKey } — NEAR signing needs both an account id and an ed25519:… secret key (not just a private key). The presence of accountId is what tells the SDK this is a NEAR wallet.

import { PipRailClient } from '@piprail/sdk'
const client = new PipRailClient({
wallet: { accountId: 'agent.near', privateKey: process.env.AGENT_KEY }, // ed25519:… secret
chain: 'near',
})

payTo is a NEAR account id — a named account like merchant.near, or a 64-hex implicit account. See Wallets by family for every family’s shape.

Name a token by symbol, 'native', or a custom NEP-141 contract:

tokenWhat it is
'native'Native NEAR (24 decimals). Zero-setup — digest-bound, no storage_deposit.
'USDC'Circle’s native USDC (17208628…36133a1, 6dp) — not the bridged …factory.bridge.near (USDC.e).
'USDT'Tether’s native USDt (usdt.tether-token.near, 6dp).
{ contractId, decimals }Any other NEP-141 token, by contract account id.
import { requirePayment } from '@piprail/sdk'
// Express/Connect middleware that turns this route paid-only:
requirePayment({ chain: 'near', token: 'USDC', amount: '0.10', payTo: 'merchant.near' })

NEAR is the volatile gas coin, so for stable pricing pay in USDC/USDT; for no-setup flows, native NEAR is ideal.

token: 'native' pays in NEAR via a plain Transfer, digest-bound like EVM/Solana/Sui: the proof is <accountId>:<txHash>, verified by tx hash + a recency window + the gate’s single-use proof set. Native needs no storage_deposit and a transfer even creates a fresh implicit recipient — there is nothing to register first.

requirePayment({ chain: 'near', token: 'native', amount: '0.10', payTo: 'merchant.near' })

Tokens need storage_deposit (the receive prerequisite)

Section titled “Tokens need storage_deposit (the receive prerequisite)”

Before an account can receive a NEP-141 token it must be storage-registered on that exact token contract (NEP-145) — a one-time ~0.00125 NEAR call, per account per token. Both the merchant (payTo) and the payer must be registered, or the payer’s ft_transfer panics.

planPayment() surfaces an unregistered recipient as a RECIPIENT_NOT_READY blocker before you spend, and a payment to an unready recipient raises a RecipientNotReadyError:

const url = 'https://api.example.com/report'
const plan = await client.planPayment(url) // → PaymentPlan | null (null when not 402-gated)
if (!plan) {
await client.fetch(url) // not payment-gated — just fetch it
} else if (plan.payable) {
await client.fetch(url) // safe — we checked
} else {
console.log(plan.fundingHint) // e.g. "recipient isn't registered on usdt.tether-token.near"
}

The payer needs a little NEAR for gas either way — native or token.

client.fetch(url) pays the cheapest settleable rail. If the wallet or recipient isn’t ready it throws a typed PipRailError — branch on the stable .code rather than the message. On NEAR the two you’ll meet are RECIPIENT_NOT_READY (the payTo account isn’t storage_deposit-registered on the token) and INSUFFICIENT_FUNDS (the payer is short on the token or on NEAR for gas):

import {
RecipientNotReadyError,
InsufficientFundsError,
} from '@piprail/sdk'
try {
const res = await client.fetch(url)
// → a normal Response once the proof verifies (200 + the gated resource)
} catch (err) {
if (err instanceof RecipientNotReadyError) {
// fix the RECIPIENT: storage_deposit-register payTo on the token (~0.00125 NEAR)
console.error('recipient not ready:', err.message)
} else if (err instanceof InsufficientFundsError) {
// fix the PAYER: top up the token, or add NEAR for gas
console.error('payer is short:', err.message)
} else {
throw err
}
}

NEAR is the one family that uses both proof templates:

AssetTemplateHow it’s bound
Native NEARB — digest-boundproof <accountId>:<txHash>, verified by tx hash + recency + single-use set
NEP-141 tokensA — memo-boundthe challenge nonce rides in the ft_transfer memo

NEAR has no account-history RPC, so the token path verifies by tx hash and only trusts an ft_transfer event emitted by the real token contract — verify() re-derives every checked field from the trusted accept, never the client-supplied ref. See Replay protection for the single-use proof set.