Skip to main content

Bulk Entry Action

POST 

/api/ledger/entries/bulk

Dispatch one tracked bulk action over ledger entries. Eligible/excluded counts are computed server-side via EligibilityResolver BEFORE dispatch, so the response counts are accurate. The job reports progress via the tracked job log endpoints.

Not yet available to API tokens

This endpoint currently requires session authentication; Personal Access Token scope support is in progress.

Authentication: Requires Bearer token + accounting.sync permission (403 without it).

Request body fields:

  • action (required) — one of: sync_now (queue an immediate provider push), set_override (force sync on/off — requires override), rebuild (regenerate from source; posted entries corrected via reversal + replacement), unlink (sever the provider sync link so SKU stops tracking the remote doc — a later sync CREATES a new doc), clear_errors (dismiss parked needs_action / failed_retryable operations WITHOUT retrying), fetch_remote (the INBOUND mirror of sync_now — re-read the remote document(s) and re-grade the link state: drift / void / settled-lock; runs as a tracked job), delete (HARD-delete the entry — permanently removes the journal entry, its GL lines, provider sync links and operation history, and nulls any sibling reversal pointer; IRREVERSIBLE; unlike the other actions it runs even when ledger generation is disabled).
  • scope (optional, selected default | all | all_stale) — all targets every entry matching the CURRENT filters (send the same filter[...] / filter_groups query params as the list); all_stale targets every stale pre-cutover (frozen history) entry, so one rebuild call drains the entire stale worklist rather than only its preview page. Both are resolved server-side and capped at 5000; entry_ids is then optional/ignored.
  • entry_ids (array, required unless scope=all or scope=all_stale, max 1000) — the explicitly selected entry ids.
  • override (required when action=set_override) — force_enabled | force_disabled | null (clear).

Eligibility (excluded from the action, counted in excluded_count): sync_now → entries eligible on at least one connection; rebuild → source still exists; unlink and fetch_remote → entry currently has a live remote link; clear_errors → entry carries a clearable parked error; set_override and delete → always applicable.

Note: when ledger generation is disabled (kill switch) no job dispatches — the response carries note: "generation_disabled" and tracked_job_log_id: null. The delete action is the one exception: it always dispatches its job so test/erroneous entries can be cleaned up while the kill switch is on.

Response fields: tracked_job_log_id (null when no job dispatched), total (entries the job will process), eligible_count, excluded_count. When scope=all or scope=all_stale and the match set exceeds the cap (default 5000, ledger.bulk.all_scope_cap), the remainder is dropped and the response adds all_scope_truncated: true, matched_total (total entries matching the filters), and cap (the limit applied); the message then names how many of how many entries were started.

replace_nominal_code action (find & replace account): remaps every line deriving from_nominal_code_id to to_nominal_code_id across the selected/all-filtered entries by pinning a durable per-entry override (re-applied on every rebuild). Extra body fields when action = "replace_nominal_code":

  • from_nominal_code_id (required, integer, exists:nominal_codes)
  • to_nominal_code_id (required, integer, exists:nominal_codes, different from from) Runs as a tracked background job (tracked job log endpoints).

Request

Responses

OK

Response Headers
    Content-Type