Audience: Developers, Data, Support
โOutcomes: Working integrations; clean analytics
Endpoints
POST /api/disputes # open POST /api/disputes/:id/evidence # upload files POST /api/disputes/:id/resolve # admin decision GET /api/disputes?status=Open # list/filter GET /api/disputes/:id # detail
Open (curl)
curl -X POST $API_BASE/api/disputes -b cookies.txt \ -H 'Content-Type: application/json' \ -d '{"orderId":"ord_123","reason":"non_delivery","details":"Due 2025-08-01, nothing submitted."}'
SSE (client)
const es = new EventSource('/api/events/stream', { withCredentials: true }); ['dispute.opened','dispute.evidence.added','dispute.resolved'].forEach(name => { es.addEventListener(name, e => console.log(name, JSON.parse(e.data))); });
Data model (core objects)
Dispute
{ "id":"dsp_456", "orderId":"ord_123", "status":"UnderReview", "reason":"poor_quality", "details":"Typography differs from spec", "openedBy":"usr_17", "openedAt":"2025-08-10T10:21:00Z", "participants":["usr_17","usr_54"], "activityLog":[] }
Evidence
{ "id":"evi_001", "disputeId":"dsp_456", "orgId":"org_123", "files":[{"name":"mockup.png","size":423221,"mime":"image/png","hash":"..."}], "notes":"See contract ยง3.1", "createdAt":"2025-08-10T11:02:00Z" }
Decision
{ "id":"dec_001", "disputeId":"dsp_456", "resolution":"refund_partial", "amount":30000, "notes":"Late by 2 weeks; typography mismatch", "decidedBy":"usr_1", "decidedAt":"2025-08-14T16:00:00Z" }
ReputationLog
{ "id":"rep_abc", "orgId":"org_123", "ts":"2025-08-14T16:01:00Z", "delta":-4.0, "reason":"refund_partial", "decayHalfLifeDays":90, "appliesTo":"seller", "evidenceQualityBonus":0.5 }
QA checklist
SSE connects with credentials; events arrive on state changes
API returns UTC timestamps; clients display local timezone