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 |
Claude connector (MCP)
Servelo exposes a remote MCP server so it can be added as a custom connector in Claude, letting you ask Claude to read and act on your live Servelo data directly from chat.
- In claude.ai, go to Settings > Connectors > Add custom connector
- Enter
https://serveloapp.com/mcpas the connector URL - Claude redirects you to Servelo's login (or your existing session) to authorize access, using the same OAuth-style consent screen any third-party app would show
- Approve the connection. Claude can now call the tools listed below on your behalf
Every tool call is authenticated as you and enforces the same roles and validation as the equivalent page in the app; nothing is reimplemented or given broader access. Excluded from the tool surface entirely: org/user/billing/plan management, SSO/MFA settings, deletion, and password changes.
| Area | Tools |
|---|---|
| Tickets | list, get, create, update, add comment |
| Customers | list, get, create, update |
| Quotes | list, get, create |
| Invoices | list, get, create |
| Technicians | list |
| Assets | list, get |
| Revenue & Expenses | list |
| Other | search, dashboard summary |
Manage or revoke access any time from My Account > Connected Apps. Revoking immediately invalidates that connection's access.
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. |