Error responses
When a request fails, the server returns an appropriate HTTP status code with a JSON error body.
Common status codes
| Status | Meaning |
|---|
400 | Bad request — malformed JSON, missing required fields, or invalid query parameters. |
401 | Unauthorized — no valid session, token, or API key provided. |
403 | Forbidden — the authenticated user lacks the required RBAC permission for this action. |
404 | Not found — the resource type (:resource slug) does not exist, or the specific record ID was not found. |
422 | Validation error — the request body failed server-side validation rules. |
500 | Internal server error — an unexpected error occurred. |
Error shape
Most error responses follow this format:
{
"error": "Unauthorized"
}
Validation errors may include additional detail:
{
"error": "Validation failed",
"details": [
{ "field": "email", "message": "must be a valid email address" }
]
}
Handling errors
- Check the HTTP status code first for routing (retry logic, user feedback, etc.).
- Read the
error field for a human-readable description.
- For
403 responses, verify the user’s RBAC role includes the required permission (e.g. records.write for create/update/delete operations).
- Do not retry
401, 403, or 404 errors — these indicate a configuration or permissions issue, not a transient failure.
Public endpoints (no auth required)
These endpoints are accessible without authentication:
| Method | Path | Description |
|---|
GET | / | Service name and basic info. Returns pointers to docs and health endpoints. |
GET | /health | Basic health check. |
GET | /health/ready | Readiness check (confirms the server and its dependencies are ready to accept requests). |
curl https://your-app.up.railway.app/health
CORS and browser clients
If a web application on a different origin calls the CRM API (e.g. a frontend at https://app.yourcompany.com calling https://crm.yourcompany.com), the browser enforces CORS restrictions.
Configuring allowed origins
Set the ALLOWED_ORIGINS environment variable on your BasicsOS server to a comma-separated list of origins:
ALLOWED_ORIGINS=https://app.yourcompany.com,https://admin.yourcompany.com
The server will include the appropriate Access-Control-Allow-Origin headers for these origins.
When CORS is not needed
- Same-origin requests — if your frontend and API share the same origin, CORS does not apply.
- Server-to-server requests — requests made from a backend service using a Personal CRM API token (
Bearer bos_crm_...) are not subject to CORS.
If you are building a server-to-server integration and do not need browser access, you can skip CORS configuration entirely.