How it works
Receipts and checking
Every payment ends in a receipt. Anyone can check it.
A receipt is one small signed file. It names the mandate, then holds the rules' answer, the person's yes and what happened at the rail.
- Format
- JSON in one exact order (RFC 8785), so the same receipt always gives the same bytes.
- Signature
- Ed25519, signed by Onbehalf.
- Version
- New receipts are 0.4.0. They also say whether the yes came by passkey or by wallet. From the release that adds charges and credits they are 0.5.0, which also names the partner's own Stripe test account. The Base Sepolia sample is 0.3.0. The Stripe sample is 0.2.0. Receipts name the approver and say how many decimal places the amount uses.
- Outside record
- A Base Sepolia receipt carries the chain id, the transaction id and whether it was final when signed. A Stripe receipt carries the Stripe id. A stand-in receipt says nothing moved.
- Checking it
- Verify checks the signature and every signed field, in your browser. Change one character we signed, and the check fails.
Every field
The receipt format, 0.2.0 to 0.5.0, field by field, as the code defines it. A receipt file has three parts: receiptCore (the signed part), cryptographicProof and anchorProof. Only the first is signed; the other two carry the proof and the timestamp state.
| Field | Holds | Meaning |
|---|---|---|
| schema | one value | Always onbehalf.action-receipt. |
| schemaVersion | one value | 0.2.0 for the Stripe sample; 0.3.0 for receipts made from Oct 7, 2026; 0.4.0 for receipts made from Oct 18, 2026; 0.5.0 from the release that adds charges and credits. |
| receiptId | one value | The receipt's own id, starting rct_. |
| issuedAt | one value | When the receipt was signed. |
| issuer | issuerId keyId | Who signed it and with which key. The key id is derived from the public key. |
| scope | environment coveredRoute coverageClaim | Test or live, the one route Onbehalf covers, and the exact sentence it claims. |
| subject | organizationRef agentRef agentVersion | Whose agent acted, and which version of it. |
| authority | mandateRef mandateVersion mandateDigest activeAtEvaluation activeAtExecution | The mandate the agent acted under, and whether it was active when checked and when the money moved. |
| action | actionId actionVersion actionType targetRef amountMinor currency currencyDecimals? requestDigest | The exact action: type, target, amount in minor units, currency, and a fingerprint of the request. From 0.3.0 the receipt states its own scale: 2 for cents, 6 for USDC units. |
| policy | policyRef policyVersion policyDigest decision reasonCodes evaluatedAt | Which rules ran and what they said: ALLOW, OBSERVE, REQUIRE_APPROVAL or DENY. |
| approval | required decision approverRef bindingDigest decidedAt approverName? undoWindow? confirmation? | Whether a person had to say yes, who did, when, and the digest that locks the yes to this exact action. New in 0.2.0: the approver's name and the undo window (seconds, opened, closed). New in 0.4.0: how the approver confirmed (kind passkey or wallet, the credential id or signer address as ref, and the sentence the receipt shows). |
| execution | provider providerEnvironment operationRef providerObjectRef attemptedAt observedState observedAt observationSources chain? providerAccountRef? | What the rail was asked, its object id, and what it reported: SUCCEEDED, FAILED or UNKNOWN. From 0.5.0 an action on a partner's own Stripe test account names that account (acct_...). From 0.3.0 a payment sent on a chain also carries its chain record: chain id, token, payer, recipient, exact units, the payment fingerprint, the transaction id, the block and whether it was final when signed. |
| evidence | level recordedEventCount evidenceManifestDigest limitations | How far the evidence goes, how many events were recorded, and the limitations in plain words. |
| commitmentNonce | one value | 256 random bits, so the receipt's fingerprint reveals nothing about its contents. |
| Part | Holds | Meaning |
|---|---|---|
| cryptographicProof | canonicalization digestAlgorithm digest signatureAlgorithm signature publicKey publicKeyFingerprint | RFC 8785 canonical JSON, SHA-256, Ed25519. The public key travels with the receipt; the fingerprint is what a trusted key list pins. |
| anchorProof | state reason | NOT_SUBMITTED on every receipt today, with the reason in words. The public timestamp is not built yet. |
Amounts are whole numbers in the smallest unit. A USDC receipt counts units of six decimals: 7500000 is 7.50 USDC. A USD receipt counts cents: 75000 is $750.00. From 0.3.0, the receipt says which. Fields marked ? may be missing.
The five checks
What the Verify page tests, in the order it shows them.
| Check | On screen | What it tests |
|---|---|---|
| Schema | Format is correct | The file has every field the format requires, with the right types, and names a version the checker supports. |
| Digest | Contents match the fingerprint | The signed part is put into RFC 8785 canonical form and hashed with SHA-256. The result must equal the fingerprint in the file. |
| Signature | Signature is genuine | The Ed25519 signature in the file must verify over those exact bytes under the public key the file carries. |
| Issuer | Signed by the configured issuer | The public key's fingerprint, the issuer id and the key id must match the trusted key list. On this site that list holds the hosted Console's key and the keys behind the two samples. The page picks the key by the fingerprint the file carries. |
| Anchor | Public timestamp | A public timestamp of the fingerprint. Not built yet, so this line reads Not yet on every file. |
Each check reads Pass, Fail or Not yet. The result is Valid when every check passes (the public timestamp counts as Not yet today), and Not valid when the contents or the signature no longer match what was signed. A file signed by a key this site does not publish reads as checked but unrecognized, in amber.
Our public keys
- Key id
key_4900f3bfa9088c80- Algorithm
- Ed25519
- Public key
sG2cgnBPZ4GZFksoWQCdRq_pp-1hK4EDw58J8opx4Ro- Fingerprint
sha256:4900f3bfa9088c80b8d21737b3749bbd3a5e6c7a2306dfe407ad012f1aed5870- Issuer
onbehalf-local- Run started
- Oct 5, 2026, 18:55 UTC
- Key id
key_6d24407f745f853d- Algorithm
- Ed25519
- Public key
r7QywjkyCqYhSwPja4_UDFDVTBicP4gu74hsgL6yvUI- Fingerprint
sha256:6d24407f745f853de158346ca7cc2ddd3e4f7e3d8400c52f4126f8ba9cec1d70- Issuer
onbehalf-local- Run started
- Oct 8, 2026, 21:15 UTC
- Key id
key_499f5f7b0ba9030f- Algorithm
- Ed25519
- Public key
NccPn3533fa03zpJiTBte9-Yek1ebeaCd9PZmNWHBzY- Fingerprint
sha256:499f5f7b0ba9030f868c4424491886ad8d0b19a73beb7a579b8821132db1e880- Issuer
onbehalf-test- In use since
- Oct 16, 2026, 00:00 UTC
The hosted Console signs with one long-term key. This site publishes it, with the keys behind the two older samples. The page picks the right one from the file's fingerprint.
The sample receipts
The two records this site publishes, each from a real run: a USDC payment on Base Sepolia, a test network, and a Stripe test-mode refund.
The USDC payment on Base Sepolia
- Receipt id
rct_9DN1SHC04GYA24EGHB7E745BW0, format 0.3.0, issued Oct 8, 2026, 22:41 UTC. - 7.50 USDC payment to recipient
rcp_K95NPNH6C1M6E177B6ZNTD8PX8, address0xEf20F82f5E14CE37101fE100cC6D4EeEd368D0A0; transaction0x1db2082713137d5d01e4f0f69b6825ec9b5725806c475d5e160dfc95f1654b5don Base Sepolia (chain 84532), sent, not final yet, when signed. The Verify page links two public explorers built from those two fields. - Provider usdc_base_sepolia, environment test. Approved by J. Tan.
- Signed by issuer
onbehalf-localwith keykey_6d24407f745f853d, fingerprintsha256:6d24407f745f853de158346ca7cc2ddd3e4f7e3d8400c52f4126f8ba9cec1d70. The issuer id is the development issuer's name; the key belongs to one run, and this site publishes only its public half. - Covered route
usdc_base_sepolia_default; coverage claimgateway_observed. - Covers only the configured Onbehalf gateway route
- Does not prove absence of actions made with other credentials
- Provider is in test mode; no real money moved.
- Base Sepolia is a test network; the USDC on it has no value and no real money moved.
The Stripe test-mode refund
- Receipt id
rct_F9HAGZVJ8ETS17RCYEKWMRDYC8, format 0.2.0, issued Oct 5, 2026, 23:13 UTC. - $750.00 refund of payment
pi_3UNL4QGMJ8LKXHDD078FssyB; the provider's refund id isre_3UNL4QGMJ8LKXHDD00nh0Ter. - Provider stripe, environment test. Approved by J. Tan.
- Signed by issuer
onbehalf-localwith keykey_4900f3bfa9088c80, fingerprintsha256:4900f3bfa9088c80b8d21737b3749bbd3a5e6c7a2306dfe407ad012f1aed5870. The issuer id is the development issuer's name; the key belongs to one run, and this site publishes only its public half. - Covered route
stripe_test_default; coverage claimgateway_observed. - Covers only the configured Onbehalf gateway route
- Does not prove absence of actions made with other credentials
- Provider is in test mode; no real money moved.
J. Tan is a demo approver in a test workspace, not a real person or customer.
Questions? Email hello@getonbehalf.com. We reply within two working days.