Introduction
The Solarium API is a GraphQL API that gives you full programmatic access to your accounting data: accounts, contacts, journal entries, receipts, and financial reports.
All requests go to a single endpoint. Authentication is via API key (Bearer token) or JWT. Every query and mutation requires an organizationId. Your API key is scoped to one organization, so use the myOrganizations query to resolve it.
Base URL: https://solarium-api.lovemaple.app/graphql
Quickstart
Grab your API key from Settings > API Keys in the dashboard, then make your first request:
# curl: resolve your org ID
curl -X POST https://solarium-api.lovemaple.app/graphql \
-H "Authorization: Bearer sol_your_key_here" \
-H "Content-Type: application/json" \
-d '{"query": "{ myOrganizations { id name } }"}'
# Python: full example
import httpx
API_URL = "https://solarium-api.lovemaple.app/graphql"
API_KEY = "sol_your_key_here"
def query(q, variables=None):
resp = httpx.post(
API_URL,
json={"query": q, "variables": variables or {}},
headers={"Authorization": f"Bearer {API_KEY}"},
)
return resp.json()["data"]
# 1. Get your org ID
orgs = query("{ myOrganizations { id name } }")
org_id = orgs["myOrganizations"][0]["id"]
# 2. List accounts
accounts = query("""
query($orgId: UUID!) {
listAccounts(organizationId: $orgId, limit: 10) {
items { id name accountType currentBalance }
totalCount
}
}
""", {"orgId": org_id})
# 3. Record an expense
result = query("""
mutation($orgId: UUID!) {
createReceipt(
organizationId: $orgId
vendorName: "Subway"
amount: "42.50"
receiptDate: "2025-01-15"
status: "processed"
) { receipt { id } success error }
}
""", {"orgId": org_id}){
"data": {
"myOrganizations": [
{
"id": "a1b2c3d4-...",
"name": "My Company Inc."
}
]
}
}# curl: resolve your org ID
curl -X POST https://solarium-api.lovemaple.app/graphql \
-H "Authorization: Bearer sol_your_key_here" \
-H "Content-Type: application/json" \
-d '{"query": "{ myOrganizations { id name } }"}'
# Python: full example
import httpx
API_URL = "https://solarium-api.lovemaple.app/graphql"
API_KEY = "sol_your_key_here"
def query(q, variables=None):
resp = httpx.post(
API_URL,
json={"query": q, "variables": variables or {}},
headers={"Authorization": f"Bearer {API_KEY}"},
)
return resp.json()["data"]
# 1. Get your org ID
orgs = query("{ myOrganizations { id name } }")
org_id = orgs["myOrganizations"][0]["id"]
# 2. List accounts
accounts = query("""
query($orgId: UUID!) {
listAccounts(organizationId: $orgId, limit: 10) {
items { id name accountType currentBalance }
totalCount
}
}
""", {"orgId": org_id})
# 3. Record an expense
result = query("""
mutation($orgId: UUID!) {
createReceipt(
organizationId: $orgId
vendorName: "Subway"
amount: "42.50"
receiptDate: "2025-01-15"
status: "processed"
) { receipt { id } success error }
}
""", {"orgId": org_id}){
"data": {
"myOrganizations": [
{
"id": "a1b2c3d4-...",
"name": "My Company Inc."
}
]
}
}Authentication
Authenticate by passing your API key as a Bearer token in the Authorization header.
API keys are created in the Solarium dashboard at Settings > API Keys. API keys start with sol_ and are shown once at creation. Store them securely. Only the SHA-256 hash is stored on our end.
API keys are scoped to a single organization. You cannot access another organization's data with an API key. Admin operations (managing members, creating other API keys) are not available via API key.
Rate Limiting
API key requests are limited to 5,000 requests per hour per API key. The limit resets on a rolling 1-hour window from the first request.
Every API key response includes rate limit headers:
X-RateLimit-Limit: your hourly quota (5000)X-RateLimit-Remaining: requests left in the current window
If you exceed the limit, requests return 429 Too Many Requests with a Retry-After header. JWT-authenticated requests (dashboard sessions) are not rate limited.
# API Key auth (recommended for integrations)
curl -X POST https://solarium-api.lovemaple.app/graphql \
-H "Authorization: Bearer sol_abc123..." \
-H "Content-Type: application/json" \
-d '{"query": "{ myOrganizations { id name } }"}'
# JWT auth (for user sessions)
curl -X POST https://solarium-api.lovemaple.app/graphql \
-H "Authorization: JWT eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{"query": "{ myOrganizations { id name } }"}'# Unauthenticated request
{
"errors": [
{ "message": "Authentication Required." }
]
}
# Wrong Organization
{
"errors": [
{ "message": "API Key Not Authorized For This Organization." }
]
}
# Rate limit exceeded (429)
{
"errors": [
{ "message": "Rate Limit Exceeded. 5,000 Requests/Hour." }
]
}
# Headers: Retry-After: 60# API Key auth (recommended for integrations)
curl -X POST https://solarium-api.lovemaple.app/graphql \
-H "Authorization: Bearer sol_abc123..." \
-H "Content-Type: application/json" \
-d '{"query": "{ myOrganizations { id name } }"}'
# JWT auth (for user sessions)
curl -X POST https://solarium-api.lovemaple.app/graphql \
-H "Authorization: JWT eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{"query": "{ myOrganizations { id name } }"}'# Unauthenticated request
{
"errors": [
{ "message": "Authentication Required." }
]
}
# Wrong Organization
{
"errors": [
{ "message": "API Key Not Authorized For This Organization." }
]
}
# Rate limit exceeded (429)
{
"errors": [
{ "message": "Rate Limit Exceeded. 5,000 Requests/Hour." }
]
}
# Headers: Retry-After: 60Errors
The Solarium API returns errors in a consistent JSON shape. GraphQL requests always return 200 OK at the HTTP level. Errors appear in the errors array of the response body.
The only exceptions are 429 Too Many Requests (rate limit) and 400 Bad Request (malformed JSON or invalid GraphQL syntax), which return non-200 HTTP status codes.
Error Object
Each error has a message string. Some errors include a path array indicating which field triggered the error.
Common Errors
| Message | Cause |
|---|---|
Authentication Required. | No token or API key provided |
API Key Not Authorized For This Organization. | API key belongs to a different organization |
Organization Not Found. | Invalid organizationId |
Not A Member Of This Organization. | JWT user is not a member of this organization |
API Keys Cannot Perform Admin Operations. | API key used for an admin-only mutation (e.g. managing members) |
Must Be Owner Or Admin. | Insufficient role for this operation |
Rate Limit Exceeded. 5,000 Requests/Hour. | API key exceeded hourly quota (HTTP 429) |
Mutation Errors
Mutations return a success boolean and an error string instead of throwing. A failed mutation returns success: false with a human-readable error. The HTTP status is still 200.
# Successful mutation
mutation {
createAccount(
organizationId: "a1b2c3d4-..."
name: "Office Supplies"
accountType: "expense"
classification: "expense"
) {
account { id name }
success
error
}
}# GraphQL-level error (in errors array)
{
"errors": [
{
"message": "Authentication Required.",
"path": ["createAccount"]
}
],
"data": { "createAccount": null }
}
# Mutation-level error (success: false)
{
"data": {
"createAccount": {
"account": null,
"success": false,
"error": "Account with this name already exists."
}
}
}
# Rate limit error (HTTP 429)
{
"errors": [
{ "message": "Rate Limit Exceeded. 5,000 Requests/Hour." }
]
}# Successful mutation
mutation {
createAccount(
organizationId: "a1b2c3d4-..."
name: "Office Supplies"
accountType: "expense"
classification: "expense"
) {
account { id name }
success
error
}
}# GraphQL-level error (in errors array)
{
"errors": [
{
"message": "Authentication Required.",
"path": ["createAccount"]
}
],
"data": { "createAccount": null }
}
# Mutation-level error (success: false)
{
"data": {
"createAccount": {
"account": null,
"success": false,
"error": "Account with this name already exists."
}
}
}
# Rate limit error (HTTP 429)
{
"errors": [
{ "message": "Rate Limit Exceeded. 5,000 Requests/Hour." }
]
}Pagination
All list endpoints use offset-based pagination with a consistent interface.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | Int | 25 | Number of items per page (max 200) |
offset | Int | 0 | Number of items to skip |
search | String | — | Case-insensitive text filter (searches relevant fields like name, memo, etc.) |
sortBy | String | — | Field to sort by (e.g. name, currentBalance, txnDate) |
sortDir | String | asc | Sort direction: asc or desc |
Response shape
Every paginated response includes:
items: the array of resultstotalCount: total number of matching records (before pagination)pageSize: thelimitthat was appliedoffset: theoffsetthat was applied
To check if there are more pages: offset + items.length < totalCount.
Requesting beyond the end of the data returns an empty items array, not an error.
# Page 1: first 10 accounts
query {
listAccounts(
organizationId: "a1b2c3d4-..."
limit: 10
offset: 0
sortBy: "name"
sortDir: "asc"
) {
items { id name currentBalance }
totalCount
pageSize
offset
}
}
# Page 2: next 10
query {
listAccounts(
organizationId: "a1b2c3d4-..."
limit: 10
offset: 10
sortBy: "name"
sortDir: "asc"
) {
items { id name currentBalance }
totalCount
pageSize
offset
}
}# Page 1 response
{
"data": {
"listAccounts": {
"items": [
{ "id": "...", "name": "Accounts Payable", "currentBalance": 4200.00 },
{ "id": "...", "name": "Accounts Receivable", "currentBalance": 12400.00 }
],
"totalCount": 24,
"pageSize": 10,
"offset": 0
}
}
}
# Last page (fewer items than limit)
{
"data": {
"listAccounts": {
"items": [
{ "id": "...", "name": "Travel", "currentBalance": 890.00 }
],
"totalCount": 24,
"pageSize": 10,
"offset": 20
}
}
}# Page 1: first 10 accounts
query {
listAccounts(
organizationId: "a1b2c3d4-..."
limit: 10
offset: 0
sortBy: "name"
sortDir: "asc"
) {
items { id name currentBalance }
totalCount
pageSize
offset
}
}
# Page 2: next 10
query {
listAccounts(
organizationId: "a1b2c3d4-..."
limit: 10
offset: 10
sortBy: "name"
sortDir: "asc"
) {
items { id name currentBalance }
totalCount
pageSize
offset
}
}# Page 1 response
{
"data": {
"listAccounts": {
"items": [
{ "id": "...", "name": "Accounts Payable", "currentBalance": 4200.00 },
{ "id": "...", "name": "Accounts Receivable", "currentBalance": 12400.00 }
],
"totalCount": 24,
"pageSize": 10,
"offset": 0
}
}
}
# Last page (fewer items than limit)
{
"data": {
"listAccounts": {
"items": [
{ "id": "...", "name": "Travel", "currentBalance": 890.00 }
],
"totalCount": 24,
"pageSize": 10,
"offset": 20
}
}
}Accounts
List Accounts
Returns a paginated list of accounts in the chart of accounts. Supports search by name and sorting.
Parameters
organizationIdUUID!requiredOrganization ID
limitIntPage size (default 25, max 200)
offsetIntNumber of records to skip
searchStringFilter by name (case-insensitive)
sortByStringField to sort by (e.g. name, currentBalance)
sortDirStringasc or desc (default asc)
query {
listAccounts(
organizationId: "a1b2c3d4-..."
limit: 10
search: "expense"
) {
items {
id
name
accountType
classification
subType
currentBalance
active
}
totalCount
pageSize
offset
}
}{
"data": {
"listAccounts": {
"items": [
{
"id": "f7e6d5c4-...",
"name": "Office Supplies",
"accountType": "expense",
"classification": "expense",
"subType": "",
"currentBalance": 1250.00,
"active": true
}
],
"totalCount": 24,
"pageSize": 10,
"offset": 0
}
}
}Create an Account
Creates a new account in the chart of accounts.
Parameters
organizationIdUUID!requiredOrganization ID
nameString!requiredAccount name
accountTypeString!requiredbank, accounts_receivable, other_current_asset, fixed_asset, credit_card, accounts_payable, other_current_liability, long_term_liability, equity, income, cogs, expense, other_income, other_expense
classificationString!requiredasset, liability, equity, revenue, expense
subTypeStringOptional sub-type label
parentIdUUIDParent account ID for hierarchical accounts
mutation {
createAccount(
organizationId: "a1b2c3d4-..."
name: "Office Supplies"
accountType: "expense"
classification: "expense"
) {
account {
id
name
accountType
classification
}
success
error
}
}{
"data": {
"createAccount": {
"account": {
"id": "f7e6d5c4-...",
"name": "Office Supplies",
"accountType": "expense",
"classification": "expense"
},
"success": true,
"error": null
}
}
}query {
listAccounts(
organizationId: "a1b2c3d4-..."
limit: 10
search: "expense"
) {
items {
id
name
accountType
classification
subType
currentBalance
active
}
totalCount
pageSize
offset
}
}{
"data": {
"listAccounts": {
"items": [
{
"id": "f7e6d5c4-...",
"name": "Office Supplies",
"accountType": "expense",
"classification": "expense",
"subType": "",
"currentBalance": 1250.00,
"active": true
}
],
"totalCount": 24,
"pageSize": 10,
"offset": 0
}
}
}mutation {
createAccount(
organizationId: "a1b2c3d4-..."
name: "Office Supplies"
accountType: "expense"
classification: "expense"
) {
account {
id
name
accountType
classification
}
success
error
}
}{
"data": {
"createAccount": {
"account": {
"id": "f7e6d5c4-...",
"name": "Office Supplies",
"accountType": "expense",
"classification": "expense"
},
"success": true,
"error": null
}
}
}Contacts
List Contacts
Returns a paginated list of vendors and customers.
Parameters
organizationIdUUID!requiredOrganization ID
limitIntPage size (default 25, max 200)
offsetIntNumber of records to skip
searchStringFilter by name
query {
listContacts(
organizationId: "a1b2c3d4-..."
limit: 10
search: "uber"
) {
items {
id
contactType
displayName
email
phone
balance
active
}
totalCount
}
}{
"data": {
"listContacts": {
"items": [
{
"id": "b2c3d4e5-...",
"contactType": "vendor",
"displayName": "Uber",
"email": "",
"phone": "",
"balance": 0,
"active": true
}
],
"totalCount": 1
}
}
}Create a Contact
Creates a new vendor or customer.
Parameters
organizationIdUUID!requiredOrganization ID
contactTypeString!requiredvendor or customer
displayNameString!requiredContact name
emailStringEmail address
phoneStringPhone number
mutation {
createContact(
organizationId: "a1b2c3d4-..."
contactType: "vendor"
displayName: "Staples"
email: "[email protected]"
) {
contact { id displayName contactType }
success
error
}
}{
"data": {
"createContact": {
"contact": {
"id": "c3d4e5f6-...",
"displayName": "Staples",
"contactType": "vendor"
},
"success": true,
"error": null
}
}
}query {
listContacts(
organizationId: "a1b2c3d4-..."
limit: 10
search: "uber"
) {
items {
id
contactType
displayName
email
phone
balance
active
}
totalCount
}
}{
"data": {
"listContacts": {
"items": [
{
"id": "b2c3d4e5-...",
"contactType": "vendor",
"displayName": "Uber",
"email": "",
"phone": "",
"balance": 0,
"active": true
}
],
"totalCount": 1
}
}
}mutation {
createContact(
organizationId: "a1b2c3d4-..."
contactType: "vendor"
displayName: "Staples"
email: "[email protected]"
) {
contact { id displayName contactType }
success
error
}
}{
"data": {
"createContact": {
"contact": {
"id": "c3d4e5f6-...",
"displayName": "Staples",
"contactType": "vendor"
},
"success": true,
"error": null
}
}
}Journal Entries
List Journal Entries
Returns a paginated list of journal entries with their debit/credit lines.
Parameters
organizationIdUUID!requiredOrganization ID
limitIntPage size (default 25, max 200)
offsetIntNumber of records to skip
searchStringFilter by memo
query {
listJournalEntries(
organizationId: "a1b2c3d4-..."
limit: 5
) {
items {
id
txnDate
totalAmount
memo
sourceType
lines {
id
debit
credit
description
account { id name }
}
}
totalCount
}
}{
"data": {
"listJournalEntries": {
"items": [
{
"id": "d4e5f6a7-...",
"txnDate": "2025-01-15",
"totalAmount": "500.00",
"memo": "Office rent — January",
"sourceType": "manual",
"lines": [
{
"id": "e5f6a7b8-...",
"debit": "500.00",
"credit": "0.00",
"description": "Rent",
"account": { "id": "...", "name": "Rent Expense" }
},
{
"id": "f6a7b8c9-...",
"debit": "0.00",
"credit": "500.00",
"description": "Paid",
"account": { "id": "...", "name": "Checking" }
}
]
}
],
"totalCount": 142
}
}
}Create a Journal Entry
Creates a manual journal entry with debit/credit lines. Total debits must equal total credits.
Parameters
organizationIdUUID!requiredOrganization ID
txnDateDate!requiredTransaction date (YYYY-MM-DD)
totalAmountDecimal!requiredTotal amount (sum of debits)
memoStringDescription / memo
lines[JournalEntryLineInput!]!requiredArray of line items. Each: accountId (UUID!), debit (Decimal), credit (Decimal), description (String)
mutation {
createJournalEntry(
organizationId: "a1b2c3d4-..."
txnDate: "2025-01-15"
totalAmount: "500.00"
memo: "Office rent — January"
lines: [
{
accountId: "rent-expense-uuid"
debit: "500.00"
credit: "0"
},
{
accountId: "checking-uuid"
debit: "0"
credit: "500.00"
}
]
) {
journalEntry { id txnDate totalAmount memo }
success
error
}
}{
"data": {
"createJournalEntry": {
"journalEntry": {
"id": "d4e5f6a7-...",
"txnDate": "2025-01-15",
"totalAmount": "500.00",
"memo": "Office rent — January"
},
"success": true,
"error": null
}
}
}query {
listJournalEntries(
organizationId: "a1b2c3d4-..."
limit: 5
) {
items {
id
txnDate
totalAmount
memo
sourceType
lines {
id
debit
credit
description
account { id name }
}
}
totalCount
}
}{
"data": {
"listJournalEntries": {
"items": [
{
"id": "d4e5f6a7-...",
"txnDate": "2025-01-15",
"totalAmount": "500.00",
"memo": "Office rent — January",
"sourceType": "manual",
"lines": [
{
"id": "e5f6a7b8-...",
"debit": "500.00",
"credit": "0.00",
"description": "Rent",
"account": { "id": "...", "name": "Rent Expense" }
},
{
"id": "f6a7b8c9-...",
"debit": "0.00",
"credit": "500.00",
"description": "Paid",
"account": { "id": "...", "name": "Checking" }
}
]
}
],
"totalCount": 142
}
}
}mutation {
createJournalEntry(
organizationId: "a1b2c3d4-..."
txnDate: "2025-01-15"
totalAmount: "500.00"
memo: "Office rent — January"
lines: [
{
accountId: "rent-expense-uuid"
debit: "500.00"
credit: "0"
},
{
accountId: "checking-uuid"
debit: "0"
credit: "500.00"
}
]
) {
journalEntry { id txnDate totalAmount memo }
success
error
}
}{
"data": {
"createJournalEntry": {
"journalEntry": {
"id": "d4e5f6a7-...",
"txnDate": "2025-01-15",
"totalAmount": "500.00",
"memo": "Office rent — January"
},
"success": true,
"error": null
}
}
}Receipts
List Receipts
Returns a paginated list of receipts/expenses.
Parameters
organizationIdUUID!requiredOrganization ID
limitIntPage size (default 25, max 200)
offsetIntNumber of records to skip
searchStringFilter by vendor name
query {
listReceipts(
organizationId: "a1b2c3d4-..."
limit: 10
) {
items {
id
vendorName
amount
taxAmount
receiptDate
status
source
category { id name }
paymentAccount { id name }
}
totalCount
}
}{
"data": {
"listReceipts": {
"items": [
{
"id": "e5f6a7b8-...",
"vendorName": "Subway",
"amount": "42.50",
"taxAmount": "5.53",
"receiptDate": "2025-01-15",
"status": "processed",
"source": "api",
"category": {
"id": "...",
"name": "Meals & Entertainment"
},
"paymentAccount": {
"id": "...",
"name": "Visa *4242"
}
}
],
"totalCount": 89
}
}
}Create a Receipt
Creates a receipt and its linked journal entry in one call. This is the primary way to record an expense via the API.
Parameters
organizationIdUUID!requiredOrganization ID
vendorNameStringVendor / merchant name
amountDecimalTotal amount including tax
taxAmountDecimalTax portion (HST/GST)
receiptDateDateDate of purchase (YYYY-MM-DD)
statusStringdraft, pending, processed, reviewed (default pending)
categoryIdUUIDExpense account to categorize under
paymentAccountIdUUIDBank/credit card account used to pay
mutation {
createReceipt(
organizationId: "a1b2c3d4-..."
vendorName: "Subway"
amount: "42.50"
taxAmount: "5.53"
receiptDate: "2025-01-15"
status: "processed"
categoryId: "meals-expense-uuid"
paymentAccountId: "visa-uuid"
) {
receipt {
id
vendorName
amount
receiptDate
status
category { id name }
paymentAccount { id name }
}
success
error
}
}{
"data": {
"createReceipt": {
"receipt": {
"id": "e5f6a7b8-...",
"vendorName": "Subway",
"amount": "42.50",
"receiptDate": "2025-01-15",
"status": "processed",
"category": {
"id": "...",
"name": "Meals & Entertainment"
},
"paymentAccount": {
"id": "...",
"name": "Visa *4242"
}
},
"success": true,
"error": null
}
}
}query {
listReceipts(
organizationId: "a1b2c3d4-..."
limit: 10
) {
items {
id
vendorName
amount
taxAmount
receiptDate
status
source
category { id name }
paymentAccount { id name }
}
totalCount
}
}{
"data": {
"listReceipts": {
"items": [
{
"id": "e5f6a7b8-...",
"vendorName": "Subway",
"amount": "42.50",
"taxAmount": "5.53",
"receiptDate": "2025-01-15",
"status": "processed",
"source": "api",
"category": {
"id": "...",
"name": "Meals & Entertainment"
},
"paymentAccount": {
"id": "...",
"name": "Visa *4242"
}
}
],
"totalCount": 89
}
}
}mutation {
createReceipt(
organizationId: "a1b2c3d4-..."
vendorName: "Subway"
amount: "42.50"
taxAmount: "5.53"
receiptDate: "2025-01-15"
status: "processed"
categoryId: "meals-expense-uuid"
paymentAccountId: "visa-uuid"
) {
receipt {
id
vendorName
amount
receiptDate
status
category { id name }
paymentAccount { id name }
}
success
error
}
}{
"data": {
"createReceipt": {
"receipt": {
"id": "e5f6a7b8-...",
"vendorName": "Subway",
"amount": "42.50",
"receiptDate": "2025-01-15",
"status": "processed",
"category": {
"id": "...",
"name": "Meals & Entertainment"
},
"paymentAccount": {
"id": "...",
"name": "Visa *4242"
}
},
"success": true,
"error": null
}
}
}Reports
Dashboard Summary
High-level financial snapshot: revenue, expenses, net income, receipt counts for a date range.
Parameters
organizationIdUUID!requiredOrganization ID
startDateDateStart of range (defaults to start of current month)
endDateDateEnd of range (defaults to today)
query {
dashboardSummary(
organizationId: "a1b2c3d4-..."
startDate: "2025-01-01"
endDate: "2025-03-31"
) {
totalRevenue
totalExpenses
netIncome
receiptCount
unreviewedCount
}
}{
"data": {
"dashboardSummary": {
"totalRevenue": "84500.00",
"totalExpenses": "52300.00",
"netIncome": "32200.00",
"receiptCount": 89,
"unreviewedCount": 3
}
}
}Income Statement
Full profit & loss report broken down by account.
Parameters
organizationIdUUID!requiredOrganization ID
startDateDateStart of range
endDateDateEnd of range
query {
incomeStatement(
organizationId: "a1b2c3d4-..."
startDate: "2025-01-01"
endDate: "2025-03-31"
) {
incomeAccounts { accountId accountName total }
expenseAccounts { accountId accountName total }
totalIncome
totalExpenses
netIncome
}
}{
"data": {
"incomeStatement": {
"incomeAccounts": [
{ "accountId": "...", "accountName": "Sales", "total": "84500.00" }
],
"expenseAccounts": [
{ "accountId": "...", "accountName": "Rent", "total": "18000.00" },
{ "accountId": "...", "accountName": "Payroll", "total": "28000.00" },
{ "accountId": "...", "accountName": "Office Supplies", "total": "6300.00" }
],
"totalIncome": "84500.00",
"totalExpenses": "52300.00",
"netIncome": "32200.00"
}
}
}Account Balances
Current balance for every account in the chart of accounts.
Parameters
organizationIdUUID!requiredOrganization ID
query {
accountBalances(organizationId: "a1b2c3d4-...") {
accountId
accountName
accountType
classification
balance
}
}{
"data": {
"accountBalances": [
{
"accountId": "...",
"accountName": "Checking",
"accountType": "bank",
"classification": "asset",
"balance": "24680.50"
},
{
"accountId": "...",
"accountName": "Accounts Receivable",
"accountType": "accounts_receivable",
"classification": "asset",
"balance": "12400.00"
}
]
}
}query {
dashboardSummary(
organizationId: "a1b2c3d4-..."
startDate: "2025-01-01"
endDate: "2025-03-31"
) {
totalRevenue
totalExpenses
netIncome
receiptCount
unreviewedCount
}
}{
"data": {
"dashboardSummary": {
"totalRevenue": "84500.00",
"totalExpenses": "52300.00",
"netIncome": "32200.00",
"receiptCount": 89,
"unreviewedCount": 3
}
}
}query {
incomeStatement(
organizationId: "a1b2c3d4-..."
startDate: "2025-01-01"
endDate: "2025-03-31"
) {
incomeAccounts { accountId accountName total }
expenseAccounts { accountId accountName total }
totalIncome
totalExpenses
netIncome
}
}{
"data": {
"incomeStatement": {
"incomeAccounts": [
{ "accountId": "...", "accountName": "Sales", "total": "84500.00" }
],
"expenseAccounts": [
{ "accountId": "...", "accountName": "Rent", "total": "18000.00" },
{ "accountId": "...", "accountName": "Payroll", "total": "28000.00" },
{ "accountId": "...", "accountName": "Office Supplies", "total": "6300.00" }
],
"totalIncome": "84500.00",
"totalExpenses": "52300.00",
"netIncome": "32200.00"
}
}
}query {
accountBalances(organizationId: "a1b2c3d4-...") {
accountId
accountName
accountType
classification
balance
}
}{
"data": {
"accountBalances": [
{
"accountId": "...",
"accountName": "Checking",
"accountType": "bank",
"classification": "asset",
"balance": "24680.50"
},
{
"accountId": "...",
"accountName": "Accounts Receivable",
"accountType": "accounts_receivable",
"classification": "asset",
"balance": "12400.00"
}
]
}
}Batch Operations
All batch mutations accept up to 500 items per call. Failures are per-item. One bad record does not roll back the others. Each item runs in its own database savepoint.
Batch Create Accounts
Create up to 500 accounts in a single call.
Parameters
organizationIdUUID!requiredOrganization ID
items[AccountInput!]!requiredArray of accounts. Each: name (String!), accountType (String!), classification (String!), subType (String), parentId (UUID)
mutation {
batchCreateAccounts(
organizationId: "a1b2c3d4-..."
items: [
{ name: "Office Supplies", accountType: "expense", classification: "expense" },
{ name: "Travel", accountType: "expense", classification: "expense" },
{ name: "Software", accountType: "expense", classification: "expense" }
]
) {
created
errors { index error }
}
}{
"data": {
"batchCreateAccounts": {
"created": 3,
"errors": []
}
}
}Batch Create Contacts
Create up to 500 contacts in a single call.
Parameters
organizationIdUUID!requiredOrganization ID
items[ContactInput!]!requiredArray of contacts. Each: contactType (String!), displayName (String!), email (String), phone (String)
mutation {
batchCreateContacts(
organizationId: "a1b2c3d4-..."
items: [
{ contactType: "vendor", displayName: "Staples" },
{ contactType: "vendor", displayName: "Amazon" }
]
) {
created
errors { index error }
}
}{
"data": {
"batchCreateContacts": {
"created": 2,
"errors": []
}
}
}Batch Create Journal Entries
Create up to 500 journal entries in a single call. Each entry includes its own lines.
Parameters
organizationIdUUID!requiredOrganization ID
items[JournalEntryInput!]!requiredArray of entries. Each: txnDate (Date!), totalAmount (Decimal!), memo (String), lines ([JELineInput!]!)
mutation {
batchCreateJournalEntries(
organizationId: "a1b2c3d4-..."
items: [
{
txnDate: "2025-01-15"
totalAmount: "100.00"
memo: "Office supplies"
lines: [
{ accountId: "expense-uuid", debit: "100.00", credit: "0" },
{ accountId: "bank-uuid", debit: "0", credit: "100.00" }
]
}
]
) {
created
errors { index error }
}
}{
"data": {
"batchCreateJournalEntries": {
"created": 1,
"errors": []
}
}
}Batch Create Receipts
Record up to 500 expenses in a single call. Each creates a receipt + journal entry.
Parameters
organizationIdUUID!requiredOrganization ID
items[ReceiptInput!]!requiredArray of receipts. Each: vendorName (String!), amount (Decimal!), receiptDate (Date!), categoryId (UUID), paymentAccountId (UUID), taxAmount (Decimal)
mutation {
batchCreateReceipts(
organizationId: "a1b2c3d4-..."
items: [
{ vendorName: "Subway", amount: "42.50", receiptDate: "2025-01-15" },
{ vendorName: "Tim Hortons", amount: "5.99", receiptDate: "2025-01-15" }
]
) {
created
errors { index error }
}
}{
"data": {
"batchCreateReceipts": {
"created": 2,
"errors": []
}
}
}mutation {
batchCreateAccounts(
organizationId: "a1b2c3d4-..."
items: [
{ name: "Office Supplies", accountType: "expense", classification: "expense" },
{ name: "Travel", accountType: "expense", classification: "expense" },
{ name: "Software", accountType: "expense", classification: "expense" }
]
) {
created
errors { index error }
}
}{
"data": {
"batchCreateAccounts": {
"created": 3,
"errors": []
}
}
}mutation {
batchCreateContacts(
organizationId: "a1b2c3d4-..."
items: [
{ contactType: "vendor", displayName: "Staples" },
{ contactType: "vendor", displayName: "Amazon" }
]
) {
created
errors { index error }
}
}{
"data": {
"batchCreateContacts": {
"created": 2,
"errors": []
}
}
}mutation {
batchCreateJournalEntries(
organizationId: "a1b2c3d4-..."
items: [
{
txnDate: "2025-01-15"
totalAmount: "100.00"
memo: "Office supplies"
lines: [
{ accountId: "expense-uuid", debit: "100.00", credit: "0" },
{ accountId: "bank-uuid", debit: "0", credit: "100.00" }
]
}
]
) {
created
errors { index error }
}
}{
"data": {
"batchCreateJournalEntries": {
"created": 1,
"errors": []
}
}
}mutation {
batchCreateReceipts(
organizationId: "a1b2c3d4-..."
items: [
{ vendorName: "Subway", amount: "42.50", receiptDate: "2025-01-15" },
{ vendorName: "Tim Hortons", amount: "5.99", receiptDate: "2025-01-15" }
]
) {
created
errors { index error }
}
}{
"data": {
"batchCreateReceipts": {
"created": 2,
"errors": []
}
}
}