Concepts
Receipts
Every allowed action carries a short signed token that says which agent was allowed to do what, under which mandate, and whether a person approved it. Anyone can check it, online or offline.
A receipt travels with the action. The agent can hand it to a merchant; the card rail spends it; an auditor can check it years later against the ledger.
#What a receipt is
A compact JWS, signed with Ed25519. The header:
{ "alg": "EdDSA", "kid": "k_2026_09", "typ": "assay-receipt+jwt" }The claims:
{
"iss": "https://immiscible.fly.dev",
"sub": "agt_4f2c91a7",
"act": "act_7Qm2c1f0",
"typ": "payment",
"amt": 4200,
"cur": "GBP",
"mer": "grocer.example",
"mdt": "mdt_91c3e0b2",
"hum": false,
"iat": 1790444901,
"exp": 1790445201,
"jti": "r_2b7e4c"
}| Claim | Meaning |
|---|---|
iss | the Immiscible deployment that issued it |
sub | the agent |
act | the action this receipt allows |
typ | the action type, for example payment |
amt, cur | the authorised amount in minor units, and its currency |
mer | the merchant domain it was authorised for |
mdt | the mandate it was allowed under |
hum | true when a person approved this specific action, not only the mandate |
iat, exp | issued and expiry times; a receipt is valid for five minutes |
jti | a unique id; a receipt is single use |
A receipt names no person. It carries pseudonymous ids only the issuing workspace can resolve.
#Verifying online
No account and no key are needed:
curl -X POST "https://immiscible.fly.dev/v1/verify" \
-H "content-type: application/json" \
-d '{ "receipt": "eyJhbGciOiJFZERTQSIs..." }'const res = await fetch('https://immiscible.fly.dev/v1/verify', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ receipt }),
});
const { valid, claims, reason, replayed } = await res.json();import requests
res = requests.post("https://immiscible.fly.dev/v1/verify", json={"receipt": receipt})
result = res.json(){
"valid": true,
"claims": {
"iss": "https://immiscible.fly.dev", "sub": "agt_4f2c91a7", "act": "act_7Qm2c1f0", "typ": "payment",
"amt": 4200, "cur": "GBP", "mer": "ocado.com", "mdt": "mdt_91c3e0b2", "hum": false,
"iat": 1791209943, "exp": 1791210243, "jti": "w0JBpe6jFQ6NA-RbE0MrgUDQ"
}
}A valid receipt has no reason. Online verification marks the receipt as seen, so a second check of the same receipt returns "valid": false with "replayed": true. valid: false always comes with a reason in plain English: a bad signature, an unknown key, an expired receipt ("expired": true), a wrong issuer, a withdrawn receipt ("revoked": true), a charge it does not cover ("mismatch": true, when you send expect) or a replay.
#Verifying offline
The public keys are a JWKS at https://immiscible.fly.dev/.well-known/immiscible-keys.json. Fetch it, keep it, and check receipts without calling Immiscible at all. The whole verifier in Node 22, using only node:crypto, is in verifying offline.
Offline verification cannot see replays. If single use matters to you (for payments it should), keep the jti values you have seen in the last five minutes, or call /v1/verify once per order.
#What a receipt proves, and what it does not
It proves that Immiscible, at iat, allowed this agent this action under a mandate a person created, and, when hum is true, that a signed-in person approved this action specifically.
It does not prove who the person is, that a payment will clear, or that the goods are what the agent described. It is not a payment guarantee and it does not move chargeback liability. It is evidence of authority, to sit alongside the card network’s own checks.
#Receipts at the card
With the card rail connected, the receipt is not only evidence, it is the key: a card bound to an agent authorises only against an unused receipt for the same payee and currency that covers the amount, and the authorisation uses it up.
#With agent payment protocols
Agent payment protocols are converging on the same idea, a signed statement of what a person authorised: Google’s Agent Payments Protocol (AP2), OpenAI and Stripe’s Agentic Commerce Protocol (ACP), Visa’s Trusted Agent Protocol and Mastercard’s Agent Pay. An Immiscible receipt is designed to travel alongside those, as an extra field carrying the independent record of what the person’s own rules allowed. We do not claim certification by, or membership of, any of these schemes.