# Disputes

Work chargebacks and pre-dispute alerts from the Disputes tab: read what the card network actually said, gather evidence, respond before the deadline, and track the outcome.

---

## Overview

A dispute is opened by the cardholder's issuing bank, not by AuxCORE. AuxCORE receives it, holds the case, and gives you the tools to answer it:

- 📥 **Intake** — the case appears in the Disputes tab with the network's original reason attached
- 🗂️ **Evidence** — upload supporting documents, which are scanned before they can be submitted
- 📤 **Response** — challenge the dispute with a packaged response, or accept it
- ⏱️ **Deadline tracking** — the response clock is shown on every open case
- 📊 **Outcome** — the result is recorded separately from where the case sits internally

---

## The three-part status model

A dispute carries **three independent values**. AuxCORE never collapses them into a single status, because they answer three different questions and can disagree with each other.

| Field | Answers | Set by |
|-------|---------|--------|
| **AuxCORE Status** | Where does this case sit in *our* handling workflow? | AuxCORE, as you work the case |
| **Network Stage** | What did the card network or processor last call it? | The network, reported verbatim |
| **Outcome** | How did it end? | The final result, once known |

A case can read `Closed` / `Not reported` / `Merchant Accepted` all at once: we are done with it, the network never sent us a stage, and it ended because you accepted liability. That is three facts, not a contradiction.

### AuxCORE Status

Where the case sits in our handling workflow.

| Value | Meaning |
|-------|---------|
| `Open` | Received and not yet answered. |
| `Action Required` | Something is needed from you before the case can move. |
| `Submitted` | Your response has been sent. |
| `Under Review` | The response is being assessed. |
| `Closed` | No further handling work on our side. |

**Closed is not a result.** It only means we have stopped working the case. Read the Outcome to find out how it ended.

### Network Stage

Printed exactly as the network or processor reported it — for example `First Chargeback`, `Pre-Arbitration`, or `Representment`. AuxCORE does not translate, normalise, or infer this value.

When nothing has been reported, the field reads **Not reported**. That is a true statement about the case rather than a placeholder: many disputes are resolved before the network ever sends a stage update.

### Outcome

How the case ended. `Pending` until a result is actually known.

| Value | Meaning |
|-------|---------|
| `Pending` | Not decided yet. This is the value on every new dispute. |
| `Merchant Won` | Decided in your favour; the funds stay with you. |
| `Merchant Lost` | Decided against you after a response. |
| `Merchant Accepted` | You accepted liability instead of challenging. |
| `Prevented` | Resolved through an alert before it became a formal dispute. |

---

## Working the queue

The tab strip is a navigation aid over the three fields above. A known Outcome decides the tab; where the Outcome is still `Pending`, the AuxCORE Status does.

| Tab | Shows |
|-----|-------|
| **Needs Attention** | Undecided cases that are open, marked Action Required, or within 7 days of their deadline. |
| **Open** | Received, undecided, not yet answered. |
| **Submitted** | Answered and awaiting a decision. |
| **Won** | Outcome is `Merchant Won`. |
| **Lost** | Outcome is `Merchant Lost` or `Merchant Accepted`. |
| **Closed** | Prevented cases, and cases closed internally with no result recorded. |
| **Alerts & Prevention** | Pre-dispute alerts, raised before any formal chargeback exists. |

AuxCORE Status and Outcome are also available as **separate filters** in the toolbar, so you can ask for combinations the tabs do not express — for example every `Closed` case whose Outcome is still `Pending`.

---

## The dispute details panel

Selecting a dispute opens a side panel with three tabs.

### Details

Customer, payment method, received date, payment date, disputed amount, and the **original reason**.

The original reason is the network's own wording — for example `Visa 13.1 — Merchandise/Services Not Received`. Where AuxCORE has a matching catalog entry, a plain-language explanation is shown *alongside* it. Where there is no mapping, the original reason is shown on its own; it is never replaced with generated text.

### Documents

Evidence attached to the case. Accepted formats are **PDF, PNG, JPEG, WEBP and ZIP, up to 25 MB each**. Every upload is scanned before it can be included in a response — a file that fails the scan stays visible but is marked unusable and is excluded from submission.

A case with no evidence yet shows an empty state, not an error.

### Timeline

