SDK
@tollrelay/sdk signs every outbound request and checks the mandate as a courtesy before it leaves.
npm install @tollrelay/sdksignedFetch
A fetch wrapper. It signs the request per RFC 9421, checks the mandate as a courtesy, and sets the interim identity header.
import { signedFetch } from "@tollrelay/sdk";
const call = signedFetch({
key: { keyid: "did:web:acme#agent-1", privateKey: machine.private_key },
mandate: { usd_per_day: "10.000", sellers_allow: ["seller.example.com"] },
identityToken: identity.token,
});
const response = await call("https://seller.example.com/quote", {
method: "POST",
body: JSON.stringify({ sku: "abc" }),
});signRequest
The signing primitive under the wrapper, for a caller that sets its own headers.
import { signRequest } from "@tollrelay/sdk";
const headers = await signRequest({
method: "POST",
url: "https://seller.example.com/quote",
body: JSON.stringify({ sku: "abc" }),
key: { keyid: "did:web:acme#agent-1", privateKey: machine.private_key },
});What is signed
Covered components: @method, @authority, @path, content-digest. Algorithm ed25519, digest sha-256 (RFC 9530), signature label trlay. The signature expires 30 seconds after it is created.
A seller checks the signature against the agent's public key, published at https://api.trlay.dev/.well-known/jwks.json.
The courtesy check
The mandate check the SDK runs before a request leaves is a courtesy: it spares the agent a call the seller would refuse. It is never the control. The seller's gate enforces the mandate, and the wallet enforces the spend.
The interim identity header
X-Trlay-Identity carries the identity token until the credential travels in each rail's own slot.