---
title: "Repair a transaction journal entry that debits and credits the same account"
method: POST
path: "/accountant/companies/{customerId}/transactions/{transactionId}/bank-offset-repair"
tags: ["Accountant Portal"]
---

# Repair a transaction journal entry that debits and credits the same account

`POST /accountant/companies/{customerId}/transactions/{transactionId}/bank-offset-repair`

## Request

- Base URL: `https://api.medianfi.com/api/v1`
- URL: `https://api.medianfi.com/api/v1/accountant/companies/{customerId}/transactions/{transactionId}/bank-offset-repair`
- Auth: HTTP bearer

#2912. For one transaction whose single posted journal entry has both lines on one GL account (balanced, and booking nothing): void-and-replaces it with the canonical two-line posting -- the bank or card offset rebuilt from the transaction's own bank account and direction (money in debits the bank GL, money out credits it), the counterpart on `categoryGlAccountId` -- and sets the transaction's category to match as a manual decision. The replacement inherits the voided entry's date, period, entity, source, description and posting key; both entries are linked to each other and an audit row records the actor, reason and before/after lines. Dry run by default: it returns the exact before and after lines and writes nothing. An apply (`dryRun: false`) must name the journal entry the dry run showed. Every eligibility check runs before any write; anything that is not exactly that shape is refused without a guessed replacement. A replay of an applied repair returns `already_repaired` and writes nothing. Human accountants only: the service token gets 404, and the accountant's assignment is re-read from the database before the request body is parsed.

## Request body

- RepairTransactionBankOffsetRequest
  - `categoryGlAccountId` string, uuid, required: The GL account the counterpart line posts to and the transaction is categorized to. Never the transaction's own bank or card GL account.
  - `reason` string, required: Why this journal entry is being repaired; kept in the audit row, never in the journal entry.
  - `dryRun` boolean: When true (the default) the response shows the plan and nothing is written.
  - `expectedJournalEntryId` string, uuid: The `journalEntryId` the dry run returned. Required when `dryRun` is false.

## Response `200`

Dry-run plan, applied repair, or already-repaired replay

- BankOffsetRepairResponse
  - `success` true, required
  - `data` BankOffsetRepairResult, required
    - `status` 'dry_run' | 'repaired' | 'already_repaired', required
    - `transactionId` string, uuid, required
    - `journalEntryId` string, uuid, required: The posted journal entry the request examined; the one voided when `status` is `repaired`.
    - `replacementJournalEntryId` string, uuid, nullable, required: The new posted journal entry; null unless `status` is `repaired`.
    - `bankGlAccountId` string, uuid, required: GL account of the transaction's own bank or card account.
    - `categoryGlAccountIdBefore` string, uuid, nullable, required
    - `categoryGlAccountIdAfter` string, uuid, nullable, required: The category column as the apply leaves it, or as a dry run would leave it. An `already_repaired` reply that wrote nothing reports the column unchanged, which may differ from the requested category.
    - `suggestedCategoryGlAccountId` string, uuid, nullable, required: Counterpart account of the most recent correct voided posting of this transaction, when there is one. A hint only; it is never applied.
    - `beforeLines` BankOffsetRepairLine[], required
      - `glAccountId` string, uuid, required
      - `glAccountCode` string, nullable, required
      - `debitCents` integer, required
      - `creditCents` integer, required
    - `afterLines` BankOffsetRepairLine[], required
      - `glAccountId` string, uuid, required
      - `glAccountCode` string, nullable, required
      - `debitCents` integer, required
      - `creditCents` integer, required

## Other responses

- `401`: Authentication required
- `403`: Insufficient permissions or not a company member
- `404`: Resource not found
- `409`: Refused, nothing written. `error.title` is one of `BANK_OFFSET_REPAIR_JOURNAL_COUNT` (not exactly one posted transaction journal entry), `BANK_OFFSET_REPAIR_JOURNAL_CHANGED` (`expectedJournalEntryId` is not the posted entry), `BANK_OFFSET_REPAIR_NOT_SELF_CANCELLING`, `BANK_OFFSET_REPAIR_SHAPE_AMBIGUOUS`, `BANK_OFFSET_REPAIR_BANK_MAPPING_CHANGED`, `BANK_OFFSET_REPAIR_RACE`, `JOURNAL_ENTRY_SHARED_AUTHORITY` (consolidated with another transaction), `JOURNAL_ENTRY_ENTITY_AUTHORITY_CONFLICT`, `TRANSACTION_DOCUMENT_MATCH_ACTIVE`, `TRANSACTION_APPLIED_TRANSFER_MATCH_ACTIVE` or `TRANSACTION_CATEGORY_ACCOUNTING_INCOMPLETE`.
- `422`: Request validation failed, or refused with nothing written. `error.title` is one of `TRANSACTION_CATEGORY_IS_BANK_ACCOUNT`, `TRANSACTION_RECONCILED`, `JOURNAL_ENTRY_RECONCILED`, `JOURNAL_ENTRY_PERIOD_LOCKED` (filing-locked; a closed, unfiled period is allowed), `BANK_OFFSET_REPAIR_EXCLUDED_FROM_BOOKS` (no business bank account mapped to a postable GL account), `BANK_OFFSET_REPAIR_SPLIT`, `BANK_OFFSET_REPAIR_NATIVE_STRIPE`, `BANK_OFFSET_REPAIR_CURRENCY`, or a category account that cannot be posted to.

---

[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)
