Company GL settings and exports

Manage the customer's existing GL chart and download completed-pay reports. Use a customer-authorised OAuth bearer token. An API-admin account does not grant access to another customer's payroll database.

CSV follows the saved chart, account codes, inclusion flags and department overrides. PDF is the existing fixed-layout Suggested GL postings report: custom account codes, per-row inclusion and individual deduction mappings do not change it. Neither endpoint sends a journal or invoice to an accounting provider.

Access and revisions

Reading settings and options requires payroll.read or payroll.write and COMPANY view permission. Editing requires payroll.write, COMPANY edit permission, an active subscription and an unlocked company. Downloads require PAYS view permission and read or write scope, even though the method is POST; an expired subscription does not itself block downloads.

Every chart response contains revision and an ETag header. Send that exact quoted ETag as If-Match on every settings mutation, including initialise, create, delete, reset and Farm Focus refresh. A successful write returns the complete chart and next ETag. GET never creates a chart or department overrides.

GET /api/company/1/gl-settings
Authorization: Bearer CUSTOMER_TOKEN

HTTP/1.1 200 OK
ETag: "REVISION"

PATCH /api/company/1/gl-settings
Authorization: Bearer CUSTOMER_TOKEN
If-Match: "REVISION"
Content-Type: application/json

{"include_date":true,"date_format":"%Y-%m-%d","date_option":"Pay Run End Date"}

A stale ETag returns 412. Re-read before retrying. After a lost response, re-read to discover whether the operation succeeded; replaying a successful create/reset with the old ETag fails. The API serialises its writes across workers. Legacy browser forms do not use revisions and can still overwrite settings later.

Settings endpoints

Paths in this table are relative to /api/company/{company_id}/gl-settings.

Method and pathBehavior
GETComplete chart, flags, configured status, revision and advisories; all legs, including hidden Farm Focus clearing legs.
GET /optionsJurisdiction-specific categories, employee/company post-tax deductions, date formats/options and templates.
POST /initialise{"template":"lp"} persists defaults only when no usable chart exists. Templates: lp, xero, myob.
PATCHChange only supplied company flags and Xero department tracking category.
POST /rowsCreate one leg; the server assigns its ID and ownership.
PATCH /rows/{id}Change supplied row fields and department overrides; omissions survive.
DELETE /rows/{id}Erase exactly that row and its overrides; return the resulting chart.
GET /defaults?template=lpPreview replacement flags, rows, tracking category, removal counts and both revisions; saves nothing.
POST /restore-defaultsAtomically replace the chart with the previewed template; explicit confirmation required.
GET /farm-focus/codesConnection status and available provider codes; leaves GL mappings untouched.
POST /farm-focus/refreshRefresh provider labels/descriptions and account-code mirrors on existing mappings; never delete legs.

Company fields are negate_credit_amounts, include_date, include_software_name, include_nil_amounts, date_format, date_option, enable_farm_focus_gl_codes and xero_department_tracking_category.

Row fields are base_attr, account_label, account_code, is_debit, split_by_department, export_to_csv, farm_focus_code_id, split_farm_focus_submissions_by_pay and departments. Standard creation requires category, label and code; debit and inclusion default true, splits false. Farm Focus creation derives display/code fields from the selected provider code. Provider labels, category labels, canonical markers and ownership IDs are read-only. send_to_bank_transactions remains a read-only desktop field.

export_to_csv also controls the configurable JSON/Xero/MYOB pipeline. negate_credit_amounts controls credit signs; disabling it adds a debit/credit column to CSV. Duplicate categories and account codes are valid double-entry legs. No operation rebalances amounts or changes pay calculations.

POST /api/company/1/gl-settings/rows
If-Match: "REVISION"

{"base_attr":"gross","account_label":"Wages","account_code":"6000"}

PATCH /api/company/1/gl-settings/rows/42
If-Match: "NEXT_REVISION"

{"split_by_department":true,"departments":[{"department_id":7,"account_code":"6010"}]}

Omitted fields, rows and department overrides are preserved. An empty department code inherits the row code. A department without an override is returned with inherited:true and is not inserted by a read. Duplicate department IDs and foreign-company IDs are rejected. Unknown fields and explicit null writable fields are rejected; use empty strings for clearable text. A saved legacy category stays readable and can receive unrelated edits; newly assigned categories must come from options.

An unconfigured chart returns transient defaults with null row IDs and configured:false. Initialise before editing. Deleting the last row is permitted, but standard exports then use defaults again. To exclude categories, turn off row inclusion instead of deleting every row.

