> This page is for version v1 (default).
> For other versions, use one of these documentation indexes:
> - v1 (default): https://developers.truemed.com/v-1/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developers.truemed.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developers.truemed.com/_mcp/server.

# Overview

> How Truemed's Disputes API lets merchants list, respond to, and resolve chargebacks from their own systems.

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.

> **Info**
>
> 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](/guides/setup/api/disputes/overview#base-urls))
> and reach out to your Truemed contact before relying on them in production.

## Base URLs

| Environment   | Base URL                      |
| ------------- | ----------------------------- |
| Sandbox (dev) | `https://dev-api.truemed.com` |
| Production    | `https://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](/guides/setup/api/disputes/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:

| State            | Meaning                                                                                                                                                                                                                         |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `inquiry`        | Pre-chargeback inquiry — surfaced and answerable. Respond with evidence to pre-empt escalation; you cannot `accept` an inquiry (no funds are at risk yet).                                                                      |
| `needs_response` | A chargeback is open and awaiting your evidence before `due_by`.                                                                                                                                                                |
| `under_review`   | Evidence was submitted (or the dispute was escalated); the issuer is deciding.                                                                                                                                                  |
| `won`            | The issuer decided in your favor; funds are returned.                                                                                                                                                                           |
| `lost`           | The issuer decided against you; funds stay with the customer.                                                                                                                                                                   |
| `accepted`       | You accepted the loss without contesting.                                                                                                                                                                                       |
| `expired`        | The response deadline passed with no submission.                                                                                                                                                                                |
| `closed`         | An 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](/guides/setup/api/disputes/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](/guides/setup/api/disputes/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`](/guides/setup/api/disputes/webhooks) webhook telling you
   *something changed* on a dispute.
2. You [fetch the dispute](/guides/setup/api/disputes/list-and-retrieve) 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

* [List and retrieve disputes](/guides/setup/api/disputes/list-and-retrieve) — find disputes and read their detail.
* [Respond with evidence](/guides/setup/api/disputes/respond-with-evidence) — draft, autosave, and one-shot submit a counter.
* [Upload evidence files](/guides/setup/api/disputes/upload-evidence-files) — attach receipts, shipping docs, and screenshots.
* [Accept a dispute](/guides/setup/api/disputes/accept-a-dispute) — concede a loss without contesting.
* [Webhooks and polling](/guides/setup/api/disputes/webhooks) — react to dispute changes in real time.