Overview

When a cardholder challenges a charge with their bank, the bank opens a dispute (commonly called a chargeback). Truemed’s Disputes API lets API-first merchants list and inspect their disputes, respond with evidence, accept a loss, and receive real-time notifications — all from their own systems, without logging into a Truemed UI.

The Disputes API is in draft. Endpoints are live in the sandbox and stable in shape, but they are not yet listed in the public API Reference and may change before general availability. Build against the sandbox (see Base URLs) and reach out to your Truemed contact before relying on them in production.

Base URLs

EnvironmentBase URL
Sandbox (dev)https://dev-api.truemed.com
Productionhttps://api.truemed.com

Truemed has no separate test-mode API keys: the environment is the mode. Requests to the sandbox host run against test data and are automatically flagged as testing; production runs live. Use the same API key format against whichever host you target, and point test-vs-live webhook subscriptions at different endpoints if you need to separate the two. The examples in these guides use the sandbox host while the API is in draft.

What’s in scope for V1

  • Stripe only. Disputes originate from Stripe-processed charges in V1.
  • Inquiries and chargebacks. Chargebacks are the core case, but pre-chargeback inquiries are surfaced and answerable too: respond to an inquiry with evidence to pre-empt its escalation to a chargeback. Inquiries notify like chargebacks — a surfaced inquiry fires dispute.created/dispute.updated, and if the bank later drops it, the terminal closed state fires dispute.closed too. The one exception is an inquiry already terminal the first time Truemed sees it (opened and closed between deliveries), which fires no webhook (see Webhooks).
  • One-shot evidence. Card disputes are answered once per phase. You compose evidence as a draft, then submit it straight to the processor in a single, final action — there is no back-and-forth with the issuer within a phase.

The canonical model

Every dispute is exposed as a stable, normalized shape, so you integrate against one consistent set of fields. Each dispute carries a Truemed UUID (dispute_id) — always reference disputes by this dispute_id, never by the raw processor ID (processor_dispute_id), which is provided for your own reconciliation only.

State

state is the canonical lifecycle position:

StateMeaning
inquiryPre-chargeback inquiry — surfaced and answerable. Respond with evidence to pre-empt escalation; you cannot accept an inquiry (no funds are at risk yet).
needs_responseA chargeback is open and awaiting your evidence before due_by.
under_reviewEvidence was submitted (or the dispute was escalated); the issuer is deciding.
wonThe issuer decided in your favor; funds are returned.
lostThe issuer decided against you; funds stay with the customer.
acceptedYou accepted the loss without contesting.
expiredThe response deadline passed with no submission.
closedAn inquiry the bank dropped with no contest — no funds withdrawn. Terminal and excluded from win-rate; a surfaced inquiry reaching closed fires dispute.closed (only an inquiry already terminal on first sight is silent).

won, lost, accepted, expired, and closed are terminal — the dispute will not change further.

Phase

phase is orthogonal to state and tracks which round the dispute is in: inquiry, dispute, pre_arbitration, or arbitration. A new phase opens a fresh evidence round (see Respond with Evidence).

Reason

reason is the canonical reason the dispute was filed: general, fraudulent, duplicate, credit_not_processed, incorrect_account_details, insufficient_funds, product_not_received, product_unacceptable, subscription_canceled, or unrecognized. The reason drives which evidence is most persuasive; the dispute’s evidence_requirements resolves the recommended evidence for that reason, grouped into compelling / supporting / other, and Respond with Evidence covers how to use it.

Outcome

outcome is the denormalized terminal result (won / lost / accepted / expired / closed) and is null until the dispute resolves.

How you integrate: notify, then fetch

The API follows a webhook + poll pattern:

  1. You receive a dispute.created / dispute.updated / dispute.closed webhook telling you something changed on a dispute.
  2. You fetch the dispute to read its current canonical state.

The webhook payload carries the full dispute snapshot, so a fetch is usually optional — but the contract is “notify, then fetch for authoritative state,” which keeps you correct even if a webhook is delayed or retried.

Where to go next