UnitBoard API
The UnitBoard API is the same surface every screen in the product speaks to — accounts payable, work orders, copilot, search, and reports. No integration tolls, no double-entry, no proprietary file dumps.
https://unitboard.ai/apiAuthentication
Authenticated endpoints accept a Bearer token in the Authorization header. Tokens are scoped to your organization and can be rotated at any time. Internal traffic uses Supabase session cookies; both forms are accepted.
Health
Liveness and service status.
get/api/health
Liveness probe
Returns 200 with a small JSON envelope when the service is up. No auth required.
Response 200
Service is healthy.
okrequiredservicerequiredtimestamprequiredAccounts Payable
Invoice intake, AI extraction, approval, and rejection. Approving posts a journal entry to the GL.
post/api/ap/extract
Extract invoice from PDF
Runs Claude Vision over a base64-encoded PDF, matches the vendor against the directory, suggests a GL coding, and persists a draft invoice (status `extracted`) ready for human review.
Authorization header.Request body
filenamerequiredpdfBase64requiredBase64-encoded PDF body. The data-URL prefix (`data:application/pdf;base64,`) is tolerated and stripped server-side.
Response 200
Invoice extracted and persisted as a draft.
okrequiredinvoiceIdrequireddurationMsrequiredvendorrequiredMatched vendor name, or the raw extracted name.
accountrequiredGL account suggestion in `code — name` form, or null when no match.
confidencerequiredpost/api/ap/approve
Approve and post invoice
Posts a journal entry (debit each line's GL account, credit AP control) and marks the invoice `posted`. Idempotent on already-posted invoices is NOT guaranteed — caller should check `status` first.
Authorization header.Request body
invoiceIdrequiredResponse 200
Invoice approved and posted to the GL.
okrequiredjournalEntryIdrequiredpost/api/ap/reject
Reject invoice
Marks an invoice as `rejected`. Does not post to the GL.
Authorization header.Request body
invoiceIdrequiredResponse 200
Invoice marked rejected.
okrequiredWork Orders
Maintenance work order lifecycle — creation and status changes.
post/api/work-orders/create
Create work order
Opens a new maintenance work order on the given property (and optionally a unit / vendor). Defaults `priority=normal`, `status=open`.
Authorization header.Request body
titlerequireddescriptionpropertyIdrequiredunitIdprioritylownormalhighurgentestimatedCostvendorIdResponse 200
Work order created.
okrequiredidrequiredpost/api/work-orders/update-status
Update work order status
Transitions a work order to one of the canonical statuses. When set to `completed`, `closed_at` is stamped to now; any other status clears `closed_at` so re-opens stay honest.
Authorization header.Request body
idrequiredstatusrequiredopenin_progresson_holdcompletedcanceledResponse 200
Status updated.
okrequiredCopilot
Natural-language ledger and operations queries. Agentic tool-use loop over Anthropic Claude.
post/api/copilot/query
Natural-language query
Runs an agentic tool-use loop over Claude. The model has read access to ledger / property / leasing tools and is capped at 5 tool-call rounds. Pass the full conversation history each call — the route is stateless.
Authorization header.Request body
messagesrequiredResponse 200
Final answer produced.
answerrequiredtoolCallsrequiredTool names invoked, in order. Empty when the model answered from context alone.
Search
Global cross-entity search — properties, units, residents, leases, vendors, invoices, work orders, journal entries.
get/api/search
Global search
Cross-entity ILIKE search. Returns up to 5 hits per group. Queries shorter than 2 characters are answered with empty groups (200 OK) so a debounced typeahead can stay responsive.
Authorization header.Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
| q | string | optional | Search query. Leading/trailing whitespace is trimmed; `%` and `_` are escaped. |
Response 200
Search results grouped by entity.
resultsrequiredpropertiesrequiredunitsrequiredresidentsrequiredleasesrequiredvendorsrequiredinvoicesrequiredworkOrdersrequiredjournalEntriesrequiredReports
Packaged financial and operational statements. JSON by default; pass ?format=csv for an attachment.
get/api/reports/{slug}
Run a packaged report
Runs the named report and returns either a JSON shape (default) suitable for rendering, or a `text/csv` download when `?format=csv`. The same registry powers the in-app report tables, so JSON / CSV / table are always in agreement.
Authorization header.Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| slug | enum | required | Report identifier.profit-and-lossbalance-sheetcash-flowrent-rolldelinquencylease-expirations |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
| format | enum | optional | Pass `csv` to download a CSV attachment instead of JSON.csv |
| period | enum | optional | Time window in days. Only honored by reports that support a period.3090180365ytd |
Response 200
Report payload.
okrequiredslugrequiredtitlerequiredcolumnsrequiredrowsrequiredtotalssummaryperiodLabelperiodDaysActivity
Cross-entity activity feed (audit log).
get/api/activity
Cross-entity activity feed
Reverse-chronological activity events across properties, leases, invoices, journal entries, and work orders. Useful as an audit log or dashboard widget.
Authorization header.Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
| limit | integer | optional | Max number of events to return. |
| since | string (date-time) | optional | Return events at or after this ISO-8601 timestamp. |
Response 200
Activity events.
eventsrequiredAdmin
Privileged endpoints requiring the admin role.
post/api/admin/set-role
Set user role
Updates a user's role. Only callers with the `admin` role may invoke this; uses the Supabase service role internally to bypass RLS.
Authorization header.Request body
userIdrequiredrolerequiredadminoperatoraccountantviewerResponse 200
Role updated.
okrequiredAuth
Supabase authentication callbacks.
get/auth/callback
Supabase auth callback
Magic-link / OAuth callback. Exchanges the `code` query param for a session cookie, then redirects to `next` (default `/dashboard`). On failure, redirects to `/login?error=auth_callback_failed`.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
| code | string | required | Authorization code issued by Supabase. |
| next | string | optional | Path to redirect to on success. |