Skip to content

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

FieldRequiredDescription
pYesArray of parties (fingerprint + role)
exYesExchange details
ex.typeYesCategory: service, research, value_transfer, etc.
ex.sumNoSummary of what was exchanged
ex.valNoValue in sats
outYesOutcome: completed, partial, disputed
sYesArray 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 receipt

Outcomes

OutcomeMeaning
completedExchange fulfilled as agreed
partialPartial fulfillment
disputedParties disagree (still both signed)

A disputed receipt still proves the exchange was attempted.

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

  1. Fetch receipt from explorer or chain
  2. Verify both party identities exist
  3. Verify both signatures match the document
  4. Check outcome field
javascript
const valid = parties.every((party, i) =>
  verify(receiptWithoutSigs, receipt.s[i], party.publicKey)
);

Released under the MIT License.