# Leads API

> REST endpoints for leads — request and response reference with examples.

<!-- Source: https://docs.actuallycare.com/api/reference/leads -->

Lead capture and qualification, including converting a lead into a client.

Base URL: `https://api.actuallycare.com/v1` · Errors use the [standard envelope](/api/reference#error-responses) — see [Errors](/api/errors).

## List all leads

```http
GET /v1/leads
```

Returns paginated list of prospective client leads. Default page size 25 (max 100).

### Parameters

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `status` | query | enum | No | One of: `new`, `contacted`, `qualified`, `unqualified`, `converted`, `lost` |
| `interest_level` | query | enum | No | One of: `hot`, `warm`, `cold` |
| `page` | query | integer | No | Page number for pagination · Default: `1` · Min: 1 |
| `limit` | query | integer | No | Number of items per page (default 25; GET /escrows overrides this to 20 at the controller level) · Default: `25` · Max: 100 · Min: 1 |

### Example request

```bash title="cURL"
curl "https://api.actuallycare.com/v1/leads" \
  -H "X-API-Key: YOUR_API_KEY"
```

```javascript title="JavaScript"
const res = await fetch("https://api.actuallycare.com/v1/leads", {
  headers: {
    "X-API-Key": "YOUR_API_KEY",
  },
});
const data = await res.json();
```

```python title="Python"
import requests

resp = requests.get(
    "https://api.actuallycare.com/v1/leads",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = resp.json()
```

### Example response (200)

```json
{
  "success": true,
  "data": {
    "leads": [
      {
        "id": "f2b8d4a6-3c5e-4f7a-9b1d-8e0c6a4f2d9b",
        "name": "Rachel Kim",
        "email": "rachel.kim@outlook.com",
        "phone": "(661) 555-0198",
        "source": "Website Form",
        "status": "new",
        "lead_type": "buyer",
        "interest_level": "warm",
        "budget": 380000,
        "timeline": "3-6 months"
      }
    ],
    "meta": {
      "page": 1,
      "limit": 25,
      "total": 34,
      "totalPages": 2,
      "hasMore": true
    }
  },
  "timestamp": "2026-07-01T22:52:30.664Z"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Paginated list — records under data.leads, pagination under data.meta (the envelope also carries data.stats and data.cursors) |
| `401` | Authentication required |
| `429` | Rate limit exceeded — too many requests in the current window. Wait for the window to reset (see Retry-After) before retrying. |
| `500` | Internal server error |

## Create new lead

```http
POST /v1/leads
```

### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | Yes | Lead's full name |
| `email` | string | No | Lead's email address |
| `phone` | string | No | Lead's phone number |
| `source` | string | No | How the lead was acquired (e.g. Website Form, Zillow) |
| `lead_type` | enum | No | Whether the lead is a buyer, seller, or both · One of: `buyer`, `seller`, `both` |

### Example request

```bash title="cURL"
curl -X POST "https://api.actuallycare.com/v1/leads" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Jordan Lee"
  }'
```

```javascript title="JavaScript"
const res = await fetch("https://api.actuallycare.com/v1/leads", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "name": "Jordan Lee"
  }),
});
const data = await res.json();
```

```python title="Python"
import requests

resp = requests.post(
    "https://api.actuallycare.com/v1/leads",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "name": "Jordan Lee"
    },
)
data = resp.json()
```

### Example response (201)

```json
{
  "success": true,
  "data": {
    "id": "f2b8d4a6-3c5e-4f7a-9b1d-8e0c6a4f2d9b",
    "name": "Rachel Kim",
    "email": "rachel.kim@outlook.com",
    "phone": "(661) 555-0198",
    "source": "Website Form",
    "status": "new",
    "lead_type": "buyer",
    "interest_level": "warm",
    "version": 1,
    "created_at": "2026-07-01T22:53:05.882Z"
  },
  "message": "Lead created successfully",
  "timestamp": "2026-07-01T22:53:05.890Z"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | Lead created |
| `400` | Invalid request data |
| `401` | Authentication required |
| `429` | Rate limit exceeded — too many requests in the current window. Wait for the window to reset (see Retry-After) before retrying. |
| `500` | Internal server error |

## Get lead by ID

```http
GET /v1/leads/{id}
```

### Parameters

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | Yes | Unique identifier (UUID) · Format: uuid |

### Example request

```bash title="cURL"
curl "https://api.actuallycare.com/v1/leads/:id" \
  -H "X-API-Key: YOUR_API_KEY"
```

```javascript title="JavaScript"
const res = await fetch("https://api.actuallycare.com/v1/leads/:id", {
  headers: {
    "X-API-Key": "YOUR_API_KEY",
  },
});
const data = await res.json();
```

```python title="Python"
import requests

resp = requests.get(
    "https://api.actuallycare.com/v1/leads/:id",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = resp.json()
```

### Example response (200)

```json
{
  "success": true,
  "data": {
    "id": "f2b8d4a6-3c5e-4f7a-9b1d-8e0c6a4f2d9b",
    "name": "Rachel Kim",
    "email": "rachel.kim@outlook.com",
    "phone": "(661) 555-0198",
    "source": "Website Form",
    "status": "contacted",
    "lead_type": "buyer",
    "interest_level": "warm",
    "budget": 380000,
    "timeline": "3-6 months",
    "version": 2
  },
  "timestamp": "2026-07-01T22:53:41.126Z"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Lead found |
| `401` | Authentication required |
| `404` | Resource not found |
| `429` | Rate limit exceeded — too many requests in the current window. Wait for the window to reset (see Retry-After) before retrying. |
| `500` | Internal server error |

## Update lead

```http
PUT /v1/leads/{id}
```

### Parameters

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | Yes | Unique identifier (UUID) · Format: uuid |

### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `status` | string | No | Lead status (new, contacted, qualified, unqualified, converted, lost) |
| `interest_level` | string | No | Lead's level of interest (hot, warm, cold) |
| `version` | integer | No | Current record version for optimistic locking |

### Example request

```bash title="cURL"
curl -X PUT "https://api.actuallycare.com/v1/leads/:id" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "your-status",
    "interest_level": "your-interest-level",
    "version": 3
  }'
