API Changes Summary

Branch kh-vendor-ai-codingmain · Generated 2026-06-18

Adds a new org-level Accounting Columns section to the Custom Columns settings page. Practices can enable/disable a fixed, Nitra-managed catalog of standard accounting dimensions (GL Account, Vendor, Class, Department, Location, Accounting Date). Some columns are “Always On” per accounting platform and cannot be disabled. Disabling a column also cascades into each member’s per-member display lists (customizedColumns) for Card Transactions, Card Fees & Interest, and Expenses. As part of the same UI (one Save button), the existing ruttercustomfieldconfig/update endpoint is converted to a batch shape — a breaking change the frontend must adopt.

This PR at a glance · 2 Added · 1 Updated (breaking) · 1 New table
Full navigation is in the sidebar on the left. On narrower screens, scroll the page or jump via the section anchors.

Added APIs Added

GET POST /v1/accountingcolumnconfig/query

Returns the fixed accounting column catalog merged with the org's enable config, for the settings page.

Request body

FieldTypeRequiredDefaultDescription
organizationIdINTEGERNoreq.organization.idThe organization to read columns for
enabledBOOLEANNoWhen set, only columns whose enabled flag matches are returned

Response (200)

{
  "status": 200,
  "success": true,
  "accountingColumns": [
    { "columnKey": "glAccount",      "name": "GL Account",      "enabled": true,  "required": true },
    { "columnKey": "vendor",         "name": "Vendor",          "enabled": true,  "required": false },
    { "columnKey": "class",          "name": "Class",           "enabled": true,  "required": false },
    { "columnKey": "department",     "name": "Department",      "enabled": true,  "required": false },
    { "columnKey": "location",       "name": "Location",        "enabled": true,  "required": false },
    { "columnKey": "accountingDate", "name": "Accounting Date", "enabled": true,  "required": false }
  ]
}
Behavior: Only the columns available on the org's accounting platform are returned, in catalog order — e.g. department is Sage-only and location is Sage/NetSuite-only, so neither appears for a QuickBooks org. (When the org has no platform, the full catalog is returned for display.) Columns with no stored config default to enabled: true. required: true columns are platform-specific (“Always On”, e.g. GL Account on NetSuite/QuickBooks) and are always returned enabled: true — the FE should render their toggle as locked on.

Errors

StatusCode
400BAD_REQUEST_INVALID_ARGUMENTS
401UNAUTHORIZED
500INTERNAL_SERVER_ERROR

GET POST /v1/accountingcolumnconfig/update

Batch-update enabled status for accounting columns; cascades into member display lists. All-or-nothing.

Request body

FieldTypeRequiredDefaultDescription
organizationIdINTEGERNoreq.organization.idMust equal the caller's organization, else 403
accountingColumnsARRAYYesMin 1 item; no duplicate columnKeys
accountingColumns[].columnKeySTRINGYesOne of the catalog keys (e.g. glaccount, vendor, class, department, location); must be available on the org's platform
accountingColumns[].enabledBOOLEANYesNew enabled state for the column

Example request

{
  "accountingColumns": [
    { "columnKey": "vendor", "enabled": false },
    { "columnKey": "class",  "enabled": false }
  ]
}

Response (200)

{
  "status": 200,
  "success": true
}
All-or-nothing: the whole batch runs in one transaction. If any item disables a platform-required column, the entire request is rejected with ACCOUNTINGCOLUMNCONFIG_BAD_REQUEST_CANNOT_DISABLE_REQUIRED_COLUMN and nothing is written. Duplicate columnKeys in accountingColumns are rejected as a 400.
Cascade side-effect: disabling a column removes it from every member's per-member display list (MemberOrganizationPreference types ACCOUNTING_ITEM_CUSTOMIZED_COLUMN, ACCOUNTING_CARD_FEES_INTEREST_CUSTOMIZED_COLUMN, ACCOUNTING_EXPENSE_CUSTOMIZED_COLUMN); enabling re-adds it only where missing. The FE should re-fetch member preferences after a successful save if it caches them.

Errors

StatusCode
400BAD_REQUEST_INVALID_ARGUMENTS (invalid/missing fields, bad columnKey, duplicate keys)
400ACCOUNTINGCOLUMNCONFIG_BAD_REQUEST_CANNOT_DISABLE_REQUIRED_COLUMN
400ACCOUNTINGCOLUMNCONFIG_BAD_REQUEST_COLUMN_NOT_AVAILABLE_ON_PLATFORM
401UNAUTHORIZED
403FORBIDDEN (organizationId is not the caller's org)
500INTERNAL_SERVER_ERROR

Updated APIs Updated

GET POST /v1/ruttercustomfieldconfig/update Breaking

Update enabled status for NetSuite/Rutter custom fields — now batch / array-only.

What changed

Request body (new shape)

FieldTypeRequiredDefaultDescription
organizationIdINTEGERNoreq.organization.idMust equal the caller's organization, else 403
customFieldsARRAYYesMin 1 item
customFields[].idINTEGERCond.Existing config row id (update). Mutually exclusive with rutterCustomFieldDefinitionId (xor)
customFields[].rutterCustomFieldDefinitionIdINTEGERCond.Definition id (create). Mutually exclusive with id (xor)
customFields[].enabledBOOLEANYesNew enabled state for the field

Migration: before → after

// BEFORE (single item, top-level)
{ "id": 12, "enabled": true }
{ "rutterCustomFieldDefinitionId": 5, "enabled": true }

// AFTER (array-only)
{ "customFields": [ { "id": 12, "enabled": true } ] }
{ "customFields": [ { "rutterCustomFieldDefinitionId": 5, "enabled": true } ] }
// multiple toggles in one Save:
{ "customFields": [
    { "id": 12, "enabled": false },
    { "rutterCustomFieldDefinitionId": 5, "enabled": true }
] }

Response (200)

{
  "status": 200,
  "success": true
}

Errors

StatusCode
400BAD_REQUEST_INVALID_ARGUMENTS
400RUTTERCUSTOMFIELDCONFIG_BAD_REQUEST_RUTTER_CUSTOM_FIELD_CONFIG_DOES_NOT_EXIST (an id item references a missing row)
401UNAUTHORIZED
403FORBIDDEN (cross-org id, or definition not on the org's platform)
500INTERNAL_SERVER_ERROR

Model / Payload Changes Schema

AccountingColumnConfig New table

Backs the accounting column toggles. Not serialized to the FE raw — consumed only via /accountingcolumnconfig/query, which returns the derived catalog shape above.

FE impact: none directly — interact with this table only through the two /accountingcolumnconfig/* endpoints. No new fields are added to existing serialized payloads.