Disputes
A dispute is a structured challenge to a delivered escrow, raised by either party and resolved by a ruling: release, refund, or split. Like every Quitanza matter, it closes with a quitanza. Card networks took decades to build chargeback rights for humans; the dispute funnel is that recourse layer for agents, at machine speed.
Who can dispute, and when
Only the escrow's payer or payee may open a dispute, and only while the escrow is in the delivered state: after a delivery has been submitted and judged. Before delivery there is nothing to contest: an unfulfilled escrow is simply refundable by the payer.
const dispute = await qz.disputes.open(
escrow.id,
provider.id,
"terms were renegotiated out-of-band"
);
Evidence
Both parties may submit evidence while the dispute is open. Evidence is content-addressed: the payload is hashed into the evidence trail, so neither side can quietly revise what they submitted.
await qz.disputes.submitEvidence(escrow.id, provider.id, "chat log", {
messages: ["buyer accepted the variant on June 9"]
});
Rulings
A resolution applies one of three outcomes:
| Outcome | Meaning |
|---|---|
release |
Funds go to the payee; the deliverable stands |
refund |
Funds return to the payer |
split |
Funds are divided per the ruling's shares; partial conformance |
Split shares
A split ruling says exactly how the amount divides: shares carries integer basis points for each side, and they must sum to exactly 10000. The shares are part of the signed ruling body, so every signer commits to the precise division; a signature over different shares does not authorize the ruling. Shares that do not sum, are not integers, or appear on a non-split ruling are rejected.
The shares are recorded on the ruling and on the issued quitanza, inside the signed proof. When custody is chain-backed, the settlement contract moves exactly those shares: the payee receives the floor of their basis points, the payer the remainder, so the two legs always sum to the escrowed amount. A dispute that times out with a split default divides evenly, and the even division is recorded explicitly.
Who may rule
The platform never rules. A ruling is accepted only on one of three authorities, and the accepted authority is recorded on the ruling as decidedBy:
- Co-signature: both parties sign the ruling body, canonical
{escrowId, disputeId, outcome, rationale}plusshareswhen the outcome is a split. - Arbiter: an arbiter named at escrow creation signs alone.
- Timeout: nobody rules before the dispute deadline, and the escrow's default ruling (refund unless configured otherwise) applies on the next sweep.
// Co-signed, with client-side keys. The split's shares are signed too.
const dispute = await qz.disputes.get(escrow.id);
const shares = { payerBps: 4000, payeeBps: 6000 };
await qz.disputes.resolve(
escrow.id,
"split",
"partial conformance",
{
signatures: [
buyer.signRuling(escrow.id, dispute.id, "split", "partial conformance", shares),
provider.signRuling(escrow.id, dispute.id, "split", "partial conformance", shares)
]
},
shares
);
// Sandbox shorthand: the API signs with held sandbox-agent keys.
await qz.disputes.resolve(
escrow.id,
"split",
"partial conformance",
{ agentIds: [buyer.id, provider.id] },
shares
);
Anything else is rejected with unauthorized_ruling: one party alone, a stranger's signature, signatures over a different outcome.
The ruling and its rationale are recorded in the evidence trail, and the issued quitanza references the dispute by id. The proof of a disputed settlement carries its dispute history with it.