All API endpoints use the /api/v1/ prefix. This prefix is centralized in packages/shared via SERVICE_PREFIXES.api and the apiPath() builder function, so future URI changes only require updating one file.
Authenticated endpoints require a JWT Bearer token in the Authorization header:
Authorization: Bearer <token>
Obtain a token via POST /api/v1/auth/login.
All errors follow a standard format:
"error" : " Human-readable message " ,
Method Path Description POST /api/v1/auth/registerCreate admin account + tenant POST /api/v1/auth/loginLogin, returns JWT (or changeToken if force-password-change) POST /api/v1/auth/change-passwordComplete forced password change (purpose-scoped JWT) POST /api/v1/auth/accept-inviteAccept team invite, set password POST /api/v1/auth/contractor-tokenGenerate contractor inspection token (configurable TTL)
Method Path Auth Description GET /api/v1/auth/meJWT Current user info + tenant config
Method Path Auth Description GET /api/v1/leadsJWT List leads (paginated, sortable, filterable) GET /api/v1/leads/:idJWT Lead detail with scoring breakdown POST /api/v1/leadsJWT (admin/member) Create a lead PATCH /api/v1/leads/:idJWT (admin/member) Update a lead DELETE /api/v1/leads/:idJWT (admin) Delete a lead POST /api/v1/leads/:id/convertJWT (admin/member) Convert lead to customer
Method Path Auth Description GET /api/v1/customersJWT List customers (paginated) GET /api/v1/customers/:idJWT Customer detail POST /api/v1/customersJWT (admin/member) Create a customer PATCH /api/v1/customers/:idJWT (admin/member) Update a customer
Method Path Auth Description GET /api/v1/projectsJWT List projects GET /api/v1/projects/:idJWT Project detail POST /api/v1/projectsJWT (admin/member) Create a project PATCH /api/v1/projects/:idJWT (admin/member) Update a project
Method Path Auth Description GET /api/v1/estimatesJWT List estimates (auto-expires stale quotes) GET /api/v1/estimates/:idJWT Estimate detail with line items POST /api/v1/estimatesJWT (admin/member) Create estimate (generates display_id QT-{seq}-{rev}) PATCH /api/v1/estimates/:idJWT (admin/member) Update estimate (content-locked for non-draft) POST /api/v1/estimates/:id/duplicateJWT (admin/member) Create revision (supersedes original) POST /api/v1/estimates/:id/cloneJWT (admin/member) Independent copy with new identity POST /api/v1/estimates/:id/renewJWT (admin/member) Renew expired quote with new expiration POST /api/v1/estimates/:id/shareJWT (admin/member) Generate share token (30-day default) POST /api/v1/estimates/:id/convertJWT (admin/member) Convert to project (creates tasks from line items) POST /api/v1/estimates/:id/archiveJWT (admin/member) Archive estimate POST /api/v1/estimates/:id/unarchiveJWT (admin/member) Unarchive estimate GET /api/v1/estimates/:id/pdfJWT HTML rendering (format=html param for raw HTML) POST /api/v1/estimates/previewJWT Render HTML from builder data (no DB write)
Method Path Auth Description GET /api/v1/estimates/:id/attachmentsJWT List attachments (ordered by sort_order) POST /api/v1/estimates/:id/attachmentsJWT (admin/member) Upload attachment (multipart/form-data, draft only) DELETE /api/v1/estimates/:id/attachments/:aidJWT (admin/member) Delete attachment (removes from R2 + DB) GET /api/v1/estimates/:id/attachments/:aid/downloadJWT Download attachment (streams from R2)
Method Path Description GET /api/v1/public/quote/:tokenPublic quote HTML view (checks token expiry) GET /api/v1/public/quote/:token/pdfPublic quote PDF download GET /api/v1/public/quote/:token/attachments/:aidPublic attachment download
Method Path Auth Description GET /api/v1/catalog/itemsJWT List catalog items POST /api/v1/catalog/itemsJWT (admin) Create catalog item PATCH /api/v1/catalog/items/:idJWT (admin) Update catalog item DELETE /api/v1/catalog/items/:idJWT (admin) Delete catalog item GET /api/v1/catalog/unit-typesJWT List unit types POST /api/v1/catalog/unit-typesJWT (admin) Create unit type PATCH /api/v1/catalog/unit-types/:idJWT (admin) Update unit type DELETE /api/v1/catalog/unit-types/:idJWT (admin) Delete unit type
Method Path Auth Description GET /api/v1/activitiesJWT List activities (filterable by lead/customer) GET /api/v1/activities/recentJWT Recent activity feed POST /api/v1/activitiesJWT (admin/member) Create activity/note
Method Path Auth Description GET /api/v1/dashboard/statsJWT Dashboard aggregations GET /api/v1/dashboard/attentionJWT Needs-attention items
Method Path Auth Description GET /api/v1/tenantJWT Tenant config PATCH /api/v1/tenantJWT (admin) Update tenant config GET /api/v1/tenant/configJWT Tenant config_json settings
Method Path Auth Description POST /api/v1/assets/intake/uploadJWT (admin/member/contractor) Upload an intake or inspection file to R2. Accepts multipart/form-data with fields: file (image, max 10MB), entityId (lead or customer ID), action (e.g. inspection, intake). Returns { url, id } where url is the R2 key. GET /api/v1/assets/intake/download?key=...JWT (admin/member/contractor) Download a file from R2 by its storage key. Returns the file with appropriate Content-Type.
R2 key format: intake-photos/{entityId}/{action}/{YYYY-MM-DD}/{filename}
Defaults to unlinked if no entityId is provided and general if no action is provided.
Method Path Auth Description GET /api/v1/searchJWT Cross-entity search POST /api/v1/geocodeJWT (admin/member) On-demand Nominatim geocoding GET /api/v1/preferencesJWT User preferences PUT /api/v1/preferences/:keyJWT Set preference POST /api/v1/webhooks/intakeSignature Intake form submission webhook GET /api/v1/healthNone Health check POST /api/v1/communications/callJWT (admin/member) Log outbound call POST /api/v1/communications/smsJWT (admin/member) Log outbound SMS
Method Path Auth Description POST /api/v1/inspections/draftJWT (contractor) Save inspection draft GET /api/v1/inspections/draftJWT (contractor) Get inspection draft
Method Path Description POST /api/v1/admin/generate-leadsGenerate fake leads via intake pipeline POST /api/v1/admin/generate-customersGenerate fake customers (leads → convert) POST /api/v1/admin/leads/soft-deleteSoft-delete all leads POST /api/v1/admin/leads/hard-deleteHard-delete all leads POST /api/v1/admin/customers/soft-deleteSoft-delete all customers POST /api/v1/admin/customers/hard-deleteHard-delete all customers GET /api/v1/admin/system-infoDB size, record counts GET /api/v1/admin/registration-statusRegistration toggle state POST /api/v1/admin/create-accountCreate user account GET /api/v1/admin/usersList tenant users POST /api/v1/admin/reset-passwordReset user password POST /api/v1/admin/toggle-force-password-changeToggle force-password-change flag
See the Schemas reference for request/response field details.