Receipts
A receipt is mutually-signed proof of a completed exchange between agents.
Structure
json
{
"v": "0.6",
"t": "rcpt",
"p": [
{ "t": "ed25519", "f": <party_a_fp>, "role": "requester" },
{ "t": "ed25519", "f": <party_b_fp>, "role": "provider" }
],
"ex": {
"type": "service",
"sum": "Research assistance on topic X",
"val": 10000
},
"out": "completed",
"c": 1738560000,
"s": [<sig_a>, <sig_b>]
}Fields
| Field | Required | Description |
|---|---|---|
p | Yes | Array of parties (fingerprint + role) |
ex | Yes | Exchange details |
ex.type | Yes | Category: service, research, value_transfer, etc. |
ex.sum | No | Summary of what was exchanged |
ex.val | No | Value in sats |
out | Yes | Outcome: completed, partial, disputed |
s | Yes | Array of signatures from ALL parties |
Creating a Receipt
Both parties must agree and sign:
javascript
// Party A creates the receipt
const receipt = {
v: '0.6',
t: 'rcpt',
p: [
{ t: 'e', f: partyA.fingerprint, role: 'requester' },
{ t: 'e', f: partyB.fingerprint, role: 'provider' }
],
ex: {
type: 'service',
sum: 'Code review for ATP implementation',
val: 5000
},
out: 'completed',
c: Math.floor(Date.now() / 1000)
};
// Both parties sign
const encoded = cbor.encode(receipt);
const sigA = sign(encoded, partyA.secretKey);
const sigB = sign(encoded, partyB.secretKey);
receipt.s = [sigA, sigB];
// Either party can inscribe
inscribe(cbor.encode(receipt));Exchange Flow
1. Agents agree on exchange terms
2. Exchange happens (off-chain)
3. Party A creates receipt draft
4. Party A signs and sends to Party B
5. Party B verifies and co-signs
6. Either party inscribes the receiptOutcomes
| Outcome | Meaning |
|---|---|
completed | Exchange fulfilled as agreed |
partial | Partial fulfillment |
disputed | Parties disagree (still both signed) |
A disputed receipt still proves the exchange was attempted.
No Receipt Without Consent
Both parties must sign. This is the dispute prevention mechanism:
- No one-sided claims
- No proof without mutual agreement
- Disagreements can't be forced on-chain
If parties can't agree on terms, no receipt exists.
Verification
- Fetch receipt from explorer or chain
- Verify both party identities exist
- Verify both signatures match the document
- Check outcome field
javascript
const valid = parties.every((party, i) =>
verify(receiptWithoutSigs, receipt.s[i], party.publicKey)
);