API Reference
Clearmargin REST API — authentication, endpoints, query syntax, and error handling.
Programmatic access to your Clearmargin data via the REST API. Create integrations, automate workflows, and connect with third-party tools.
Base URL
All endpoint paths in this reference are relative to the base URL:
https://www.clearmargin.app/apiAuthentication
All API requests require authentication via an API key. Create keys in your dashboard at Settings > API Keys.
Include your API key using either method:
Authorization header (recommended):
Authorization: Bearer sk_live_your_api_key_herex-api-key header (alternative):
x-api-key: sk_live_your_api_key_hereOrganization scoping
API keys are scoped to your organization. All data returned is automatically filtered to your organization. You cannot access data from other organizations.
Rate Limits
API requests are rate-limited to ensure platform stability.
| Limit | Window |
|---|---|
| 100 requests | Per minute, per API key |
Rate limit status is included in every response via headers:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed per window |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp when the window resets |
When rate-limited, the API returns HTTP 429 with a Retry-After header indicating when you can retry.
Resources
Clearmargin exposes a RESTful API following standard CRUD patterns. Each resource supports list, get, create, update, and delete operations.
| Resource | Endpoint | Description |
|---|---|---|
| Clients | /api/clients | Client and company records |
| Projects | /api/projects | Client projects with scope tracking |
| Invoices | /api/invoices | Client invoices and billing |
| Proposals | /api/proposals | Client proposals with line items |
| Time Entries | /api/time-entries | Time logged against projects |
| Transactions | /api/transactions | Unified cost and revenue ledger |
| Catalog Items | /api/catalog-items | Service and product catalog |
| Contacts | /api/contacts | Contact people on clients |
| Milestones | /api/milestones | Project and proposal milestones |
| Calendar Events | /api/calendar-events | Schedule calendar events |
| Webhooks | /api/webhooks | Webhook endpoint configuration |
Each resource supports these operations:
GET /api/{resource}--- List all recordsGET /api/{resource}/:id--- Get a single recordPOST /api/{resource}--- Create a new recordPATCH /api/{resource}/:id--- Update a recordDELETE /api/{resource}/:id--- Delete a record
Query Syntax
List endpoints support filtering, sorting, pagination, and relationship population via query parameters.
Parameters
| Parameter | Type | Description |
|---|---|---|
where | Object | Filter results using Payload query syntax |
sort | String | Field name to sort by. Prefix with - for descending |
limit | Number | Results per page (default: 10, max: 100) |
page | Number | Page number for pagination (starts at 1) |
depth | Number | Relationship population depth (default: 1, max: 3) |
Filtering
The where parameter uses Payload query syntax. Pass conditions as nested query parameters:
# Filter clients by status
GET /api/clients?where[status][equals]=active
# Filter invoices by amount greater than 1000
GET /api/invoices?where[total][greater_than]=1000
# Filter time entries by date range
GET /api/time-entries?where[date][greater_than_equal]=2026-01-01&where[date][less_than]=2026-02-01
# Combine filters with AND (default)
GET /api/projects?where[status][equals]=active&where[client][equals]=client_id_hereOperators
| Operator | Description |
|---|---|
equals | Exact match |
not_equals | Not equal to |
greater_than | Greater than |
greater_than_equal | Greater than or equal |
less_than | Less than |
less_than_equal | Less than or equal |
like | Case-insensitive partial match |
contains | String contains |
in | Value is in array |
exists | Field exists / is not null |
Sorting
Sort results by any field. Prefix the field name with - for descending order:
# Newest first
GET /api/clients?sort=-createdAt
# Oldest due dates first
GET /api/invoices?sort=dueDatePagination
# Page 2, 25 results per page
GET /api/clients?page=2&limit=25List endpoints return paginated results in this format:
{
"docs": [...],
"totalDocs": 42,
"limit": 10,
"totalPages": 5,
"page": 1,
"pagingCounter": 1,
"hasPrevPage": false,
"hasNextPage": true,
"prevPage": null,
"nextPage": 2
}Depth
Control how deeply related documents are populated:
# Populate one level of relationships (default)
GET /api/invoices?depth=1
# Populate nested relationships (e.g., invoice > client > contacts)
GET /api/invoices?depth=2Examples
List clients
curl -H "Authorization: Bearer sk_live_your_key" \
"https://www.clearmargin.app/api/clients?limit=10&sort=-createdAt"Create a client
curl -X POST \
-H "Authorization: Bearer sk_live_your_key" \
-H "Content-Type: application/json" \
-d '{"name": "Acme Corp", "email": "billing@acme.com"}' \
"https://www.clearmargin.app/api/clients"Get unpaid invoices
curl -H "Authorization: Bearer sk_live_your_key" \
"https://www.clearmargin.app/api/invoices?where[status][not_equals]=paid&sort=dueDate"Log a time entry
curl -X POST \
-H "Authorization: Bearer sk_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"project": "project_id_here",
"hours": 2.5,
"date": "2026-03-14",
"description": "API integration work",
"billable": true
}' \
"https://www.clearmargin.app/api/time-entries"Error Handling
The API uses standard HTTP status codes to indicate success or failure.
| Status | Description |
|---|---|
200 | Success |
201 | Created (for POST requests) |
400 | Bad request (invalid parameters or body) |
401 | Unauthorized (missing or invalid API key) |
403 | Forbidden (key lacks required permissions) |
404 | Resource not found |
429 | Rate limited (too many requests) |
500 | Internal server error |
Error responses include a JSON body describing what went wrong:
{
"errors": [
{
"message": "You are not allowed to perform this action.",
"data": {
"collection": "invoices"
}
}
]
}