# LeoCRM API Overview

> Summary of all API endpoints, grouped by domain.

## Base URL

```
http://localhost:8000/api/v1
```

## Authentication

All endpoints (except `/health` and `/auth/login`) require a valid session cookie obtained via login.

| Endpoint | Method | Auth | Description |
|---|---|---|---|
| `/api/v1/auth/login` | POST | No | Login with email + password, returns session cookie |
| `/api/v1/auth/register` | POST | No | Register first user (bootstrap) |
| `/api/v1/auth/logout` | POST | Yes | Logout and destroy session |
| `/api/v1/auth/me` | GET | Yes | Get current user profile |
| `/api/v1/auth/refresh` | POST | Yes | Refresh session token |

## Health & Monitoring

| Endpoint | Method | Auth | Description |
|---|---|---|---|
| `/api/v1/health` | GET | No | Health check (DB, Redis, storage, worker) |
| `/api/v1/metrics` | GET | Admin | Prometheus metrics (text/plain) |

## Contacts

| Endpoint | Method | Auth | Description |
|---|---|---|---|
| `/api/v1/contacts` | GET | Yes | List contacts (pagination, search, sort) — page_size max 100 |
| `/api/v1/contacts` | POST | Yes | Create a contact (with optional company links) |
| `/api/v1/contacts/export` | GET | Yes | Stream contacts as CSV (StreamingResponse) |
| `/api/v1/contacts/{id}` | GET | Yes | Get a single contact with companies |
| `/api/v1/contacts/{id}` | PUT | Yes | Update a contact |
| `/api/v1/contacts/{id}` | DELETE | Yes | Delete a contact (soft or GDPR hard-delete) |

### Query Parameters (List)

| Parameter | Type | Default | Constraints |
|---|---|---|---|
| `page` | int | 1 | ≥1 |
| `page_size` | int | 20 | ≥1, ≤100 (max 100 enforced) |
| `search` | string | _(none)_ | Searches first_name, last_name, email |
| `sort_by` | string | last_name | Column name |
| `sort_order` | string | asc | `asc` or `desc` |

## Companies

| Endpoint | Method | Auth | Description |
|---|---|---|---|
| `/api/v1/companies` | GET | Yes | List companies (pagination, FTS, industry filter) — page_size max 100 |
| `/api/v1/companies` | POST | Yes | Create a company |
| `/api/v1/companies/export` | GET | Yes | Stream companies as CSV or XLSX |
| `/api/v1/companies/{id}` | GET | Yes | Get a single company with contacts |
| `/api/v1/companies/{id}` | PUT | Yes | Update a company |
| `/api/v1/companies/{id}` | DELETE | Yes | Soft-delete a company |
| `/api/v1/companies/{id}/contacts/{cid}` | POST | Yes | Link a contact to a company (N:M) |
| `/api/v1/companies/{id}/contacts/{cid}` | DELETE | Yes | Unlink a contact from a company |
| `/api/v1/companies/{id}/emails` | GET | Yes | Get emails for a company |

## Users & Roles

| Endpoint | Method | Auth | Description |
|---|---|---|---|
| `/api/v1/users` | GET | Admin | List users |
| `/api/v1/users` | POST | Admin | Create/invite a user |
| `/api/v1/users/{id}` | GET | Yes | Get user details |
| `/api/v1/users/{id}` | PATCH | Admin | Update user (activate/deactivate, role) |
| `/api/v1/users/{id}` | DELETE | Admin | Delete a user |
| `/api/v1/roles` | GET | Admin | List roles |
| `/api/v1/roles` | POST | Admin | Create a custom role |
| `/api/v1/roles/{id}` | PUT | Admin | Update a role |
| `/api/v1/roles/{id}` | DELETE | Admin | Delete a custom role |

## Tenants

| Endpoint | Method | Auth | Description |
|---|---|---|---|
| `/api/v1/tenants` | GET | Yes | List tenants for current user |
| `/api/v1/tenants/current` | GET | Yes | Get current tenant |
| `/api/v1/tenants/switch` | POST | Yes | Switch active tenant |

## Notifications

| Endpoint | Method | Auth | Description |
|---|---|---|---|
| `/api/v1/notifications` | GET | Yes | List notifications |
| `/api/v1/notifications/{id}/read` | POST | Yes | Mark notification as read |
| `/api/v1/notifications/read-all` | POST | Yes | Mark all as read |

## Import/Export

| Endpoint | Method | Auth | Description |
|---|---|---|---|
| `/api/v1/import/contacts` | POST | Yes | Import contacts from CSV/JSON |
| `/api/v1/import/companies` | POST | Yes | Import companies from CSV/JSON |

## Plugins

| Endpoint | Method | Auth | Description |
|---|---|---|---|
| `/api/v1/plugins` | GET | Admin | List available plugins |
| `/api/v1/plugins/{name}/install` | POST | Admin | Install a plugin |
| `/api/v1/plugins/{name}/activate` | POST | Admin | Activate a plugin |
| `/api/v1/plugins/{name}/deactivate` | POST | Admin | Deactivate a plugin |
| `/api/v1/plugins/{name}/uninstall` | POST | Admin | Uninstall a plugin |

## AI Copilot

| Endpoint | Method | Auth | Description |
|---|---|---|---|
| `/api/v1/ai/chat` | POST | Yes | Send a message to the AI copilot |
| `/api/v1/ai/conversations` | GET | Yes | List AI conversations |
| `/api/v1/ai/conversations/{id}` | GET | Yes | Get conversation with messages |

## Workflows

| Endpoint | Method | Auth | Description |
|---|---|---|---|
| `/api/v1/workflows` | GET | Yes | List workflows |
| `/api/v1/workflows` | POST | Admin | Create a workflow |
| `/api/v1/workflows/{id}` | GET | Yes | Get workflow details |
| `/api/v1/workflows/{id}/start` | POST | Yes | Start a workflow instance |

## Pagination

All list endpoints use cursor-based pagination with the following response format:

```json
{
  "items": [...],
  "total": 1234,
  "page": 1,
  "page_size": 20
}
```

- `page_size` is capped at **100** (values >100 return HTTP 422).
- `page` starts at 1.

## CSV Export

Contacts and companies support streaming CSV export:

```
GET /api/v1/contacts/export?format=csv
GET /api/v1/companies/export?format=csv
```

- Uses `StreamingResponse` — does not buffer the entire file in memory.
- Streams rows in batches of 500 for memory efficiency.
- Supports `search` filter for filtered exports.

## Swagger UI

Interactive API documentation is available at:

- **Swagger UI**: `http://localhost:8000/docs`
- **ReDoc**: `http://localhost:8000/redoc`

## Error Format

All errors return a consistent JSON structure:

```json
{
  "detail": {
    "detail": "Human-readable error message",
    "code": "error_code"
  }
}
```

Common status codes:
- `200` — Success
- `201` — Created
- `204` — No content (delete success)
- `400` — Bad request (invalid input)
- `401` — Not authenticated
- `403` — Forbidden (insufficient permissions)
- `404` — Not found
- `422` — Validation error (e.g., page_size > 100)
- `500` — Internal server error
