> ## Documentation Index
> Fetch the complete documentation index at: https://basicsos.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# CRM REST API

> Full CRUD reference for contacts, companies, deals, tasks, notes, tags, and custom objects.

The CRM REST API is a generic resource router mounted at `/api`. Every CRM record type shares the same endpoint shape, so once you learn the pattern you can work with any resource.

All endpoints require authentication (see [Authentication](https://basicsos.com/docs/self-hosted-crm/authentication.md)).

## Built-in resources

Use any of these as the `:resource` segment in the endpoints below:

| Resource slug | Description |
| - | - |
| `contacts` | People in your CRM |
| `companies` | Organizations |
| `deals` | Sales opportunities / pipeline records |
| `tasks` | Action items linked to records |
| `contact_notes` | Notes attached to contacts |
| `deal_notes` | Notes attached to deals |
| `company_notes` | Notes attached to companies |
| `tags` | Labels for organizing records |
| `configuration` | CRM configuration entries |
| `automation_rules` | Automation rule definitions |
| `crm_users` | CRM user records |
| `companies_summary` | Aggregated company data (read-only) |
| `contacts_summary` | Aggregated contact data (read-only) |

## Custom CRM objects

If your organization defines custom objects in the database, the `:resource` segment can also be the custom object's slug. These resolve dynamically per organization and support the same CRUD endpoints as built-in resources.

***

## Endpoints

### List records

```
GET /api/:resource
```

Returns a JSON array of records. See [Query parameters](#query-parameters) for filtering, sorting, and pagination.

```bash theme={null}
curl "https://your-app.up.railway.app/api/contacts?range=[0,24]" \
  -H "Authorization: Bearer bos_crm_your_token_here"
```

**Response:** JSON array of record objects.

The response includes a `Content-Range` header for pagination:

```
Content-Range: contacts 0-24/142
```

Format: `<resource> <start>-<end>/<total>`

### Get one record

```
GET /api/:resource/:id
```

```bash theme={null}
curl https://your-app.up.railway.app/api/contacts/c_abc123 \
  -H "Authorization: Bearer bos_crm_your_token_here"
```

### Create a record

```
POST /api/:resource
```

```bash theme={null}
curl -X POST https://your-app.up.railway.app/api/contacts \
  -H "Authorization: Bearer bos_crm_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "first_name": "Ada",
    "last_name": "Lovelace",
    "email": "ada@example.com",
    "company_id": "comp_xyz789"
  }'
```

### Update a record

```
PUT /api/:resource/:id
```

```bash theme={null}
curl -X PUT https://your-app.up.railway.app/api/contacts/c_abc123 \
  -H "Authorization: Bearer bos_crm_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "ada.new@example.com"
  }'
```

### Delete a record

```
DELETE /api/:resource/:id
```

Deletes or archives the record depending on the resource type's rules.

```bash theme={null}
curl -X DELETE https://your-app.up.railway.app/api/deals/d_deal456 \
  -H "Authorization: Bearer bos_crm_your_token_here"
```

### Restore a record

```
POST /api/:resource/:id/restore
```

Restores a previously deleted/archived record. Supported where the backend allows (e.g. deals).

```bash theme={null}
curl -X POST https://your-app.up.railway.app/api/deals/d_deal456/restore \
  -H "Authorization: Bearer bos_crm_your_token_here"
```

### Merge contacts

```
POST /api/merge_contacts
```

A special action to merge two or more contact records. This is not part of the generic `:resource` pattern.

```bash theme={null}
curl -X POST https://your-app.up.railway.app/api/merge_contacts \
  -H "Authorization: Bearer bos_crm_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "source_ids": ["c_abc123", "c_def456"],
    "target_id": "c_abc123"
  }'
```

### Endpoint summary

| Method | Path | Description |
| - | - | - |
| `GET` | `/api/:resource` | List records (paginated). |
| `GET` | `/api/:resource/:id` | Get one record. |
| `POST` | `/api/:resource` | Create a record. |
| `PUT` | `/api/:resource/:id` | Update a record. |
| `DELETE` | `/api/:resource/:id` | Delete or archive a record. |
| `POST` | `/api/:resource/:id/restore` | Restore an archived record. |
| `POST` | `/api/merge_contacts` | Merge contacts (special action). |

***

## Query parameters

Use these on `GET /api/:resource` to control pagination, filtering, and sorting.

### `range`

JSON array specifying the inclusive start and end indices for pagination.

```bash theme={null}
# Fetch records 0 through 24 (first 25 records)
GET /api/contacts?range=[0,24]
```

If omitted, the server defaults to `[0, 24]`.

### `filter`

JSON object for legacy filter support. Keys are field names, values are the match criteria.

```bash theme={null}
# Filter contacts where status is "active"
GET /api/contacts?filter={"status":"active"}
```

### `filters`

JSON array of filter objects for advanced filtering. Each object specifies a field, operator, value, and optional logical operator.

```bash theme={null}
GET /api/contacts?filters=[{"field":"status","op":"eq","value":"active","logicalOp":"and"},{"field":"city","op":"eq","value":"London"}]
```

| Property | Type | Description |
| - | - | - |
| `field` | string | The field name to filter on. |
| `op` | string | Operator (e.g. `eq`, `neq`, `gt`, `lt`, `gte`, `lte`, `contains`, `starts_with`). |
| `value` | any | The value to compare against. |
| `logicalOp` | string | `"and"` or `"or"`. Combines with the next filter. Optional. |

### `sort` and `order`

Single-field sort.

```bash theme={null}
# Sort by created_at descending
GET /api/contacts?sort=created_at&order=DESC
```

| Parameter | Values |
| - | - |
| `sort` | Any field name |
| `order` | `ASC` or `DESC` |

### `sorts`

JSON array of sort objects for multi-field sorting.

```bash theme={null}
GET /api/contacts?sorts=[{"field":"last_name","order":"ASC"},{"field":"created_at","order":"DESC"}]
```

### Full example

```bash theme={null}
curl -G "https://your-app.up.railway.app/api/contacts" \
  --data-urlencode 'range=[0,49]' \
  --data-urlencode 'filters=[{"field":"status","op":"eq","value":"active"}]' \
  --data-urlencode 'sorts=[{"field":"last_name","order":"ASC"}]' \
  -H "Authorization: Bearer bos_crm_your_token_here"
```

***

## Pagination with Content-Range

List responses include a `Content-Range` header:

```
Content-Range: contacts 0-24/142
```

| Segment | Meaning |
| - | - |
| `contacts` | The resource name. |
| `0-24` | Start and end indices of the returned window. |
| `142` | Total number of records matching the query. |

Use this to build pagination controls on the client side. Increment the `range` parameter to fetch the next page:

```bash theme={null}
# Page 1
GET /api/contacts?range=[0,24]
# Page 2
GET /api/contacts?range=[25,49]
# Page 3
GET /api/contacts?range=[50,74]
```

***

## Request body format

* Send JSON with `Content-Type: application/json`.
* The API accepts **snake\_case** field names (e.g. `first_name`, `company_id`). The server maps these to internal camelCase for built-in tables automatically.
* Writable fields per resource are enforced server-side via a whitelist. Fields not in the whitelist are silently ignored.

> [!TIP]
>
> To discover the exact fields available for a resource, use the schema introspection endpoint: `GET /api/schema/:tableName`. See [Related APIs](https://basicsos.com/docs/self-hosted-crm/related-apis.md) for details.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.