# Reconciliation

Reconcile settlements against gateway data, and compare them with deposits and transactions.

All endpoints are admin API calls: send `Authorization: Bearer <JWT>` (or an API key in `x-api-key`). The tenant comes from the token or key.

> **Note:** there is no date-based reconciliation report and no auto-reconcile endpoint. Reconciliation runs per settlement, with the endpoint below.

---

## List Settlements

```http
GET /api/v1/settlements
```

```bash
curl "https://uat.auxcore.net/api/v1/settlements?merchantId=3f9c2b7e-1a4d-4e8f-b6c5-2d1e0f9a8b7c&dateFrom=2026-01-01&dateTo=2026-01-31&status=discrepancy" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

| Query param | Notes |
|---|---|
| `merchantId` | With it: that merchant's settlements, filtered by the params below. **Without it:** the tenant's settlements awaiting approval (other filters ignored). |
| `dateFrom`, `dateTo` | `YYYY-MM-DD` |
| `status` | `calculating`, `calculated`, `reconciling`, `reconciled`, `discrepancy`, `approved`, `payout_processing`, `paid`, `failed` |

Each settlement carries `id`, `merchantId`, `payPeriodId`, `gatewayType`, `status`, `grossAmount`, `transactionCount`, `totalFees`, `netAmount`, `reserveHeld`, `payoutAmount`, `feeBreakdown`, `volumeBreakdown`, `reconciliation` (the last result, or `null`), `hasDiscrepancy`, `discrepancyAmount`, and the approval and reconciliation timestamps. Money fields are decimal strings. `GET /api/v1/settlements/:settlementId` returns one settlement (`404` if not found).

---

## Reconcile a Settlement

```http
POST /api/v1/settlements/:settlementId/reconcile
```

Compares the settlement with the gateway's settlement data for the same pay period.

```bash
curl -X POST https://uat.auxcore.net/api/v1/settlements/c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f/reconcile \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"gatewayType": "NMI"}'
```

`gatewayType` is required; without it the response is `400` with `error.code` `MISSING_GATEWAY_TYPE`.

**Response:**
```json
{
  "success": true,
  "data": {
    "gatewayGross": "10000.00",
    "calculatedGross": "10000.00",
    "grossVariance": "0.00",
    "gatewayNet": "9700.00",
    "calculatedNet": "9700.00",
    "netVariance": "0.00",
    "transactionCountGateway": 212,
    "transactionCountLocal": 212,
    "countVariance": 0,
    "missingTransactions": [],
    "extraTransactions": [],
    "amountMismatches": [],
    "status": "matched",
    "varianceThreshold": "0.01",
    "reconciledAt": "2026-01-16T14:05:12.000Z",
    "reconciledBy": "7a8b9c0d-1e2f-4a3b-8c4d-5e6f7a8b9c0d"
  }
}
```

- `status`: `matched` (gross and net within $0.01 and equal counts), `critical_variance` (gross off by more than $100 or more than 10 transactions), otherwise `variance`.
- `missingTransactions`: IDs the gateway has but AuxCORE does not; `extraTransactions`: the reverse.
- `amountMismatches[]`: `{ "transactionId", "localAmount", "gatewayAmount", "variance" }`.
- Any status other than `matched` flags the settlement (`hasDiscrepancy: true`) and moves it to `discrepancy`.

Errors (including an unknown settlement) return `500` with `{ "success": false, "error": "<message>" }`.

---

## Approve a Settlement

```http
POST /api/v1/settlements/:settlementId/approve
```

Body: `notes` (optional), `overrideDiscrepancy` (boolean, default `false`). Only settlements in `calculated` or `reconciled` status can be approved; a flagged settlement needs `overrideDiscrepancy: true`.

---

## Review Discrepancies

```http
GET /api/v1/reports/discrepancies
```

Intended to list settlement discrepancies for the tenant (optional `status`: `new`, `investigating`, `resolved`, `accepted`; requires the `reports.view` permission).

> **Known issue:** this endpoint currently returns `500` with `error.code` `INTERNAL_ERROR` (the reporting service calls a settlement route that does not exist). Until it is fixed, list flagged settlements with `GET /api/v1/settlements?merchantId=<id>&status=discrepancy`.

---

## Compare with Deposits

```http
GET /api/v1/deposits
```

Lists deposits (one per settled batch) to match against your bank statement.

```bash
curl "https://uat.auxcore.net/api/v1/deposits?merchantId=3f9c2b7e-1a4d-4e8f-b6c5-2d1e0f9a8b7c&dateFrom=2026-01-01&dateTo=2026-01-31" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

Query: `merchantId` (admins; merchant users always get their own), `dateFrom`, `dateTo`, `limit` (default 100, max 500). Each item: `id`, `date`, `depositDate`, `amount`, `grossAmount`, `refundAmount`, `chargebackAmount`, `transactionCount`, `fees`, `net`, `netAmount`, `status` (`pending`, `processing`, `completed`, `failed`), `bankAccount`, `reference`, `merchantId`, `gateway`. `GET /api/v1/deposits/:id` returns one deposit.

> `bankAccount` is currently always the placeholder `****0000`.

---

## Handle Discrepancies

If totals don't match, review the transactions settled in the period:

```bash
curl "https://uat.auxcore.net/api/v1/transactions?merchantId=3f9c2b7e-1a4d-4e8f-b6c5-2d1e0f9a8b7c&dateField=settledAt&dateFrom=2026-01-15&dateTo=2026-01-15&status=settled" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

`dateField=settledAt` filters on the settlement date instead of the creation date.

---

**Need help?** Contact support@auxcore.net
