SDK

@tollrelay/sdk signs every outbound request and checks the mandate as a courtesy before it leaves.

npm install @tollrelay/sdk

signedFetch

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.