# Leads

> List, read, create and update leads, move them between statuses, set their tags and owners, and read their timeline through the Fondaro API.

Leads are the people in your CRM. These routes use the scopes `crm:read` (reading) and `crm:write` (changing). Writes also need an active Fondaro plan; without one they answer `403` with `SUBSCRIPTION_REQUIRED`.

The key acts as the person who made it:

- **A member** reaches only the leads they own. A lead that is not theirs answers `404` with "Lead not found.", the same as a lead that does not exist.
- **An admin** reaches every lead of the agency. Only an admin can assign owners, move many leads at once, or create a lead for someone else.

Send `Authorization: Bearer $FONDARO_API_KEY` on every call. Pages that list rows follow [Errors and limits](https://www.fondaro.com/docs/api/errors-and-limits.md) for paging. Lead ids are integers.

A status change (single or bulk), an assignee change, and a lead's opening status and owner when you create it through the API are recorded in the lead's history with the source value `api`, so the lead's timeline shows it as an API change made by the key's person.

## List leads

`GET /v1/leads`

A page of leads, newest first, with their tags. A member sees only their own leads.

| Parameter | In | Type | Required | Description |
|-----------|----|------|----------|-------------|
| `page` | Query | integer | No | Page number, starting at 1 |
| `limit` | Query | integer | No | 1 to 100. Default 25 |
| `search` | Query | string | No | Up to 200 characters, matched against first name, last name, full name, email and phone number |
| `crmStatus` | Query | string | No | `lead`, `potential`, `bad_timing`, `client` or `unqualified` |
| `assigneeIds` | Query | string or string[] | No | Admins only: leads owned by any of these people (comma-separated or repeated). A member always sees only their own |

```bash
curl "https://api.fondaro.com/v1/leads?limit=3" \
  -H "Authorization: Bearer $FONDARO_API_KEY"
```

```json
{
  "data": [
    {
      "id": 3438,
      "firstName": "David",
      "lastName": "Cohen",
      "email": "david.cohen@example.com",
      "phoneNumber": "+15624528939",
      "language": "en-GB",
      "companyName": null,
      "crmStatus": "lead",
      "assigneeIds": ["user_2abcDEF1234567890ghiJKL"],
      "purchasedAt": "2026-10-01T05:42:00.000Z",
      "totalCalls": 0,
      "lastCallAt": null,
      "pendingTasks": 2,
      "nextTaskDueAt": "2026-10-01T07:30:00.000Z",
      "leadGroup": null,
      "tags": []
    }
  ],
  "hasMore": true,
  "page": 1,
  "limit": 3,
  "total": 29
}
```

Paging is by page number; `total` is exact. Errors: `400` for a `limit` over 100 or an unknown `crmStatus`.

## Count leads per status

`GET /v1/leads/counts`

The number of leads in each status. A member counts only their own leads; an admin counts the whole agency and also gets an `unassigned` bucket.

| Parameter | In | Type | Required | Description |
|-----------|----|------|----------|-------------|
| `assigneeIds` | Query | string or string[] | No | Admins only: count across these people. Ignored for members |

```bash
curl https://api.fondaro.com/v1/leads/counts \
  -H "Authorization: Bearer $FONDARO_API_KEY"
```

```json
{ "lead": 6, "potential": 12, "bad_timing": 1, "client": 9, "unqualified": 1, "unassigned": 0 }
```

## Get a lead

`GET /v1/leads/{leadId}`

One lead: contact details, status, tags, owners, call and task totals, and the chat channels linked to it. The history is on the timeline route.

| Parameter | In | Type | Required | Description |
|-----------|----|------|----------|-------------|
| `leadId` | Path | integer | Yes | The id of the lead |

```bash
curl https://api.fondaro.com/v1/leads/1042 \
  -H "Authorization: Bearer $FONDARO_API_KEY"
```

```json
{
  "id": 1042,
  "firstName": "Anna",
  "lastName": "Berg",
  "email": "anna@example.com",
  "phoneNumber": "+46701234567",
  "language": null,
  "companyName": null,
  "crmStatus": "lead",
  "assigneeIds": ["user_2abcDEF1234567890ghiJKL"],
  "totalCalls": 0,
  "pendingTasks": 0,
  "source": "manual",
  "leadType": "buyer",
  "tags": [],
  "createdAt": "2026-10-04T12:02:03.718Z",
  "channels": []
}
```

Errors: `404` "Lead not found." for a lead that does not exist or is not yours. `400` for an id that is not an integer.

## Get a lead timeline

`GET /v1/leads/{leadId}/timeline`

The lead's activity, newest first: notes, tasks, calls, emails, chat messages, meetings, viewings, documents, status changes, deal events, owner changes and how the lead was created. A very long body carries a `_preview` field that says what was shortened; the full text is on the calls and emails routes.

| Parameter | In | Type | Required | Description |
|-----------|----|------|----------|-------------|
| `leadId` | Path | integer | Yes | The id of the lead |
| `limit` | Query | integer | No | 1 to 100. Default 20 |
| `offset` | Query | integer | No | Entries to skip. Continue with `nextOffset` |

```bash
curl "https://api.fondaro.com/v1/leads/1042/timeline?limit=5" \
  -H "Authorization: Bearer $FONDARO_API_KEY"
```

```json
{
  "data": [
    {
      "type": "assignee-change",
      "date": "2026-10-04T12:02:03.718Z",
      "assigneeChange": {
        "addedUserIds": ["user_2abcDEF1234567890ghiJKL"],
        "removedUserIds": [],
        "changedBy": "user_2abcDEF1234567890ghiJKL",
        "source": "user"
      }
    },
    { "type": "lead-created", "date": "2026-10-04T12:02:03.640Z", "leadCreated": { "source": "manual", "leadGroupName": null } }
  ],
  "hasMore": false,
  "total": 2,
  "totalIsExact": true,
  "tasksById": {},
  "dealsById": {}
}
```

Paging is by offset. Errors: `404` "Lead not found."

## Create a lead

`POST /v1/leads`

Creates a lead owned by the key's person. Only an admin can create an unassigned lead or one owned by someone else. Needs `crm:write`. Accepts an `Idempotency-Key` header.

| Parameter | In | Type | Required | Description |
|-----------|----|------|----------|-------------|
| `firstName` | Body | string | Yes | First name |
| `lastName` | Body | string | Yes | Last name |
| `email` | Body | string | Yes | Email address |
| `phoneNumber` | Body | string | Yes | Phone number |
| `crmStatus` | Body | string | Yes | `lead`, `potential`, `bad_timing`, `client` or `unqualified` |
| `companyName` | Body | string | No | Up to 255 characters |
| `language` | Body | string | No | The lead's language, for example `en-GB` |
| `assigneeIds` | Body | string or string[] | No | Admins only: owners other than the key's person |
| `teamIds` | Body | UUID or UUID[] | No | Admins only: give the lead to every member of these teams |
| `unassigned` | Body | boolean | No | Admins only: create the lead with no owner |

```bash
curl -X POST https://api.fondaro.com/v1/leads \
  -H "Authorization: Bearer $FONDARO_API_KEY" \
  -H "Idempotency-Key: 6f1c2d3e-0a4b-4c5d-8e9f-1a2b3c4d5e6f" \
  -H "Content-Type: application/json" \
  -d '{ "firstName": "Anna", "lastName": "Berg", "email": "anna@example.com", "phoneNumber": "+46701234567", "crmStatus": "lead" }'
```

The `201` response wraps the new lead:

```json
{
  "lead": {
    "id": 1042,
    "firstName": "Anna",
    "lastName": "Berg",
    "email": "anna@example.com",
    "phoneNumber": "+46701234567",
    "crmStatus": "lead",
    "assigneeIds": ["user_2abcDEF1234567890ghiJKL"],
    "source": "manual",
    "leadType": "buyer",
    "tags": [],
    "createdAt": "2026-10-04T12:02:03.718Z"
  }
}
```

Errors: `400` for a missing field; `403` with `FORBIDDEN` ("Only org admins can create unassigned leads or assign them to others") when a member asks for another owner or an unassigned lead.

## Update a lead's contact details

`PATCH /v1/leads/{leadId}`

Changes only the fields you send. A `null` or empty `companyName` clears it. Needs `crm:write`.

| Parameter | In | Type | Required | Description |
|-----------|----|------|----------|-------------|
| `leadId` | Path | integer | Yes | The id of the lead |
| `firstName` | Body | string | No | First name |
| `lastName` | Body | string | No | Last name |
| `email` | Body | string | No | Email address |
| `phoneNumber` | Body | string | No | Phone number |
| `companyName` | Body | string or null | No | Up to 255 characters |

```bash
curl -X PATCH https://api.fondaro.com/v1/leads/1042 \
  -H "Authorization: Bearer $FONDARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "companyName": "Berg Holdings" }'
```

The response is the lead, as in [Get a lead](#get-a-lead), with `"companyName": "Berg Holdings"`. Errors: `404` "Lead not found."

## Move a lead to another status

`PUT /v1/leads/{leadId}/status`

Sets the pipeline status. Needs `crm:write`.

| Parameter | In | Type | Required | Description |
|-----------|----|------|----------|-------------|
| `leadId` | Path | integer | Yes | The id of the lead |
| `crmStatus` | Body | string | Yes | `lead`, `potential`, `bad_timing`, `client` or `unqualified` |

```bash
curl -X PUT https://api.fondaro.com/v1/leads/1042/status \
  -H "Authorization: Bearer $FONDARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "crmStatus": "potential" }'
```

The response is the lead with `"crmStatus": "potential"`. The change is recorded with the source value `api`. Errors: `404` "Lead not found."

## Move many leads to one status

`POST /v1/leads/status`

Admins only. Sets the same status on up to 500 leads in one call. Needs `crm:write`.

| Parameter | In | Type | Required | Description |
|-----------|----|------|----------|-------------|
| `leadIds` | Body | integer[] | Yes | Up to 500 lead ids |
| `crmStatus` | Body | string | Yes | The new status |

```bash
curl -X POST https://api.fondaro.com/v1/leads/status \
  -H "Authorization: Bearer $FONDARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "leadIds": [1042, 1043], "crmStatus": "potential" }'
```

```json
{ "updated": 2 }
```

`updated` is the number of leads updated. Errors: `403` with `ORG_ADMIN_REQUIRED` for a member's key.

## Set the tags on a lead

`PUT /v1/leads/{leadId}/tags`

Replaces the lead's tags with exactly the tag ids you send. An empty list clears them. Get tag ids from [List tags](https://www.fondaro.com/docs/api/v1/people.md#list-tags). Needs `crm:write`.

| Parameter | In | Type | Required | Description |
|-----------|----|------|----------|-------------|
| `leadId` | Path | integer | Yes | The id of the lead |
| `tagIds` | Body | UUID[] | Yes | The full new set of tags |

```bash
curl -X PUT https://api.fondaro.com/v1/leads/1042/tags \
  -H "Authorization: Bearer $FONDARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "tagIds": ["3f6c2a10-0000-4000-8000-000000000006"] }'
```

The response is the lead, with the tag in `tags`:

```json
{ "id": 1042, "tags": [{ "id": "3f6c2a10-0000-4000-8000-000000000006", "name": "BrandNewTag", "color": "slate", "leadCount": 1 }] }
```

## Set the owners of a lead

`PUT /v1/leads/{leadId}/assignees`

Admins only. Replaces the lead's owners with the people, and the members of the teams, you send. An empty list leaves the lead unassigned. Needs `crm:write`.

| Parameter | In | Type | Required | Description |
|-----------|----|------|----------|-------------|
| `leadId` | Path | integer | Yes | The id of the lead |
| `userIds` | Body | string[] | Yes | Person ids from [List members](https://www.fondaro.com/docs/api/v1/people.md#list-members) |
| `teamIds` | Body | UUID or UUID[] | No | Teams from [List teams](https://www.fondaro.com/docs/api/v1/people.md#list-teams) |

```bash
curl -X PUT https://api.fondaro.com/v1/leads/1042/assignees \
  -H "Authorization: Bearer $FONDARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "userIds": ["user_2abcDEF1234567890ghiJKL"] }'
```

The response wraps the lead: `{ "lead": { "id": 1042, "assigneeIds": ["user_2abcDEF1234567890ghiJKL"], … } }`. Errors: `403` with `ORG_ADMIN_REQUIRED` for a member's key.

## Add owners to a lead

`POST /v1/leads/{leadId}/assignees`

Admins only. Adds people, and the members of teams, to the lead's owners and keeps the existing ones. The parameters are the same as for setting owners. Needs `crm:write`.

```bash
curl -X POST https://api.fondaro.com/v1/leads/1042/assignees \
  -H "Authorization: Bearer $FONDARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "userIds": ["user_2mnoPQR1234567890stuVWX"] }'
```

The response wraps the lead, as above. Errors: `403` with `ORG_ADMIN_REQUIRED` for a member's key.

Source: https://www.fondaro.com/docs/api/v1/leads
