POST .../compare, which is also non-destructive (it returns deltas, no writes).
Required scope
| Endpoint | Scope |
|---|---|
GET trial-balance | accounting:read OR migration:read |
GET ar-aging | accounting:read OR migration:read |
GET ap-aging | accounting:read OR migration:read |
GET inventory-valuation | accounting:read OR migration:read |
GET cash-balance | accounting:read OR migration:read |
GET counts | accounting:read OR migration:read |
POST compare | migration:read (narrower; migration-specific) |
accounting:read can run reconciliation reports during normal operations; a migration-specific key with migration:read (and nothing else) can do the same during a cutover window.
Trial balance
as_of_date=YYYY-MM-DD(default: today). Snapshot date for the trial balance.external_source=versa(default: all). Restrict to journal entries imported from a single source. Use this to verify that ONLY the migrated GL ties; subsequent native postings are excluded.
totals.balance equal to 0.00. Anything else is a data error and unfreeze will block.
AR aging
totals.total must equal the AR control-account balance in the trial balance. That tie is the primary AR proof.
AP aging
Same shape as AR aging; vendor-keyed instead of customer-keyed.Inventory valuation
as_of_date=YYYY-MM-DD(default: today)method(default: entity’s costing method) -fifo,avg, orlot_costlocation_id(optional) - filter to one warehouse
total_value must equal the Inventory control-account balance in the trial balance.
Cash balance
gl_balance equals the trial-balance value for that account. bank_balance is the running bank-reconciliation balance. They tie when all transactions are cleared; uncleared rows are flagged for review.
Resource counts
external_source filters to records imported from that source via the bulk endpoint. Omit it to see total counts across all sources.
Compare external records (the penny-match endpoint)
This is the workhorse. Submit external records (from the legacy ERP) and the API returns the per-record verdict against your Arcus data.external_resource values:
ar_aging_by_customer- per-customer AR aging bucketsap_aging_by_vendor- per-vendor AP aging bucketstrial_balance_by_account- per-GL-account debit/credit/balanceresource_counts- object-level counts
tolerance_cents is the per-record delta you accept (default: 1 cent). Set to 0 for exact ties.
Response:
matched records balance to the penny. mismatched records have at least one field outside tolerance_cents. missing_in_arcus records exist in the external file but not in Arcus. extra_in_arcus records exist in Arcus but not in the external file.
Hard cap: 5000 records per call. Split larger comparisons into batches.
Suggested cutover-day workflow
- Pre-cutover (week of): run trial balance + counts daily. Confirm you can reproduce the same totals from the legacy ERP. Spot-check 5 to 10 named accounts via
compare. - Cutover Friday EOD (T-0): freeze the entity. Run final reconciliation suite. Snapshot legacy source data alongside the Arcus database snapshot.
- Cutover Saturday morning: run a top-up bulk-import sync for any data that changed between Thursday’s full load and Friday EOD freeze. Re-run reconciliation.
- Cutover Saturday evening: swap traffic, then run
POST .../cutover/verifywhich fires the full reconciliation suite. This is the gate that unblocks unfreeze. - Cutover Sunday: smoke-test critical user flows. Re-run individual reconciliation reports as needed.
- Cutover Monday go-live: keep the reconciliation key live for a week so the operator can investigate any reported discrepancies.
Error envelope
Like the rest of the public API, every 4xx response follows the canonical envelope:Related
- Cutover orchestration - the freeze / snapshot / swap / verify / unfreeze sequence that consumes these reads.
- Migrating Data into Arcus - the bulk-load step that populates the data these endpoints read.
- Idempotency - request-level idempotency semantics.

