Require a receipt in one endpoint.
No receipt, no irreversible action. Make your service refuse an irreversible call unless a valid authorization receipt rides with it. The caller gets a 402 that says exactly what to bring; a well-behaved agent obtains a receipt and retries; you verify it offline — no EMILIA backend, fail-closed.
Wrap the irreversible endpoint.
Framework-agnostic Express-style middleware. Install npm i @emilia-protocol/require-receipt, then gate the one route that does something it can’t take back:
import { requireEmiliaReceipt } from '@emilia-protocol/require-receipt';
app.post(
'/release-payment',
requireEmiliaReceipt({
trustedKeys: [process.env.EMILIA_ISSUER_PUBKEY], // base64url SPKI you trust
action: 'payment.release',
maxAgeSec: 900,
}),
(req, res) => {
// Only reached if a fresh, untampered, action-bound receipt from a
// trusted issuer was presented. req.emiliaReceipt holds the verified claim.
res.json({ released: true, receipt: req.emiliaReceipt.receipt_id });
},
);The agent self-serves the proof.
No receipt? The service answers 402 and tells the agent exactly what to bring — like a browser handling 401. A well-behaved agent obtains a receipt and retries, no human in the support loop:
→ POST /release-payment (no receipt)
← 402 EMILIA Receipt Required
WWW-Authenticate: EMILIA realm="agent-actions", action="payment.release"
{ required: { action: "payment.release",
header: "X-EMILIA-Receipt: base64(...)" } }
→ POST /release-payment X-EMILIA-Receipt: base64(<receipt>)
← 200 { released: true }Run the whole loop end to end from a clean checkout: node examples/402-loop.mjs · or see a receipt issued + verified offline in 30s: npx @emilia-protocol/crash-test
Check it yourself — no one’s word for it.
The same package exports verifyEmiliaReceipt(doc, opts) for programmatic checks, and any receipt verifies from the terminal with npx @emilia-protocol/verify receipt.json — asymmetric, offline, open-source (Apache-2.0). For MCP servers, @emilia-protocol/mcp-guard applies the same demand hook to a tool-call handler.
Because it converts "trust me, a human approved this" into portable, offline-checkable evidence — and it lets well-behaved agents self-serve authorization with no human in the support loop. 402 deliberately rides the same "challenge-to-transact" rail as agent-commerce conventions (x402 / AP2).
No. Verification is offline and asymmetric: you hold the issuer public keys you trust and check the receipt locally. Nothing calls home. The middleware fails closed — no valid receipt, no irreversible action.
Use @emilia-protocol/mcp-guard: it wraps an MCP tool-call handler so irreversible tool calls route through signoff and emit a receipt while everything else passes through — the same demand hook, returning a 402-style refusal.
The middleware fails closed: an absent, expired, tampered, or untrusted-issuer receipt is refused. Offline verification proves the receipt is authentic, intact, and bound to the exact action; it does not assert the decision was correct or identity beyond the enrollment layer. Open standard (Apache-2.0), IETF Internet-Drafts.