API Reference
The Servelo REST API lets you integrate ticket and client data with external tools. All API requests are scoped to a tenant and require authentication.
Authentication
The API uses short-lived JWT access tokens (15-minute TTL) and long-lived refresh tokens (30-day TTL). Obtain tokens by signing in with a password or via magic link verification.
POST /api/auth/login
Content-Type: application/json
{ "email": "admin@yourdomain.com", "password": "your-password" }
Include the access token in all subsequent requests:
Authorization: Bearer <accessToken>
When the access token expires, refresh it:
POST /api/auth/refresh
{ "refreshToken": "<refreshToken>" }
โ { "accessToken": "..." }
Tenant resolution
The API resolves the tenant from the request hostname. Use your tenant subdomain as the base URL:
https://your-company.serveloapp.com/api/...
Auth
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /api/auth/login | None | Sign in with email and password. Returns access + refresh tokens. |
| POST | /api/auth/magic-link/request | None | Request a magic link for an email address. |
| GET | /api/auth/magic-link/verify | None | Verify a magic link token. Returns access + refresh tokens. |
| POST | /api/auth/refresh | None | Exchange a refresh token for a new access token. |
| POST | /api/auth/logout | None | Revoke a refresh token. |
| GET | /api/auth/me | Required | Get the current user's profile. Includes has_password boolean. |
Users
All user endpoints require a valid access token. Role requirements are noted per route.
| Method | Endpoint | Role | Description |
|---|---|---|---|
| GET | /api/users | Admin | List all users in the org with role, status, and auth provider. |
| POST | /api/users/invite | Admin | Invite a new user. Sends a 7-day magic link invite email. |
| GET | /api/users/technicians | Any | List active users available for ticket assignment. |
| GET | /api/users/preferences | Any | Get the current user's preferences. |
| PUT | /api/users/preferences | Any | Merge-update the current user's preferences. |
| POST | /api/users/me/avatar | Any | Upload a profile photo for the current user. |
| POST | /api/users/me/set-password | Any | Set a password on the current user's account (no existing password required). Body: { password }. |
| POST | /api/users/me/change-password | Any | Change the current user's password. Body: { currentPassword, newPassword }. |
| PUT | /api/users/:id | Admin | Update a user's name, role, phone, notes, or avatar URL. |
| POST | /api/users/:id/set-password | Admin | Force-set a password for any user in the org. Body: { password }. Minimum 8 characters. |
| POST | /api/users/:id/send-login-link | Admin | Send a 24-hour magic link to a user. |
| PUT | /api/users/:id/deactivate | Admin | Deactivate a user. They cannot log in until reactivated. |
| PUT | /api/users/:id/reactivate | Admin | Reactivate a previously deactivated user. |
| DELETE | /api/users/:id | Admin | Permanently delete a user. |
Tickets
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/tickets | List all tickets |
| GET | /api/tickets/:id | Get a single ticket |
| POST | /api/tickets | Create a ticket |
| PUT | /api/tickets/:id | Update a ticket |
| DELETE | /api/tickets/:id | Move a ticket to Trash (admin only) |
| GET | /api/tickets/:id/comments | List comments on a ticket |
| POST | /api/tickets/:id/comments | Add a comment |
| POST | /api/tickets/:id/photos | Upload a photo to a ticket |
| DELETE | /api/tickets/:id/photos/:photoId | Delete a ticket photo |
Clients
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/customers | List all clients |
| GET | /api/customers/:id | Get a single client |
| POST | /api/customers | Create a client |
| PUT | /api/customers/:id | Update a client |
| DELETE | /api/customers/:id | Delete a client (admin only) |
Quotes
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/quotes | List all quotes |
| GET | /api/quotes/:id | Get a single quote |
| POST | /api/quotes | Create a quote |
| PUT | /api/quotes/:id | Update a quote |
| POST | /api/quotes/:id/send | Email the quote to the client |
| DELETE | /api/quotes/:id | Delete a quote (admin only) |
Revenue & Expenses
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/revenue | List revenue entries |
| POST | /api/revenue | Create a revenue entry |
| PUT | /api/revenue/:id | Update a revenue entry |
| DELETE | /api/revenue/:id | Delete a revenue entry (admin only) |
| GET | /api/expenses | List expense entries |
| POST | /api/expenses | Create an expense entry |
| PUT | /api/expenses/:id | Update an expense entry |
| DELETE | /api/expenses/:id | Delete an expense entry (admin only) |
Settings
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/settings | Get all settings for the org |
| PUT | /api/settings | Update one or more settings (admin only) |
System Admin
These endpoints require the caller to be an admin in the SYSTEM_ADMIN_ORG organization.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/admin/orgs | List all organizations with user counts and plan info |
| PUT | /api/admin/orgs/:slug | Update an org (plan, name, active status) |
| DELETE | /api/admin/orgs/:slug | Permanently delete an org and all its data |
| GET | /api/admin/orgs/:slug/users | List all users in an org |
| PUT | /api/admin/orgs/:slug/users/:id | Update a user's role or active status in any org |
| POST | /api/admin/orgs/:slug/users/:id/set-password | Force-set a password for a user in any org. Body: { password }. |
| DELETE | /api/admin/orgs/:slug/users/:id | Permanently delete a user from any org |
Error format
All error responses use the same shape:
{ "error": "Human-readable error message" }
Common status codes:
| Code | Meaning |
|---|---|
400 | Bad request. Missing or invalid input. |
401 | Unauthenticated. Token missing, invalid, or expired. |
403 | Forbidden. Authenticated but not allowed (wrong role, suspended org). |
404 | Resource not found. |
409 | Conflict. Typically a duplicate (e.g. email already exists). |
429 | Rate limited. Slow down and retry. |
500 | Server error. |