Reports
Generate financial reports for analysis, compliance, and decision-making.
Reports in SpeyBooks are derived views over the ledger. They are generated on demand from posted transactions — nothing is pre-calculated, cached, or manually adjusted.
Authentication
All endpoints require a valid API key. See Authentication.
How reports work
- Reports are read-only
- All values are derived from transactions
- Results are deterministic for a given ledger state
- Changing historical transactions will change historical reports
- There is no separate "reporting database"
Available reports
| Report | Endpoint | Description |
|---|---|---|
| Profit & Loss | /v1/reports/profit-loss | Income and expenses for a period |
| Balance Sheet | /v1/reports/balance-sheet | Financial position at a point in time |
| Trial Balance | /v1/reports/trial-balance | All account balances for verification |
| VAT Return | /v1/reports/vat | VAT summary for MTD submission |
| General Ledger | /v1/reports/general-ledger | Detailed ledger by account |
| Dashboard | /v1/reports/dashboard | High-level financial overview |
| Aged Debtors | /v1/reports/aged-debtors | Outstanding receivables by age |
| Aged Creditors | /v1/reports/aged-creditors | Outstanding payables by age |
| Financial Periods | /v1/reports/periods | Configured financial periods |
Profit & Loss
GET /v1/reports/profit-loss
Income statement showing revenue, expenses, and net profit for a date range.
curl "https://api.speybooks.com/v1/reports/profit-loss?from=2026-01-01&to=2026-03-31" \
-H "Authorization: Bearer sk_live_your_api_key"
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
from | string | Yes | Start date (YYYY-MM-DD) |
to | string | Yes | End date (YYYY-MM-DD) |
comparative | boolean | No | Include prior period comparison |
Response
{
"success": true,
"data": {
"period": {
"from": "2026-01-01",
"to": "2026-03-31"
},
"revenue": {
"accounts": [
{ "id": "acc_4000", "code": "4000", "name": "Sales", "balance": 5000000 },
{ "id": "acc_4100", "code": "4100", "name": "Consulting", "balance": 1500000 }
],
"total": 6500000
},
"expenses": {
"accounts": [
{ "id": "acc_5100", "code": "5100", "name": "Office Expenses", "balance": 250000 },
{ "id": "acc_5200", "code": "5200", "name": "Software", "balance": 500000 },
{ "id": "acc_5300", "code": "5300", "name": "Professional Fees", "balance": 750000 }
],
"total": 1500000
},
"grossProfit": 6500000,
"netProfit": 5000000,
"comparative": null
}
}
Response with comparative
When comparative=true, includes the equivalent prior period:
{
"success": true,
"data": {
"period": { "from": "2026-01-01", "to": "2026-03-31" },
"revenue": { "total": 6500000 },
"expenses": { "total": 1500000 },
"netProfit": 5000000,
"comparative": {
"period": { "from": "2025-10-01", "to": "2025-12-31" },
"totalRevenue": 5200000,
"totalExpenses": 1300000,
"netProfit": 3900000
}
}
}
Notes
- Revenue accounts normally carry credit balances
- Expense accounts normally carry debit balances
- Net profit = revenue − expenses
Balance Sheet
GET /v1/reports/balance-sheet
Statement of financial position as at a specific date.
curl "https://api.speybooks.com/v1/reports/balance-sheet?asOf=2026-03-31" \
-H "Authorization: Bearer sk_live_your_api_key"
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
asOf | string | Yes | Report date (YYYY-MM-DD) |
Response
{
"success": true,
"data": {
"asOf": "2026-03-31",
"assets": {
"accounts": [
{ "id": "acc_1100", "code": "1100", "name": "Accounts Receivable", "balance": 1250000 },
{ "id": "acc_1200", "code": "1200", "name": "Bank Account", "balance": 8500000 },
{ "id": "acc_1500", "code": "1500", "name": "Equipment", "balance": 2000000 }
],
"total": 11750000
},
"liabilities": {
"accounts": [
{ "id": "acc_2100", "code": "2100", "name": "Accounts Payable", "balance": 450000 },
{ "id": "acc_2200", "code": "2200", "name": "VAT Payable", "balance": 350000 }
],
"total": 800000
},
"equity": {
"accounts": [
{ "id": "acc_3000", "code": "3000", "name": "Share Capital", "balance": 100000 },
{ "id": "acc_3100", "code": "3100", "name": "Retained Earnings", "balance": 5850000 },
{ "id": "acc_3200", "code": "3200", "name": "Current Year Profit", "balance": 5000000 }
],
"total": 10950000
},
"netAssets": 10950000,
"checksum": true
}
}
Checksum
The checksum field confirms: Assets = Liabilities + Equity
If checksum is false, the ledger is inconsistent (this should never occur).
Trial Balance
GET /v1/reports/trial-balance
Lists all account balances for verification. Total debits must equal total credits.
curl "https://api.speybooks.com/v1/reports/trial-balance?asOf=2026-03-31" \
-H "Authorization: Bearer sk_live_your_api_key"
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
asOf | string | No | Report date (default: today) |
Response
{
"success": true,
"data": {
"asOf": "2026-03-31",
"accounts": [
{ "id": "acc_1100", "code": "1100", "name": "Accounts Receivable", "debit": 1250000, "credit": 0 },
{ "id": "acc_1200", "code": "1200", "name": "Bank Account", "debit": 8500000, "credit": 0 },
{ "id": "acc_2100", "code": "2100", "name": "Accounts Payable", "debit": 0, "credit": 450000 },
{ "id": "acc_2200", "code": "2200", "name": "VAT Payable", "debit": 0, "credit": 350000 },
{ "id": "acc_3000", "code": "3000", "name": "Share Capital", "debit": 0, "credit": 100000 },
{ "id": "acc_4000", "code": "4000", "name": "Sales", "debit": 0, "credit": 6500000 },
{ "id": "acc_5100", "code": "5100", "name": "Office Expenses", "debit": 250000, "credit": 0 }
],
"totals": {
"debit": 12500000,
"credit": 12500000
},
"balanced": true
}
}
Purpose
- Verifies ledger integrity
- Total debits must equal total credits
- Used by accountants to validate postings
VAT Return
GET /v1/reports/vat
VAT summary in MTD-compatible 9-box format.
curl "https://api.speybooks.com/v1/reports/vat?from=2026-01-01&to=2026-03-31" \
-H "Authorization: Bearer sk_live_your_api_key"
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
from | string | Yes | Period start date (YYYY-MM-DD) |
to | string | Yes | Period end date (YYYY-MM-DD) |
Response
{
"success": true,
"data": {
"period": {
"from": "2026-01-01",
"to": "2026-03-31"
},
"boxes": {
"box1": 130000,
"box2": 0,
"box3": 130000,
"box4": 30000,
"box5": 100000,
"box6": 650000,
"box7": 150000,
"box8": 0,
"box9": 0
},
"description": {
"box1": "VAT due on sales",
"box2": "VAT due on acquisitions from EU",
"box3": "Total VAT due (Box 1 + Box 2)",
"box4": "VAT reclaimed on purchases",
"box5": "Net VAT to pay/reclaim (Box 3 - Box 4)",
"box6": "Total sales excluding VAT",
"box7": "Total purchases excluding VAT",
"box8": "Total value of EU supplies",
"box9": "Total value of EU acquisitions"
}
}
}
Notes
- Derived directly from VAT control accounts
- No manual adjustments
- Suitable for submission via HMRC MTD APIs
See VAT Returns Guide for submission details.
General Ledger
GET /v1/reports/general-ledger
Detailed transaction listing by account. This is the authoritative audit trail.
curl "https://api.speybooks.com/v1/reports/general-ledger?from=2026-01-01&to=2026-01-31&accountId=acc_1200" \
-H "Authorization: Bearer sk_live_your_api_key"
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
from | string | Yes | Start date (YYYY-MM-DD) |
to | string | Yes | End date (YYYY-MM-DD) |
accountId | string | No | Filter by account (e.g., acc_1200) |
Response
{
"success": true,
"data": {
"period": { "from": "2026-01-01", "to": "2026-01-31" },
"accounts": [
{
"id": "acc_1200",
"code": "1200",
"name": "Bank Account",
"accountType": "asset",
"openingBalance": 5000000,
"transactions": [
{
"id": "txn_52",
"date": "2026-01-15",
"description": "Payment received - INV-0001",
"reference": "BACS-123",
"debit": 120000,
"credit": 0,
"runningBalance": 5120000
},
{
"id": "txn_53",
"date": "2026-01-20",
"description": "Office supplies",
"reference": "AMZN-456",
"debit": 0,
"credit": 5000,
"runningBalance": 5115000
}
],
"closingBalance": 5115000,
"totalDebit": 3500000,
"totalCredit": 385000
}
]
}
}
What this shows
- Opening balance
- All transactions in date order
- Running balance per transaction
- Closing balance
Dashboard
GET /v1/reports/dashboard
High-level financial snapshot intended for quick status checks.
curl https://api.speybooks.com/v1/reports/dashboard \
-H "Authorization: Bearer sk_live_your_api_key"
Response
{
"success": true,
"data": {
"currentPeriod": {
"from": "2026-01-01",
"to": "2026-01-31"
},
"bankBalance": 8500000,
"accountsReceivable": 1250000,
"accountsPayable": 450000,
"revenue": {
"current": 2150000,
"prior": 1800000,
"change": 19.4
},
"expenses": {
"current": 500000,
"prior": 420000,
"change": 19.0
},
"netProfit": {
"current": 1650000,
"prior": 1380000,
"change": 19.6
},
"overdueInvoices": {
"count": 3,
"total": 245000
},
"upcomingBills": {
"count": 5,
"total": 180000
}
}
}
Includes
- Bank balance
- Receivables / payables
- Revenue and expense trends
- Overdue invoices
- Upcoming bills
Aged Debtors
GET /v1/reports/aged-debtors
Outstanding receivables broken down by age buckets. Used for credit control and cash-flow management.
curl "https://api.speybooks.com/v1/reports/aged-debtors?asOfDate=2026-01-31" \
-H "Authorization: Bearer sk_live_your_api_key"
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
asOfDate | string | No | Report date (default: today) |
Aging buckets
- Current
- 1–30 days
- 31–60 days
- 61–90 days
- 90+ days
Response
{
"success": true,
"data": {
"reportDate": "2026-01-31",
"reportTitle": "Aged Debtors",
"contacts": [
{
"contactId": "cont_17",
"contactName": "Acme Corporation",
"invoices": [
{
"id": "inv_42",
"invoiceNumber": "INV-2026-0001",
"issueDate": "2026-01-15",
"dueDate": "2026-02-14",
"total": 120000,
"amountPaid": 0,
"outstanding": 120000,
"daysOverdue": 0,
"agingBucket": "current"
}
],
"current": 120000,
"days1to30": 0,
"days31to60": 0,
"days61to90": 0,
"days90plus": 0,
"total": 120000
},
{
"contactId": "cont_18",
"contactName": "TechStart Ltd",
"invoices": [
{
"id": "inv_38",
"invoiceNumber": "INV-2025-0042",
"issueDate": "2025-11-15",
"dueDate": "2025-12-15",
"total": 85000,
"amountPaid": 0,
"outstanding": 85000,
"daysOverdue": 47,
"agingBucket": "31-60"
}
],
"current": 0,
"days1to30": 0,
"days31to60": 85000,
"days61to90": 0,
"days90plus": 0,
"total": 85000
}
],
"totals": {
"current": 120000,
"days1to30": 0,
"days31to60": 85000,
"days61to90": 0,
"days90plus": 0,
"total": 205000
},
"summary": {
"totalContacts": 2,
"totalInvoices": 2
}
}
}
Aged Creditors
GET /v1/reports/aged-creditors
Outstanding payables using the same aging buckets as debtors. Used to manage upcoming obligations and supplier payments.
curl "https://api.speybooks.com/v1/reports/aged-creditors?asOfDate=2026-01-31" \
-H "Authorization: Bearer sk_live_your_api_key"
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
asOfDate | string | No | Report date (default: today) |
Response
Same structure as Aged Debtors, but for purchase invoices (amounts you owe to suppliers).
{
"success": true,
"data": {
"reportDate": "2026-01-31",
"reportTitle": "Aged Creditors",
"contacts": [
{
"contactId": "cont_25",
"contactName": "Office Supplies Ltd",
"current": 15000,
"days1to30": 0,
"days31to60": 0,
"days61to90": 0,
"days90plus": 0,
"total": 15000
}
],
"totals": {
"current": 15000,
"days1to30": 0,
"days31to60": 0,
"days61to90": 0,
"days90plus": 0,
"total": 15000
},
"summary": {
"totalContacts": 1,
"totalInvoices": 1
}
}
}
Financial Periods
GET /v1/reports/periods
Lists configured financial periods.
curl https://api.speybooks.com/v1/reports/periods \
-H "Authorization: Bearer sk_live_your_api_key"
Response
{
"success": true,
"data": {
"periods": [
{
"id": "period_1",
"name": "FY 2025-26",
"startDate": "2025-04-01",
"endDate": "2026-03-31",
"isCurrent": true,
"isClosed": false
},
{
"id": "period_2",
"name": "FY 2024-25",
"startDate": "2024-04-01",
"endDate": "2025-03-31",
"isCurrent": false,
"isClosed": true
}
]
}
}
Notes
- Periods define reporting boundaries
- Closed periods are read-only
- Current period is used by default where applicable
Key guarantees
- Reports are pure functions of the ledger
- No report stores its own state
- Results are reproducible and auditable
- Historical reports change only if history changes
Error codes
| Code | HTTP | Description |
|---|---|---|
validation_error | 400 | Missing required date parameters |
validation_error | 400 | Invalid date format (expected YYYY-MM-DD) |
validation_error | 400 | from date is after to date |
invalid_id | 400 | Malformed account ID in filter |
Amount format
All monetary values in reports are in minor units (pence for GBP):
5000000 = £50,000.00
130000 = £1,300.00
Divide by 100 for display.