Reset and recovery

Reset permanently deletes the existing rows, department overrides and mappings. Before resetting, save the complete GET response as gl-settings-<company_id>-<revision>.json.

GET /api/company/1/gl-settings/defaults?template=xero

POST /api/company/1/gl-settings/restore-defaults
If-Match: "CHART_REVISION_FROM_PREVIEW"

{"template":"xero","template_revision":"TEMPLATE_REVISION_FROM_PREVIEW","confirm_reset":true}

A changed chart or template returns 412 before deleting anything. LP chooses AU/NZ defaults; Xero and MYOB use their existing templates. Xero sets tracking to Department, LP clears it, and MYOB preserves it. Templates are editable starting points, not guarantees of balanced journals. Current settings also affect exports for historical pays.

Reapply saved settings and recreate rows to recover values; IDs may change and must be re-read. Exact ID/state recovery requires a customer-database backup and may roll back unrelated payroll work. There is no automatic undo endpoint; reverting application code does not recover deleted configuration.

Farm Focus

Enabling the mode, assigning a nonempty mapping, discovering codes and refreshing require the Farm Focus add-on. Saved data remains readable after expiry; disabling the mode or clearing a mapping remains allowed. Unrelated edits do not contact the provider.

Discovery returns connected, not_connected, token_expired or no_matching_company, plus codes and setup_path. Provider failures return an error rather than an empty successful catalogue. Tokens, farm IDs and customer overrides are never accepted from callers. NZ connections use employer IRD; AU uses ABN, always scoped to the authenticated customer.

Consent/reconnection uses /admin/company/gl_codes. The customer signs in normally, or a partner uses an already-authorised session handoff. This API grants no additional handoff capability. Refreshing provider credentials may rotate server-held tokens independently of local GL writes.

PATCH /api/company/1/gl-settings/rows/42
If-Match: "REVISION"

{"farm_focus_code_id":"100","split_farm_focus_submissions_by_pay":true}

Assignment validates the code against that farm and fills its labels and account-code mirror. Custom account labels survive. Clearing a mapping clears provider labels and its account-code mirror. Refresh reports missing provider codes as advisories and keeps their mapping IDs for recovery. All legs remain stored; farm_focus_canonical identifies the existing invoice engine's selected leg. Duplicate-mapping warnings are advisory.

File downloads

POST /api/pay-run/123/gl-postings/csv
Authorization: Bearer CUSTOMER_TOKEN
Content-Type: application/json

{"pay_ids":[101,102]}

POST /api/pay-run/123/gl-postings/pdf
Authorization: Bearer CUSTOMER_TOKEN

Omitted body or {} selects every completed pay in the run. A nonempty pay_ids list selects exactly those completed pays. Empty lists, duplicates, nonpositive IDs and unknown fields are 422. Wrong-run/company IDs are 404 for the entire request; explicitly selected pending pays and runs with no completed pays are 409. Default selection excludes pending pays.

Responses are raw file attachments, with private/no-store caching: UTF-8 text/csv or application/pdf. CSV uses the Excel dialect, quotes every cell and has no header. The optional date and software-name columns follow company flags. PDF uses the existing template and partner branding. CSV preserves the software-name behavior of the UI CSV action. Each output reads one consistent database snapshot.

The existing GET /api/pay-run/{id}/gl-postings keeps its JSON envelope and fields. Its date follows the configured date format, or is empty when dates are disabled. Credit signs follow the negate setting. Existing AU/NZ arithmetic and report limitations are unchanged; PDF and CSV are not interchangeable representations of the custom chart.

Errors and throttling

GL errors use FastAPI's detail envelope, for example {"detail":"GL settings changed. Read the current chart and retry."}. Validation details may be a list. Existing authentication and throttling behavior is preserved; rate-limit responses use {"error":"Rate limit exceeded: …"}.

StatusMeaning
401 / 403Authentication failure / permission, scope or entitlement denied.
404 / 409Resource outside the selected tenant/company or missing / invalid state.
412 / 428Stale revision or changed connection / missing If-Match.
422Invalid input; no partial configuration saved.
429 / 503Rate limited / database busy; respect retry guidance, re-read and retry.
502 / 504Provider unavailable or malformed response / provider timeout.
500Local persistence or report rendering failed; never treated as a successful save/download.

Ordinary calls use authenticated partner-key throttling; PDF uses the customer render limit. Counters are per worker, so these are not promises of an exact global throughput ceiling.