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.
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,
}],
});[ { "success": true, "payer": "0x…", "transaction": "…",
"network": "eip155:5042002", "chainId": 5042002 } ]Field types#
| Field | SDK accepts | On the wire | Notes |
|---|---|---|---|
value | string only | string | Atomic units. A JavaScript number loses precision and the signature recovers to the wrong payer. |
nonce | string only | string | 0x + 64 hex. Opaque; never a number. |
validAfter, validBefore | number or string | string | The SDK stringifies these two for you. |
sig, from, to | string | string | Carried verbatim. |
slice_id | number, 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.
| Outcome | Looks like | Safe to retry? |
|---|---|---|
| Settled | success: true with transaction | — |
| Malformed request (HTTP 400) | success: false, reason describes the request | Yes, after fixing it. Nothing was submitted. |
Provider rejection (HTTP 402), e.g. insufficient_balance | success: false with the provider's reason | Only after fixing the stated cause. |
nonce_already_used | success: false | No — ambiguous. |
| Transport fault | success: false, the transport error | No, not blindly. Reconcile first. |
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.