```

```javascript title="JavaScript"
const res = await fetch("https://api.actuallycare.com/v1/leads/:id", {
  method: "PUT",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "status": "your-status",
    "interest_level": "your-interest-level",
    "version": 3
  }),
});
const data = await res.json();
```

```python title="Python"
import requests

resp = requests.put(
    "https://api.actuallycare.com/v1/leads/:id",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "status": "your-status",
        "interest_level": "your-interest-level",
        "version": 3
    },
)
data = resp.json()
```

### Example response (200)

```json
{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "user_id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Jane Smith",
    "email": "jane.smith@example.com",
    "phone": "(555) 987-6543",
    "source": "Website Form",
    "status": "new",
    "lead_type": "buyer",
    "interest_level": "warm",
    "budget": 450000,
    "timeline": "3-6 months",
    "message": "example message",
    "notes": "example notes",
    "last_contact_date": "2026-07-15T14:32:10.000Z",
    "next_follow_up": "2026-07-15T14:32:10.000Z",
    "converted_to_client_id": "550e8400-e29b-41d4-a716-446655440000",
    "version": 1,
    "created_at": "2026-07-15T14:32:10.000Z",
    "updated_at": "2026-07-15T14:32:10.000Z"
  },
  "timestamp": "2026-07-15T14:32:10.000Z"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Lead updated |
| `400` | Invalid request data |
| `401` | Authentication required |
| `404` | Resource not found |
| `429` | Rate limit exceeded — too many requests in the current window. Wait for the window to reset (see Retry-After) before retrying. |
| `500` | Internal server error |

## Delete lead

```http
DELETE /v1/leads/{id}
```

### Parameters

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | Yes | Unique identifier (UUID) · Format: uuid |

### Example request

```bash title="cURL"
curl -X DELETE "https://api.actuallycare.com/v1/leads/:id" \
  -H "X-API-Key: YOUR_API_KEY"
```

```javascript title="JavaScript"
const res = await fetch("https://api.actuallycare.com/v1/leads/:id", {
  method: "DELETE",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
  },
});
const data = await res.json();
```

```python title="Python"
import requests

resp = requests.delete(
    "https://api.actuallycare.com/v1/leads/:id",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = resp.json()
```

### Example response (200)

```json
{
  "success": true,
  "data": {},
  "timestamp": "2026-07-15T14:32:10.000Z"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Lead deleted |
| `401` | Authentication required |
| `404` | Resource not found |
| `429` | Rate limit exceeded — too many requests in the current window. Wait for the window to reset (see Retry-After) before retrying. |
| `500` | Internal server error |

## Convert lead to client

```http
POST /v1/leads/{id}/convert
```

Converts a qualified lead into a full client record (transactional). Creates or reuses a contact, creates the client, and marks the lead converted.

### Parameters

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | Yes | Unique identifier (UUID) · Format: uuid |

### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `clientType` | enum | No | Client type for the new client record · One of: `buyer`, `seller`, `both` · Default: `"buyer"` |

### Example request

```bash title="cURL"
curl -X POST "https://api.actuallycare.com/v1/leads/:id/convert" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "clientType": "buyer"
  }'
```

```javascript title="JavaScript"
const res = await fetch("https://api.actuallycare.com/v1/leads/:id/convert", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "clientType": "buyer"
  }),
});
const data = await res.json();
```

```python title="Python"
import requests

resp = requests.post(
    "https://api.actuallycare.com/v1/leads/:id/convert",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "clientType": "buyer"
    },
)
data = resp.json()
```

### Example response (200)

```json
{
  "success": true,
  "data": {
    "client": {
      "id": "c9d2e4f6-1a3b-4c5d-8e7f-0b2d4f6a8c1e",
      "contact_id": "7e5a3c1b-9d8f-4e2a-b6c4-1f0e8d7a5b3c",
      "client_type": "buyer",
      "status": "active",
      "price_range_min": 342000,
      "price_range_max": 418000
    },
    "lead": {
      "id": "f2b8d4a6-3c5e-4f7a-9b1d-8e0c6a4f2d9b",
      "lead_status": "converted",
      "client_id": "c9d2e4f6-1a3b-4c5d-8e7f-0b2d4f6a8c1e"
    },
    "primaryContactId": "7e5a3c1b-9d8f-4e2a-b6c4-1f0e8d7a5b3c",
    "additionalContactsCount": 0
  },
  "message": "Lead successfully converted to client",
  "timestamp": "2026-07-01T22:54:29.773Z"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Lead converted successfully |
| `401` | Authentication required |
| `404` | Resource not found |
| `429` | Rate limit exceeded — too many requests in the current window. Wait for the window to reset (see Retry-After) before retrying. |
| `500` | Internal server error |
