RESTful API for accessing accounting data. All endpoints require authentication via API key.
API Key Authentication
Include your API key in the Authorization header with the Bearer scheme.
Example Header
Authorization: Bearer <your-api-key>
Error Response (401)
{
"error": {
"code": "UNAUTHORIZED",
"message": "Unauthorized"
}
}Structured Error Shape
All API errors return a consistent JSON shape: { error: { code: string, message: string } }.
/api/v1/coaRetrieve the chart of accounts hierarchy.
Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| active | boolean | Optional | Filter by active status (default: true). Use `all=true` to include inactive. |
| all | boolean | Optional | Include inactive COA entries. |
| search | string | Optional | Search by name or code (regex). |
Response
[
{
"_id": "...",
"parent": null,
"code": "1",
"name": "Current Assets",
"position": "Db",
"category": "Asset",
"isActive": true
}
]/api/v1/accountsRetrieve accounts. Supports filters and lookup by ID.
Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| id | string | Optional | Get a single account by ID. |
| number | string | Optional | Filter by exact account number. |
| coa | string | Optional | Filter accounts by parent COA ID. |
| all | boolean | Optional | Include inactive accounts (default: active only). |
Response
[
{
"_id": "...",
"coa": "...",
"number": "10101",
"name": "Petty Cash",
"balance": 5000000,
"isActive": true
}
]/api/v1/transactionsList transactions with optional filters.
Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| id | string | Optional | Get a single transaction by ID. |
| code | string | Optional | Filter by transaction code (case-insensitive partial match). |
| status | string | Optional | Filter by status: Pending, Confirmed, Rejected, Reversed. |
| source | string | Optional | Filter by source: api, ui. |
| startDate | string (YYYY-MM-DD) | Optional | Filter by effective date (inclusive start). |
| endDate | string (YYYY-MM-DD) | Optional | Filter by effective date (inclusive end). |
| vendor | string | Optional | Search by reference field (case-insensitive partial match). |
| includeDetails | boolean | Optional | Include journal line details. |
Response
[
{
"_id": "...",
"code": "GJ-20260701-001",
"effectiveDate": "2026-07-01T00:00:00.000Z",
"amount": 1000000,
"status": "Confirmed",
"reference": "INV-001",
"information": "Payment received",
"source": "api",
"created": { "at": "...", "by": "..." },
"evidence": [
{ "url": "/uploads/evidence/...", "description": "Invoice scan" }
]
}
]/api/v1/transactions/:idGet a single transaction by ID with journal line details.
Response
{
"_id": "...",
"code": "GJ-20260701-001",
"effectiveDate": "2026-07-01T00:00:00.000Z",
"amount": 1000000,
"status": "Confirmed",
"source": "api",
"evidence": [],
"details": [
{ "account": { "number": "10101", "name": "Petty Cash" }, "debit": 1000000, "credit": 0 },
{ "account": { "number": "40101", "name": "Revenue" }, "debit": 0, "credit": 1000000 }
]
}/api/v1/transactionsCreate a new transaction. Supports dry-run, idempotency, evidence, and evidence descriptions.
Request Body
{
"type": "General",
"effectiveDate": "2026-07-01",
"reference": "INV-001",
"information": "Payment received",
"dryRun": false,
"evidence": [
{ "url": "https://example.com/invoice.pdf", "description": "Invoice scan" }
],
"lines": [
{ "accountId": "...", "debit": 1000000, "credit": 0 },
{ "accountId": "...", "debit": 0, "credit": 1000000 }
]
}Response
{
"_id": "...",
"code": "GJ-20260701-001",
"status": "Pending",
"source": "api"
}Idempotency: Send Idempotency-Key header to prevent duplicate submissions. The server caches the response for the key and returns it on reuse.
Dry-run: Set dryRun: true to validate the transaction without persisting. Returns a validation summary.
/api/v1/transactions/:idUpdate a pending transaction. Replaces all journal lines if provided.
Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| id | string | Required | Transaction ID (in path). |
Request Body
{
"effectiveDate": "2026-07-02",
"reference": "INV-001",
"information": "Updated info",
"lines": [
{ "accountId": "...", "debit": 2000000, "credit": 0 },
{ "accountId": "...", "debit": 0, "credit": 2000000 }
]
}Response
{
"message": "Updated."
}/api/v1/transactions/:id?action=confirmConfirm a pending transaction. Affects account balances.
Response
{
"message": "Confirmed."
}/api/v1/transactions/:id?action=rejectReject a pending transaction.
Response
{
"message": "Rejected."
}/api/v1/transactions/:id?action=cancelCancel a pending transaction (soft delete — sets status to Canceled, hidden from ledger).
Response
{
"message": "Deleted."
}/api/v1/transactions/:id?action=reverseCreate a reversal for a confirmed transaction. Creates a pending reversal with opposite journal lines. The original is only marked as Reversed when the reversal transaction is confirmed.
Response
{
"message": "Reversal created.",
"reversalId": "...",
"reversalCode": "REV-GJ-20260709-123"
}/api/v1/transactions/:id/evidenceUpload an evidence file to a transaction. Supports optional description.
Request Body
multipart/form-data: file: (binary) description: "Invoice scan" (optional)
Response
{
"url": "/uploads/evidence/12345-invoice.pdf",
"description": "Invoice scan"
}/api/v1/transactions/:id/evidence?url=...Remove evidence by URL from a transaction.
Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| url | string | Required | URL of the evidence to remove. |
Response
{
"message": "Evidence removed."
}/api/v1/transaction-typesList available transaction types and their code prefixes.
Response
{
"General": "GJ",
"FundTransfer": "FT",
"Expense": "EX",
"Revenue": "RV",
"Purchase": "PC",
"Sales": "SL",
"Payroll": "PR",
"Tax": "TX",
"Depreciation": "DP",
"Closing": "CE"
}/api/v1/ledger-periodsRetrieve ledger entries for a specific account within a date range. Returns opening balance, period mutations, and running balance.
Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| accountId | string | Required | Account ID to retrieve ledger for. |
| startDate | string (YYYY-MM-DD) | Optional | Start date (inclusive). Defaults to beginning of current year. |
| endDate | string (YYYY-MM-DD) | Optional | End date (inclusive). Defaults to today. |
Response
{
"account": { "number": "10101", "name": "Petty Cash" },
"coa": { "code": "1", "name": "Current Assets", "position": "Db" },
"openingBalance": 0,
"startDate": "2026-01-01",
"endDate": "2026-07-01",
"rows": [
{ "date": "2026-07-01T00:00:00.000Z", "code": "GJ-20260701-001", "information": "Payment", "debit": 1000000, "credit": 0, "balance": 1000000 }
]
}/api/v1/reports/balance-sheetGenerate the balance sheet as of a specific date.
Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| date | string (YYYY-MM-DD) | Optional | Date as of which to generate the balance sheet. Defaults to today. |
Response
{
"asOfDate": "2026-07-01T00:00:00.000Z",
"assets": { "_id": "Asset", "code": "", "name": "ASSET", "position": "Db", "children": [...], "accounts": [], "total": 50000000 },
"liabilities": { "_id": "Liability", "code": "", "name": "LIABILITY", "position": "Cr", "children": [...], "accounts": [], "total": 10000000 },
"equity": { "_id": "Equity", "code": "", "name": "EQUITY", "position": "Cr", "children": [...], "accounts": [], "total": 40000000 },
"netIncome": 5000000
}/api/v1/reports/income-statementGenerate the income statement for a date range.
Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| startDate | string (YYYY-MM-DD) | Optional | Start date (inclusive). Defaults to Jan 1 of current year. |
| endDate | string (YYYY-MM-DD) | Optional | End date (inclusive). Defaults to today. |
Response
{
"startDate": "2026-01-01T00:00:00.000Z",
"endDate": "2026-07-01T00:00:00.000Z",
"revenue": { "_id": "Revenue", "code": "", "name": "REVENUE", "position": "Cr", "category": "Revenue", "parent": null, "children": [...], "total": 50000000 },
"cogs": { "_id": "COGS", "code": "", "name": "COGS", "position": "Db", "category": "COGS", "parent": null, "children": [...], "total": 20000000 },
"expenses": { "_id": "Expense", "code": "", "name": "EXPENSE", "position": "Db", "category": "Expense", "parent": null, "children": [...], "total": 25000000 },
"grossProfit": 30000000,
"netProfit": 5000000
}All errors return the same JSON shape: { error: { code: string, message: string } }
Additional Error Codes
UNBALANCED_JOURNAL — Debits must equal credits (HTTP 400).
NOT_PENDING — Transaction is not in Pending status (HTTP 400).
ACCOUNT_NOT_FOUND — Referenced account ID does not exist (HTTP 404).
Store securely: Treat your API key like a password. Do not expose it in client-side code or version control.
Regenerate periodically: You can regenerate your API key from your profile page at any time. Regenerating invalidates the previous key immediately.
Date format: All dates should be in ISO 8601 format (YYYY-MM-DD) or ISO string (YYYY-MM-DDTHH:mm:ss.sssZ).
Transaction source: Transactions created via the API are automatically marked with source: "api" to distinguish them from UI-created transactions.
Idempotency: Use the Idempotency-Key header on POST /api/v1/transactions to safely retry requests without creating duplicates. Keys expire after a period.
Dry-run validation: Set dryRun: true on POST /api/v1/transactions to validate journal lines, account existence, and balanced books without persisting the transaction.
Evidence: Upload supporting documents via POST /api/v1/transactions/:id/evidence (multipart/form-data). Optionally attach a description field. Evidence can also be provided inline during creation via the evidence array in the request body.