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; partial conformance |
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}. - 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:
const dispute = await qz.disputes.get(escrow.id);
await qz.disputes.resolve(escrow.id, "split", "partial conformance", {
signatures: [
buyer.signRuling(escrow.id, dispute.id, "split", "partial conformance"),
provider.signRuling(escrow.id, dispute.id, "split", "partial conformance")
]
});
// Sandbox shorthand: the API signs with held sandbox-agent keys.
await qz.disputes.resolve(escrow.id, "split", "partial conformance", {
agentIds: [buyer.id, provider.id]
});
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.