The recorded history of the case: when the dispute was received, the response deadline, the actions taken on it, and the outcome once it is known. Entries are facts with timestamps — nothing is re-derived for display.

Where a case has **no response deadline**, the timeline says *No response deadline set*. Not every dispute arrives with a deadline attached.

---

## Responding to a dispute

Both actions are offered only while there is response work left, and disappear once the case is decided.

### Build Response

Opens the guided response flow: the deadline and original transaction first, then the reason, then the evidence to package. You choose which documents to include; unusable files are never sent. A summary is shown before anything is submitted.

### Accept Dispute

Accepts liability without challenging. It is confirmed in its own modal — nothing is sent until you confirm — and can be reached either directly or from inside Build Response. Both routes run the identical confirmation and write the identical timeline entry.

Accepting sets the Outcome to `Merchant Accepted`. The disputed amount is not returned to you.

### Deadlines

Open cases show the days remaining on the network's response deadline. Inside 7 days the case is pulled into **Needs Attention**; inside 2 days the response flow is highlighted.

A missed deadline is normally decided against you by default, so treat `Due today` as the last chance to respond rather than as the deadline itself.

---

## Other actions

| Action | What it does |
|--------|--------------|
| **View Original Transaction** | Opens the transaction the dispute was raised against. |
| **Get Help** | Opens a new support case with the dispute reference already filled in. |
| **Export** | Downloads the disputes currently listed, as filtered, in CSV. |

---

## Alerts and prevention

Where enrolled, AuxCORE surfaces pre-dispute alerts: the issuer has flagged a transaction but no chargeback exists yet. Resolving one — usually by refunding — stops the dispute from being raised, and the case is recorded with the Outcome `Prevented`.

Prevented cases never became a formal dispute, so they carry no network stage and no response deadline.

---

## Disputes API

Everything the Disputes tab does is available on the admin API under `/api/v1/chargebacks` (authenticate with `Authorization: Bearer <JWT>` or `x-api-key`). A merchant-scoped caller only sees its own merchant's disputes; tenant-level callers pass `merchantId`.

API values are lowercase snake_case: `auxcoreStatus` is one of `open`, `action_required`, `submitted`, `under_review`, `closed`; `outcome` is one of `pending`, `merchant_won`, `merchant_lost`, `merchant_accepted`, `prevented`. `networkStage` is free text, stored verbatim.

Reads are open to any authenticated user of the merchant. Responding, accepting, notes, evidence uploads and status changes need `chargebacks.manage`; creating a dispute needs `transactions.chargeback`. Listing, downloading and deleting evidence documents have no extra permission check.

### List Disputes

```http
GET /api/v1/chargebacks
```

| Query | Description |
|-------|-------------|
| `merchantId` | Merchant (required for tenant-level callers) |
| `auxcoreStatus` / `outcome` / `networkStage` | Independent filters |
| `status` | Legacy single status: `open`, `under_review`, `won`, `lost`, `expired` |
| `transactionId` | Disputes raised against one transaction |
| `branchId` | Location filter (`all` = no filter) |
| `startDate` / `endDate` | Date range |
| `page` / `limit` | Default `1` / `50`, max `limit` 200 |

**Response:** `{ "success": true, "data": [ … ], "total": 12, "page": 1, "limit": 50, "totalPages": 1 }`

### Get Dispute

```http
GET /api/v1/chargebacks/:id
```

`404` `NOT_FOUND` if it does not exist in your tenant.

### Dispute Summary

```http
GET /api/v1/chargebacks/summary
```

Query: `merchantId` (required for tenant-level callers), `startDate`, `endDate`.

### Create Dispute

```http
POST /api/v1/chargebacks
```

```json
{
  "merchantId": "3f2a9c1e-7b4d-4e8a-9f10-2c5d6e7f8a90",
  "caseNumber": "CB-2026-000123",
  "originalTransactionId": "8d1c2b3a-4e5f-4a6b-9c7d-0e1f2a3b4c5d",
  "transactionAmount": 120.00,
  "disputeAmount": 120.00,
  "reasonCode": "13.1",
  "reason": "Merchandise/Services Not Received",
  "dueDate": "2026-02-15"
}
```

