---
title: "Run the duplicate bill-accrual journal-entries repair (#1704)"
method: POST
path: "/admin/repairs/duplicate-bill-accruals"
tags: ["Admin"]
---

# Run the duplicate bill-accrual journal-entries repair (#1704)

`POST /admin/repairs/duplicate-bill-accruals`

## Request

- Base URL: `https://api.medianfi.com/api/v1`
- URL: `https://api.medianfi.com/api/v1/admin/repairs/duplicate-bill-accruals`
- Auth: HTTP bearer

Detects groups of posted document-sourced `Bill accrual:` journal entries duplicating the same (company, description, date, amount) and (on apply) voids the surplus entries through the atomic void-with-audit-and-recompute funnel, keeping the adjudicated or earliest-posted entry. Groups with distinct invoice numbers or reconciled surplus entries are reported, never touched. 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)
