---
title: "Run the Ramp cross-family duplicate-payments repair (#1715)"
method: POST
path: "/admin/repairs/ramp-cross-family-duplicates"
tags: ["Admin"]
---

# Run the Ramp cross-family duplicate-payments repair (#1715)

`POST /admin/repairs/ramp-cross-family-duplicates`

## Request

- Base URL: `https://api.medianfi.com/api/v1`
- URL: `https://api.medianfi.com/api/v1/admin/repairs/ramp-cross-family-duplicates`
- Auth: HTTP bearer

Detects transaction pairs where the retired cash-side Ramp sync minted a `ramp:transfer-` row duplicating the live `ramp:card-payment-` row for the same transfer UUID, and (on apply) voids the orphaned transfer leg through the canonical accountant soft-delete funnel. Dry-run by default; `apply` additionally requires `companyId` and `confirm` set to exactly `REPAIR <companyId>`. Fleet-wide apply is refused. Requires a human bearer JWT whose user id is present in the immutable server-owned SUPER_ADMIN_USER_IDS allowlist; API keys cannot call this operation. Every void is audit-logged with the caller as actor.

## Request body

- DataRepairRequest
  - `companyId` string, uuid: Scope. Omitted = fleet-wide, which is allowed for dry-run only.
  - `apply` boolean: false = dry-run; report proposals, touch nothing.
  - `confirm` string: Must be exactly `REPAIR <companyId>` when apply is true.
  - `maxActions` integer: Cap on void operations per request. Selection excludes already-voided rows — repeat until the ledger reports zero remaining.

## Response `200`

JSON change ledger (proposals, voids, failures, remaining work)

- DataRepairLedgerResponse
  - `success` true, required
  - `data` object, required: JSON change ledger. Shared fields listed here; each repair adds its own counters (pairsFound/voidable/remainingVoidable for the Ramp repair; duplicateGroups/surplusEntries/remainingSurplus for the bill-accrual repair) plus its full proposal list.
    - `repairRun` string, required: Stable identifier stamped on every void's audit trail.
    - `mode` 'dry-run' | 'apply', required
    - `companiesScanned` union: The requested scope, or "all" for a fleet-wide dry-run.
      - string[]
      - 'all'
    - `attempted` integer, required: Void operations attempted this run (bounded by maxActions).
    - `voided` integer, required
    - `failures` object[], required
    - `proposals` object[], required

## Other responses

- `401`: Authentication required
- `403`: Insufficient permissions or not a company member
- `422`: Validation error

---

[API](https://skmtc.dev/medianfi/apis/median-api.md) · [All operations](https://skmtc.dev/medianfi/apis/median-api/llms.txt) · [OpenAPI document](https://skmtc.dev/medianfi/apis/median-api/revisions/20090ea32b0d?raw)