`merchantId` and `caseNumber` are required; a `caseNumber` already used in your tenant returns `400` `VALIDATION_ERROR`. Optional: `currency`, `chargebackType`, `originalReasonNetwork` / `originalReasonCode` / `originalReasonWording` / `originalReasonSubWording`, `customerName`, `customerEmail`, `cardLast4`, `cardBrand`, `transactionDate`, `receivedDate`, `networkStage`, `auxcoreStatus`, `outcome`. Returns `201`.

### Update Status

```http
PATCH /api/v1/chargebacks/:id/status
```

```json
{ "outcome": "merchant_won", "auxcoreStatus": "closed", "note": "Issuer reversed the chargeback" }
```

Send at least one of `auxcoreStatus`, `networkStage` (plus optional `networkStageSource`) or `outcome`; each moves independently. An invalid value returns `400` `VALIDATION_ERROR` listing the allowed values. (Sending only the legacy `status` field is still accepted.)

### Respond (Challenge)

```http
POST /api/v1/chargebacks/:id/respond
```

```json
{
  "response": "Item was delivered on 2026-01-10; tracking and signed proof attached.",
  "documentIds": ["4b5c6d7e-8f9a-4b1c-9d2e-3f4a5b6c7d8e"]
}
```

`response` is required. `documentIds` picks which evidence to package (default: every usable document); files that failed the scan are never included. Sets `auxcoreStatus` to `submitted`; the outcome stays `pending`. A decided case returns `409` `DISPUTE_NOT_OPEN`.

### Accept Dispute

```http
POST /api/v1/chargebacks/:id/accept
```

Optional body `{ "acceptanceNote": "…" }`. Sets the outcome to `merchant_accepted`. A decided case returns `409` `DISPUTE_NOT_OPEN`.

### Notes

```http
POST /api/v1/chargebacks/:id/notes
```

Body `{ "content": "…" }` (required).

### Upload Evidence Documents

```http
POST /api/v1/chargebacks/:id/documents
```

`multipart/form-data` with up to 10 files in the field `files` (PDF, PNG, JPEG, WEBP, ZIP; max 25 MB each) and an optional `description`. Returns `201`. A file over the limit returns `400` `UPLOAD_ERROR`; an unsupported type returns `400` `VALIDATION_ERROR`; a file rejected by the scan returns `400` `EVIDENCE_REJECTED`.

### List Evidence Documents

```http
GET /api/v1/chargebacks/:id/documents
```

### Download an Evidence Document

```http
GET /api/v1/chargebacks/:id/documents/:docId/download
```

### Delete an Evidence Document

```http
DELETE /api/v1/chargebacks/:id/documents/:docId
```

### List Pre-Dispute Alerts

Alerts live on their own path, separate from formal disputes. The path is gated by the tenant's `dispute-alerts` feature; without it the gateway returns `403` `SERVICE_UNAVAILABLE`.

```http
GET /api/v1/dispute-alerts
```

Query: `merchantId`, `program` (`prevent`, `prevent_plus`, `rdr`, `mc_resolve`, `cdrn`, `unknown`), `status` (`open`, `resolved`, `deflected`, `declined`, `escalated`, `expired`), `startDate`, `endDate`, `page` (default `1`), `limit` (default `50`, max 200).

### Get a Pre-Dispute Alert

```http
GET /api/v1/dispute-alerts/:id
```

`404` `NOT_FOUND` if the alert does not exist.

> **Note:** To hear about new cases and status changes as they happen, subscribe a webhook endpoint to the [dispute events](../reference/webhook-events.md#dispute-events) (`chargeback.received`, `chargeback.won`, …). They are not in the default subscription, so list them in `events`.

---

## Reducing disputes

- Use a clear, recognisable billing descriptor — an unrecognised descriptor is a leading dispute reason.
- Send receipts on every transaction, so the cardholder has your details before their bank does.
- Answer refund requests quickly; a refund is far cheaper than a chargeback.
- Keep delivery, service, and communication records — they are what a response is built from.
- Turn on [AVS](./avs.md) and [CVV](./cvv.md) filters to reject the transactions most likely to be disputed.

---

## Next Steps

- [Risk management →](./risk.md)
- [Process a refund →](../core/refunds.md)
- [View transactions →](../core/transactions.md)
- [Set up webhooks →](../getting-started/webhooks.md)

---

**Need help?** Contact [support@auxcore.net](mailto:support@auxcore.net)
