NEAR
Introduction
Section titled “Introduction”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.
Install the peer dependency
Section titled “Install the peer dependency”The NEAR library is an optional peer, lazy-loaded the first time you name chain: 'near':
npm install near-api-jsWallet shape
Section titled “Wallet shape”A NEAR wallet is { accountId, key }, where key is an ed25519:… secret key — NEAR signing
needs both an account id and the 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', key: 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.
Supported tokens
Section titled “Supported tokens”Name a token by symbol, 'native', or a custom NEP-141 contract:
token | What 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.
Native NEAR — the zero-setup path
Section titled “Native NEAR — the zero-setup path”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.
When a payment can’t go through
Section titled “When a payment can’t go through”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 }}Proof binding — both templates
Section titled “Proof binding — both templates”NEAR is the one family that uses both proof templates:
| Asset | Template | How it’s bound |
|---|---|---|
| Native NEAR | B — digest-bound | proof <accountId>:<txHash>, verified by tx hash + recency + single-use set |
| NEP-141 tokens | A — memo-bound | the 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.
Standard exact rail — gasless for the buyer via NEP-366 (NEP-141 tokens)
Section titled “Standard exact rail — gasless for the buyer via NEP-366 (NEP-141 tokens)”Beside the default onchain-proof rail, PipRail also speaks the ratified x402 exact scheme for
NEAR (scheme_exact_near.md,
x402 v2). The buyer signs a NEP-366 SignedDelegateAction authorizing exactly one NEP-141
ft_transfer (to payTo, the exact amount, the mandatory 1 yoctoNEAR) with a full-access key —
and never broadcasts it or holds any NEAR. A relayer wraps that delegate in its own outer
transaction, prepays the gas + the yocto, and submits it. The agent (buyer) is completely gasless.
This rail is opt-in and only ever offered for NEP-141 tokens (USDC / USDT, or a custom token
you pass). Native NEAR is not exact-payable — the scheme is defined over ft_transfer — so native
always stays on the zero-setup onchain-proof rail. Defaults are unchanged: an onchain-proof-only
client behaves exactly as before.
Paying (the buyer / agent — gasless)
Section titled “Paying (the buyer / agent — gasless)”Enable 'exact' in schemes and the client builds + signs the SignedDelegateAction for any NEAR
exact rail it’s offered. It spends zero NEAR (the merchant’s relayer pays):
const client = new PipRailClient({ chain: 'near', wallet: { accountId: 'agent.near', key: 'ed25519:…' }, // MUST be a full-access key (see below) schemes: ['onchain-proof', 'exact'],})await client.fetch('https://api.example.com/data') // 402 → signs a delegate (0 NEAR) → 200Receiving (the merchant) — self-settle today
Section titled “Receiving (the merchant) — self-settle today”NEAR exact is self-settled today: the merchant runs a small relayer (a funded NEAR account)
that the gate uses to submit the buyer’s signed delegate. The buyer stays gasless; the merchant’s
relayer pays the sub-cent NEAR network fee to receive — exactly like PipRail’s self-settle on
Solana / Algorand / Aptos. This is the standard, working configuration:
createPaymentGate({ chain: 'near', token: 'USDC', // or 'USDT' — any NEP-141; native is onchain-proof only amount: '0.01', payTo: 'merchant.near', exact: { settle: 'self', relayer: { accountId: 'relayer.near', key: 'ed25519:…' }, // a funded NEAR key that pays settle gas },})The relayer:
- needs a little NEAR for gas (each settle costs ≈ 0.0003 NEAR — well under a cent);
- must not equal the payer (that’s the buyer), but may equal
payTo(the merchant can relay its own incoming payment — NEAR’s outer/inner-transaction split allows it); - should use a dedicated key you can fund + rotate, not your cold treasury key (it’s a hot key the gate signs with on every settle).
Unlike EVM/Solana/Algorand — where the merchant co-signs one slot of the buyer’s transaction —
the NEAR relayer wraps the delegate in a separate outer transaction it fully owns, then waits for
the inner ft_transfer receipt to finish executing across shards before the gate returns 200.
Gas model + the sponsor drain guard
Section titled “Gas model + the sponsor drain guard”| Party | Pays gas? |
|---|---|
| Buyer / agent | No — signs off-chain, holds zero NEAR |
| Merchant relayer (self-settle) | Yes — the sub-cent settle fee + the 1 yoctoNEAR, prepaid on submit |
Because the relayer prepays both the gas and the attached deposit of the delegated call, a hostile
buyer could try to drain it by signing a valid sub-cent transfer with a huge gas or a large
deposit. PipRail’s gate re-derives every field from your trusted rail and refuses the delegate
before the relayer ever signs if the attached deposit ≠ exactly 1 yoctoNEAR or the gas
exceeds 300 TGas (an honest payload uses ~30 TGas). It also re-checks the token contract, payTo,
amount, single-action shape, and expiry against the rail — never the client’s echo.
Storage registration (NEP-145) — required to send AND receive
Section titled “Storage registration (NEP-145) — required to send AND receive”A NEP-141 token only moves between accounts that are storage-registered on that token
(storage_deposit, ≈ 0.00125 NEAR once per account+token). For the exact rail that means both the
buyer (sender) and payTo (recipient) must be registered on the token, or the ft_transfer panics.
Check the recipient with planPayment() /
recipientReady() (planPayment() surfaces the RECIPIENT_NOT_READY blocker; recipientReady()
returns the NOT_REGISTERED reason) before you rely on the rail. Register out of band once; it persists.