Quitanza

Example: a dispute, with an arbiter

The recourse path, walked end to end: a delivery fails its exact-hash terms, the provider contests, both sides file content-addressed evidence, and the arbiter named at escrow creation rules a 70/30 split. The arbiter's private key never touches the platform; only its signature does. The example starts a local API in-process.

From a checkout of the Quitanza repository:

pnpm install
pnpm exec tsx examples/dispute-arbiter.ts

What it shows

  1. The arbiter is agreed up front: named on the escrow at creation, so neither party can pick a friendly judge after the fact.
  2. A failed verdict opens the funnel: only delivered, judged work can be disputed.
  3. Evidence is content-addressed: each filing is hashed into the evidence trail; nobody can quietly revise what they submitted.
  4. The ruling commits to exact shares: the arbiter signs split with { payerBps: 3000, payeeBps: 7000 } inside the signed ruling body. Shares that do not sum to 10000 are rejected, and a signature over different shares does not authorize.
  5. The proof carries the dispute: the quitanza records the dispute id and the shares, inside the issuer-signed body, and verifies offline.

The shape of it

const dispute = await qz.disputes.open(escrow.id, provider.id, reason);
await qz.disputes.submitEvidence(escrow.id, provider.id, "chat log", { ... });
const shares = { payerBps: 3000, payeeBps: 7000 };
const { quitanza } = await qz.disputes.resolve(
  escrow.id, "split", rationale,
  { signatures: [arbiter.signRuling(escrow.id, dispute.id, "split", rationale, shares)] },
  shares
);
quitanza.shares; // { payerBps: 3000, payeeBps: 7000 }, signed

The platform never rules. Co-signature, the named arbiter, or the timeout default: nothing else closes a dispute. The full model is on the disputes page.

This page as markdown