Skip to main content

Accounting API

Access Scope

All accounting endpoints are protected by both permissions and object/workspace access rules.

A user must not only hold the relevant accounting permission, but also belong to the workspace or project owning the requested connection, review, sync record, category, mapping, or period.

This applies in particular to:

  • connections
  • reviews
  • syncs
  • exception summary
  • categories
  • mappings
  • periods

Connections

Create Connection

POST /accounting/connections
{
"workspaceId": 1,
"providerType": "INTUIT",
"name": "QuickBooks Production",
"credentials": { "clientId": "...", "clientSecret": "...", "realmId": "...", "accessToken": "...", "refreshToken": "...", "tokenExpiresAt": "..." },
"config": {},
"syncMode": "AUTO_PUSH",
"requireReview": true,
"requireCompletenessForSync": true,
"syncScheduleCron": "0 */6 * * *",
"projectIds": [1, 2]
}
FieldRequiredDescription
workspaceIdYesWorkspace ID
providerTypeYesMANUAL, INTUIT, or custom
nameYesDisplay name
credentialsYesProvider-specific credentials
syncModeNoMANUAL, MANUAL_PUSH, AUTO_PUSH, BIDIRECTIONAL (default: MANUAL_PUSH)
requireReviewNoWhether entries need review before sync (default: true)
requireCompletenessForSyncNoRequire entry completeness for sync (default: true)
syncScheduleCronNoCron expression for scheduled pull (BIDIRECTIONAL mode)
projectIdsNoRestrict to specific projects

Provider credentials are encrypted before persistence and are not returned by connection list/detail APIs.

List Connections

GET /accounting/connections?workspaceId={id}

Get / Update / Deactivate Connection

GET /accounting/connections/{id}
PATCH /accounting/connections/{id}
DELETE /accounting/connections/{id}

Returned connection payloads exclude stored provider credentials.

Backfill Reviews

