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:
connectionsreviewssyncsexception summarycategoriesmappingsperiods
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]
}
| Field | Required | Description |
|---|---|---|
workspaceId | Yes | Workspace ID |
providerType | Yes | MANUAL, INTUIT, or custom |
name | Yes | Display name |
credentials | Yes | Provider-specific credentials |
syncMode | No | MANUAL, MANUAL_PUSH, AUTO_PUSH, BIDIRECTIONAL (default: MANUAL_PUSH) |
requireReview | No | Whether entries need review before sync (default: true) |
requireCompletenessForSync | No | Require entry completeness for sync (default: true) |
syncScheduleCron | No | Cron expression for scheduled pull (BIDIRECTIONAL mode) |
projectIds | No | Restrict 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 toCOMPLETEDENTRY_REJECTED— Sets entry status toREJECTEDENTRY_VOIDED— Sets entry status toVOIDEDDOCUMENT_REQUESTED— Creates a document requestENTRY_UPDATED— Records an update event
Permissions
| Permission | Description |
|---|---|
accounting.manage | Manage connections and sync operations |
accounting.review | Review entries in accounting queue |
accounting.categories | Manage chart of accounts |
accounting.periods | Manage accounting periods |
accounting.mappings | Manage party and tax mappings |