HashAnchor Guide

Settling device-signed payments

The same SDK carries device-signed stablecoin authorizations to an x402 V2 settlement endpoint on EVM networks, via Circle Gateway and USDC. This path needs no API key.

The payer's key never reaches HashAnchor#

The device signs — with BoAT MER, for example. The SDK keeps the signed fields verbatim and relays them. HashAnchor holds no key, connects to no RPC node and pays no gas.

settle.mjs
import { HashAnchor } from "@tlay/hashanchor-client";

const ha = new HashAnchor();              // settle is a public endpoint
const results = await ha.settle({
  sid: "stream-1",
  batchIdx: 0,
  network: "eip155:5042002",              // CAIP-2, always explicit
  proofs: [{
    sig: "0x…", from: "0x…", to: "0x…",
    value: "10",                          // atomic units, as a string
    validAfter: 1718200000, validBefore: 1718804900,
    nonce: "0x…",                         // 32 bytes, as a string
    slice_id: 0,
  }],
});
one result per proof, in order
[ { "success": true, "payer": "0x…", "transaction": "…",
    "network": "eip155:5042002", "chainId": 5042002 } ]

Field types#

FieldSDK acceptsOn the wireNotes
valuestring onlystringAtomic units. A JavaScript number loses precision and the signature recovers to the wrong payer.
noncestring onlystring0x + 64 hex. Opaque; never a number.
validAfter, validBeforenumber or stringstringThe SDK stringifies these two for you.
sig, from, tostringstringCarried verbatim.
slice_idnumber, optional—Client-side idempotency only; not signed.

When a payment is refused#

settle() does not throw for a rejected payment. It returns one result per proof, so one failure never sinks the batch. Read every result.

OutcomeLooks likeSafe to retry?
Settledsuccess: true with transaction—
Malformed request (HTTP 400)success: false, reason describes the requestYes, after fixing it. Nothing was submitted.
Provider rejection (HTTP 402), e.g. insufficient_balancesuccess: false with the provider's reasonOnly after fixing the stated cause.
nonce_already_usedsuccess: falseNo — ambiguous.
Transport faultsuccess: false, the transport errorNo, not blindly. Reconcile first.
Careful

It proves the authorization's nonce was consumed — not by which settlement, and not that it was yours. Reconcile network, asset, payer, payee and amount against the provider or the chain before recording it as a prior success. The same goes for any timeout.

Before you build a signer#

Read the settle envelope and the EIP-712 Gateway-domain guide. The domain is the most common source of signatures that verify locally and fail remotely. Confirm a network with the settlement provider before building on it — that the SDK can address a network does not mean the provider accepts it today.