Queue all existing entries (that don't already have a review) for accounting review on a connection.

POST /accounting/connections/{id}/backfill-reviews

Response:

{ "queued": 42 }

Use this after creating a new connection to populate the review queue with existing entries.

Reviews

Permission required: accounting.review

List Reviews

GET /accounting/reviews?workspaceId={id}&status=QUEUED&limit=20&offset=0

Query parameters: connectionId, status, reviewerId, workspaceId, limit, offset.

Create Review

POST /accounting/reviews
{ "entryId": 42, "connectionId": "uuid-or-null" }

Get Review

GET /accounting/reviews/{id}

Assign Reviewer (self-assign)

PATCH /accounting/reviews/{id}/assign

Approve Review

PATCH /accounting/reviews/{id}/approve
{ "categoryId": "category-uuid", "notes": "Verified and categorized" }

If the connection has syncMode: AUTO_PUSH, the entry is automatically pushed to the external system after approval.

Reject Review

PATCH /accounting/reviews/{id}/reject
{ "notes": "Missing invoice document" }

Request Changes

PATCH /accounting/reviews/{id}/request-changes
{ "notes": "Please attach the receipt" }

Batch Approve

POST /accounting/reviews/batch/approve
{ "reviewIds": ["uuid1", "uuid2"], "categoryId": "category-uuid" }

Batch Reject

POST /accounting/reviews/batch/reject
{ "reviewIds": ["uuid1", "uuid2"], "notes": "Incomplete documentation" }

Chart of Accounts (Categories)

Permission required: accounting.categories

List Categories

GET /accounting/categories?workspaceId={id}

Create Category

POST /accounting/categories
{
"workspaceId": 1,
"code": "6010",
"name": "Office Supplies",
"accountType": "EXPENSE",
"parentId": "parent-uuid-or-null"
}

Account types: ASSET, LIABILITY, EQUITY, REVENUE, EXPENSE.

Update / Delete Category

PATCH /accounting/categories/{id}
DELETE /accounting/categories/{id}

Mappings

Permission required: accounting.mappings

Party Mappings

GET /accounting/mappings/parties?connectionId={id}
POST /accounting/mappings/parties
POST /accounting/mappings/parties/batch
DELETE /accounting/mappings/parties/{id}

Create payload:

{
"connectionId": "uuid",
"partyId": 5,
"externalId": "QB-VENDOR-123",
"externalType": "Vendor",
"externalName": "Acme Corp"
}

Tax Mappings

GET /accounting/mappings/taxes?connectionId={id}
POST /accounting/mappings/taxes
DELETE /accounting/mappings/taxes/{id}

Project Routing

GET /accounting/mappings/projects?connectionId={id}
POST /accounting/mappings/projects
{ "connectionId": "uuid", "projectIds": [1, 2, 3] }

Sync Operations

Push Entry

POST /accounting/sync/push
{ "entryId": 42, "connectionId": "uuid" }

Validations before push:

  • Entry must not be excluded from sync (excludeFromSync: false)
  • If requireCompletenessForSync, entry must be complete
  • Entry date must not fall within a closed accounting period
  • If entry was previously synced and marked STALE, performs an update instead of create

Pull Entries

POST /accounting/sync/pull
{ "connectionId": "uuid", "since": "2026-01-01T00:00:00Z" }

Webhook Security

If a connection defines config.webhookSecret, incoming accounting webhooks must include:

X-Webhook-Secret: <configured-secret>

Requests with a mismatched secret are rejected before webhook actions are processed.

For INTUIT, Moonlight also supports provider-specific signature verification when webhookVerifierToken is present in the stored credentials. In that case the request must include a valid Intuit signature header.

Pull Chart of Accounts

POST /accounting/sync/pull-chart-of-accounts
{ "connectionId": "uuid" }

Imports accounts from the external system into Moonlight categories.

Pull External Parties

POST /accounting/sync/pull-parties
{ "connectionId": "uuid" }

Resolve Conflict

POST /accounting/sync/resolve-conflict
{ "syncId": "uuid", "resolution": "KEEP_LOCAL" }

Resolutions: KEEP_LOCAL (re-push), KEEP_EXTERNAL (accept external version).

Get Sync Status

GET /accounting/sync/entry/{entryId}
GET /accounting/sync/pending/{connectionId}

List Sync Exceptions

Workspace-scoped sync lists for exception workbenches:

GET /accounting/syncs?workspaceId={id}&status=FAILED
GET /accounting/syncs?workspaceId={id}&status=STALE
GET /accounting/syncs?workspaceId={id}&status=CONFLICT

Each row returns the sync record together with its connection and entry context.

Retry Sync

Retry a single degraded sync record:

POST /accounting/syncs/{id}/retry

Response:

{ "success": true }

Batch Retry Syncs

POST /accounting/syncs/retry-batch
{ "syncIds": ["uuid1", "uuid2"] }

Response:

{ "success": true, "retried": 2 }

Exception Summary

Operational summary for accountant workbenches and owner control panels:

GET /accounting/exceptions/summary?workspaceId={id}

Response:

{
"failedSyncs": 3,
"staleSyncs": 7,
"conflictingSyncs": 1,
"unreconciledEntries": 24,
"requestedDocuments": 6,
"rejectedReviews": 2,
"changesRequestedReviews": 4
}

Dashboard Exception Section

GET /accounting/dashboard?workspaceId={id} now includes an exceptionSummary object in addition to review stats, sync stats, and connections. This is intended for operational control surfaces rather than decorative analytics.

Accounting Periods

Permission required: accounting.periods

GET /accounting/periods?workspaceId={id}
GET /accounting/periods/{id}
POST /accounting/periods
PATCH /accounting/periods/{id}/close
PATCH /accounting/periods/{id}/reopen
DELETE /accounting/periods/{id}

Create payload:

{ "workspaceId": 1, "name": "Q1 2026", "startDate": "2026-01-01", "endDate": "2026-03-31" }

Dashboard

GET /accounting/dashboard?workspaceId={id}

Returns:

{
"reviewStats": { "queued": 5, "inReview": 2, "approved": 15, "rejected": 1, "changesRequested": 0 },
"syncStats": { "pending": 3, "synced": 12, "failed": 1, "stale": 2, "conflict": 0 },
"connections": [...],
"exceptionSummary": {
"failedSyncs": 1,
"staleSyncs": 2,
"conflictingSyncs": 0,
"unreconciledEntries": 24,
"requestedDocuments": 6,
"rejectedReviews": 1,
"changesRequestedReviews": 0
}
}

Webhooks

POST /webhooks/accounting/{connectionId}

Unauthenticated endpoint. Supported actions:

  • ENTRY_APPROVED — Sets entry status to COMPLETED
  • ENTRY_REJECTED — Sets entry status to REJECTED
  • ENTRY_VOIDED — Sets entry status to VOIDED
  • DOCUMENT_REQUESTED — Creates a document request
  • ENTRY_UPDATED — Records an update event

Permissions

PermissionDescription
accounting.manageManage connections and sync operations
accounting.reviewReview entries in accounting queue
accounting.categoriesManage chart of accounts
accounting.periodsManage accounting periods
accounting.mappingsManage party and tax mappings