Practice Management
Practice management APIs for partner firms. All endpoints require the requesting entity to be an active partner firm (enforced by requirePartner).
Client Entities
List Client Entities
GET /api/practice/clients?firmEntityId={firmEntityId}Returns all active client entities managed by the partner firm.
Create Client Entity
POST /api/practice/clientsCreates a new entity, seeds default chart of accounts and books, links it to the partner firm, and syncs the Stripe subscription.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
firmEntityId | string | Yes | Partner firm entity ID |
name | string | Yes | Client business name |
type | string | No | Entity type (llc, corp, sole_prop, etc.) |
industry | string | No | Industry classification |
tier | string | No | Client subscription tier (STARTER, PROFESSIONAL, BUSINESS). Default: STARTER |
billingMode | string | No | consolidated or client_direct. Default: consolidated |
Response
{
"entity": { "id": "ent_new", "name": "Acme Corp", "...": "..." },
"link": { "id": "pcl_123", "clientTier": "STARTER", "billingMode": "consolidated", "monthlyFee": 79 }
}Invite Client User
POST /api/practice/clients/{entityId}/inviteSends an email invitation to a client user to join the entity.
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | Invitee email address |
role | string | No | Role to assign (ADMIN, MEMBER, VIEWER). Default: VIEWER |
Time Tracking
List Time Entries
GET /api/practice/time?firmEntityId={firmEntityId}Query parameters
| Field | Type | Required | Description |
|---|---|---|---|
firmEntityId | string | Yes | Partner firm entity ID |
clientEntityId | string | No | Filter by client entity |
from | string | No | Start date (ISO 8601) |
to | string | No | End date (ISO 8601) |
unbilledOnly | boolean | No | Only return unbilled entries |
Response
{
"entries": [ { "id": "te_1", "hours": 2.5, "description": "Month-end close", "..." : "..." } ],
"totalHours": 12.5,
"billableHours": 10.0
}Create Time Entry
POST /api/practice/time| Field | Type | Required | Description |
|---|---|---|---|
firmEntityId | string | Yes | Partner firm entity ID |
entityId | string | Yes | Client entity ID |
date | string | Yes | Date of work (ISO 8601) |
hours | number | Yes | Hours worked |
description | string | No | Description of work |
billable | boolean | No | Whether billable. Default: true |
rate | number | No | Hourly rate in cents |
Delete Time Entry
DELETE /api/practice/time?timeEntryId={timeEntryId}&firmEntityId={firmEntityId}Deletes a time entry. Invoiced entries cannot be deleted.
Engagements
List Engagements
GET /api/practice/engagements?firmEntityId={firmEntityId}Returns all engagements with their associated tasks.
Create Engagement
POST /api/practice/engagements| Field | Type | Required | Description |
|---|---|---|---|
firmEntityId | string | Yes | Partner firm entity ID |
entityId | string | Yes | Client entity ID |
name | string | Yes | Engagement name |
startDate | string | Yes | Start date (ISO 8601) |
type | string | No | bookkeeping, tax_prep, advisory, audit, other |
recurrence | string | No | monthly, quarterly, annual, or null |
notes | string | No | Additional notes |
Update Engagement / Complete Task
PATCH /api/practice/engagementsComplete a task:
{ "firmEntityId": "...", "taskId": "task_123" }Update engagement status:
{ "firmEntityId": "...", "engagementId": "eng_123", "status": "completed" }Billing
Get Billing Overview
GET /api/practice/billing?firmEntityId={firmEntityId}Returns partner tier, volume discount, and per-client billing breakdown.
Generate Invoice from Time Entries
POST /api/practice/billing/invoiceCreates an AR invoice from unbilled time entries for a specific client.
| Field | Type | Required | Description |
|---|---|---|---|
firmEntityId | string | Yes | Partner firm entity ID |
clientEntityId | string | Yes | Client entity ID |
timeEntryIds | string[] | Yes | Array of time entry IDs to invoice |
Response
{
"invoice": { "id": "inv_123", "total": 250000, "lineCount": 3 },
"markedEntries": 3
}Reports
Generate PDF Report
GET /api/reports/pdf?entityId={entityId}&bookId={bookId}&report={type}&from={date}&to={date}Server-side financial report generation. Returns HTML (Content-Type: text/html).
| Parameter | Type | Required | Description |
|---|---|---|---|
entityId | string | Yes | Entity ID |
bookId | string | Yes | Book ID |
report | string | Yes | balance_sheet, income_statement, or trial_balance |
from | string | Yes | Period start date |
to | string | Yes | Period end date |
Create Shareable Report Link
POST /api/reports/shareGenerates a time-limited shareable link to a report.
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | Yes | Entity ID |
reportType | string | Yes | Report type |
parameters | object | Yes | Report parameters (bookId, from, to) |
expiresInDays | number | No | Expiry in days. Default: 7 |
Response
{
"shareUrl": "https://app.axiomatic.com/api/reports/share/tok_abc123",
"expiresAt": "2026-03-11T00:00:00Z"
}Access Shared Report
GET /api/reports/share/{token}Redirects to the rendered report if the token is valid and not expired. Increments access count.