Concepts

Receipts

Every paid action produces an Ed25519-signed JSON receipt. Receipts are the unit of trust in the agent web — portable, composable, cryptographically anchored to a specific payment.


What a receipt is

A receipt is a small JSON document, signed by the publisher's service key, that binds together five facts:

  • ·Which action ran (action_id)
  • ·What input was provided (a hash, not the input itself)
  • ·What output was returned (a hash)
  • ·How much was paid, against which Lightning payment hash
  • ·When it completed, signed by which key

Receipts are not stored on Lightning; they live in any database the agent or publisher chooses. Their integrity comes from Ed25519, and their evidentiary value comes from the underlying paid invoice (which Lightning anchors to physical bitcoin economics).

Shape

receipt
json
{
  "receipt_id":      "rcpt_a1b2c3d4e5f6",
  "action_id":       "ask.site_agent",
  "amount_msats":    3000,
  "payment_hash":    "9bb6b97be7d50917…",
  "input_hash":      "e467438db080543a…",
  "output_hash":     "8fa4e1c1e000f76d…",
  "completed_at":    "2026-04-26T10:22:01.412Z",
  "service_pubkey":  "302a300506032b6570032100…",
  "signature":       "83ac15b707b63dbc…"
}

Signing

The publisher computes the Ed25519 signature over the canonical JSON encoding of every field except signature itself, sorted by key, no insignificant whitespace. The signature is emitted as lowercase hex.

signing — Node.js
ts
const core = {
  receipt_id, action_id, amount_msats, payment_hash,
  input_hash, output_hash, completed_at, service_pubkey,
};
const msg = Buffer.from(canonicalJSON(core));
const sig = crypto.sign(null, msg, privateKey).toString("hex");
return { ...core, signature: sig };

Verifying

verifying — Node.js
ts
function verifyReceipt(r, manifestPubkeyHex) {
  if (r.service_pubkey !== manifestPubkeyHex) return false;
  const { signature, ...core } = r;
  const pub = crypto.createPublicKey({
    key: Buffer.from(r.service_pubkey, "hex"),
    format: "der",
    type: "spki",
  });
  return crypto.verify(null, Buffer.from(canonicalJSON(core)), pub,
                       Buffer.from(signature, "hex"));
}

Verification is fully offline. An agent that has cached the publisher's manifest pubkey can verify any receipt from that publisher without further network access — useful for audit pipelines, reputation aggregators, and offline reasoning.

Receipts → reputation

Receipts power agents402's decentralized reputation system. When the buyer supplies a Nostr pubkey at payment time (the optional buyer_pubkey field), they can later publish a signed feedback event embedding the receipt — provably tying their 0–1 score to a real Lightning payment. See /concepts/reputation.

Local-first by design
agents402 does not require a global reputation graph. Each agent accumulates receipts it has issued or observed, optionally publishes feedback events on Nostr, and computes its own trust scoring policy locally. Receipts are the substrate; the graph is an emergent property of public, signed events.
SignalWhat it tells you
Per-domain receipt countHow active a service is, or how often this agent uses it.
Per-action receipt countWhether the service consistently fulfills a given action type.
Receipt volume over timeAdoption trend, churn signal.
Signed buyer feedbackQuality, in cases where the agent network publishes feedback events.
Receipt freshnessRecency-weighted trust — old receipts decay.
Next
Trust model
Why the model never approves its own spend, and how the agent runtime enforces policy.
agents402.org / 2026
Open protocol · v0.1