---
title: "Change only the code and/or name of an existing GL account, keeping its id (#2883)"
method: POST
path: "/accountant/companies/{customerId}/chart-of-accounts/{accountId}/identity"
tags: ["Accountant Portal"]
---

# Change only the code and/or name of an existing GL account, keeping its id (#2883)

`POST /accountant/companies/{customerId}/chart-of-accounts/{accountId}/identity`

## Request

- Base URL: `https://api.medianfi.com/api/v1`
- URL: `https://api.medianfi.com/api/v1/accountant/companies/{customerId}/chart-of-accounts/{accountId}/identity`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-API-Key`

The identity-preserving chart edit. It writes ONLY `code`, `name` and `updated_at` on the account, so the id is unchanged and every journal line, bank or integration mapping, QuickBooks account mapping, role and schedule stays attached. It cannot change type, subtype, detail type, report section, description, parent, normal balance, isActive, isLocked, isPostable, provenance or any classification: any other body key is a 422, never an ignored field. It has no posting cutoff, automatic mapping, automatic sync or QuickBooks write side effect, and it creates, deactivates and retires nothing.
`expected` is the code and name the caller last read; the edit lands only on exactly that row. A request whose target code and name are already on the account replays: 200 with `meta.replayed: true`, no write and no audit record. A successful edit writes one audit record (action `update`, entity `gl_account`, `lifecycleAction: identity_edit`) with the reason, the before and after snapshot, the acting user and, for the service token, its API key id. The edit and its audit record commit in one database transaction: neither lands without the other, so a 500 or 503 means nothing was written and the request can be retried unchanged. A feed-created bank or card account (`source: integration`) is relabelled like any other, since its feed links by id.
Conflicts are reported, never resolved: a code held by another account (active, inactive or retired), an active name held by another active account, a company merchant rule that targets the code being left or taken, or a live QuickBooks create-account write-back item for the account return 409 `GL_ACCOUNT_IDENTITY_CONFLICT` with every conflict in `error.extensions.conflicts`. Nothing is overwritten, swapped, deactivated or retired to make room. Service-principal access reviewed 2026-10-02 (#2883); the full `PATCH .../chart-of-accounts/{accountId}` stays bearer-only.

## Request body

- EditGlAccountIdentityInput: Change only an account's code and/or name (#2883). At least one of `code` and `name` is required. Unknown keys are refused.
  - `code` string: The new code. 1-7 letters, digits, dots or dashes, so it survives as a QuickBooks account number.
  - `name` string: The new name. Single line, no HTML, no colon or double quote, not an account code (3-6 digits), no repeated spaces.
  - `reason` string, required: Why the account is being recoded or renamed; stored on the audit record.
  - `expected` object, required: The code and name the caller last read on the account. Anything else on the row is a 409 GL_ACCOUNT_IDENTITY_STALE.
    - `code` string, required
    - `name` string, required

## Response `200`

The account after the edit, or the unchanged account when the request replays

- object
  - `success` true, required
  - `data` GlAccount, required
    - `id` string, uuid
    - `companyId` string, uuid
    - `code` string
    - `name` string
    - `type` 'Asset' | 'Liability' | 'Equity' | 'Revenue' | 'Expense'
    - `subtype` string, nullable
    - `parentAccountId` string, uuid, nullable
    - `normalBalance` 'debit' | 'credit'
    - `detailTypeKey` string: Canonical COA detail type used for report grouping.
    - `detailTypeLabel` string
    - `detailTypeDescription` string
    - `reportSectionKey` string
    - `reportSectionLabel` string
    - `accountExplanation` CoaAccountExplanation: Read-only COA account context returned only when the customer company is allowlisted by CUSTOMER_APP_INTELLIGENCE_HOME_COMPANY_IDS.
      - `accountType` CoaAccountExplanationPart
        - `key` string
        - `label` string
        - `description` string
      - `detailType` CoaAccountExplanationPart
        - `key` string
        - `label` string
        - `description` string
      - `reportSection` CoaAccountExplanationPart
        - `key` string
        - `label` string
        - `description` string
      - `classification` CoaAccountExplanationPart
        - `key` string
        - `label` string
        - `description` string
    - `cashFlowSection` 'operating' | 'investing' | 'financing' | 'cash' | 'non_cash' | 'null', nullable
    - `taxFormSectionKey` string, nullable
    - `description` string, nullable
    - `source` 'system' | 'template' | 'integration' | 'migration' | 'manual' | 'repair'
    - `isSystem` boolean
    - `isLocked` boolean: Locked accounts cannot be selected for new direct posting.
    - `isPostable` boolean: False for parent, locked, inactive, or otherwise non-postable accounts.
    - `isParent` boolean: True when at least one active child account references this account.
    - `isActive` boolean
    - `isMonetary` boolean, nullable: Null is fail-closed and blocks foreign-balance revaluation.
    - `monetaryClassificationSource` 'account_type_subtype' | 'manual' | 'null', nullable
    - `monetaryClassifiedAt` string, date-time, nullable
    - `monetaryClassifiedByUserId` string, uuid, nullable
    - `deactivatedAt` string, date-time, nullable
    - `deactivatedByUserId` string, uuid, nullable
    - `deactivationReason` string, nullable
    - `expectedNormalBalance` 'debit' | 'credit'
    - `healthFindings` object[]
      - `code` string
      - `severity` 'critical' | 'high' | 'medium' | 'low'
      - `message` string
    - `createdAt` string, date-time
    - `updatedAt` string, date-time
  - `meta` object, required
    - `replayed` boolean, required: True when the account already carried the requested code and name; nothing was written.

## Other responses

- `401`: Authentication required
- `403`: Insufficient permissions or not a company member
- `404`: Resource not found
- `409`: `GL_ACCOUNT_IDENTITY_CONFLICT`: the target code or name is held or referenced elsewhere; `error.extensions.conflicts` is an array of GlAccountIdentityConflict. `GL_ACCOUNT_IDENTITY_STALE`: the account no longer carries the `expected` code and name; `error.extensions.current` is its `{ code, name }` now. Re-read and retry.
- `422`: `Validation error`: the body or a path id failed validation (an unknown key, a missing reason or `expected`, a code that is not 1-7 letters, digits, dots or dashes, a name QuickBooks would rewrite). `GL_ACCOUNT_IDENTITY_PROTECTED`: the route refuses this account or target, with `error.extensions.reason` one of `system_account` (a required system account), `reserved_code` (the account's code or the target code is reserved for a system or Stripe account; `extensions.code`), `seed_template_code` (the account sits on a code Median's default chart seeds, which the next sync would re-create), `seed_template_code_meaning` (the target is a default-chart code and the account is a different type or detail type), `seed_template_name` (the target name is a default-chart name whose code the company does not hold), `engine_pinned_code` (the target is a code posting resolves by code for another account type, or the account is the type posting binds to its current code; `extensions.code` and `extensions.pinnedType`), `classification_change` (a report, cash, revenue, sub-ledger, posting-role or QuickBooks classification would change; `extensions.differences` lists each key with its before and after) or `filing_locked_history` (the account has posted lines in a filing-locked period). Also 422 when `reason` carries a control character or lone surrogate, which the audit record cannot store.
- `429`: Service key write rate limit exceeded (the edit counts against the service principal's write budget)
- `503`: The accountant assignment could not be re-read before the write. Nothing was written; retry unchanged.

---

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