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

# REST API endpoints for creating and managing prospects

> Create, list, update, delete, export, and import prospect records. Filter by bounding box, status, tags, assigned rep, date range, or free-text search.

Prospects are the core resource in LeadScout — they represent individual homes or businesses your team is canvassing. The prospects API gives you full CRUD access plus bulk CSV export and import. Sales reps automatically see only their own assigned prospects; admins and owners see all prospects across the company. Every response includes the prospect's current status, address, assigned rep, and tags.

## List prospects

<Note>
  Sales reps without `canViewAllProspects` permission see only prospects assigned to them. Admins and owners see all company prospects.
</Note>

```
GET /api/prospects
```

### Query parameters

<ParamField query="bbox" type="string">
  Bounding box filter as `minLng,minLat,maxLng,maxLat`. Returns only prospects whose coordinates fall within the box. Example: `-85.7,42.9,-85.5,43.1`
</ParamField>

<ParamField query="dateFrom" type="string">
  ISO 8601 date string. Returns prospects created on or after this date. Example: `2024-01-01`
</ParamField>

<ParamField query="dateTo" type="string">
  ISO 8601 date string. Returns prospects created on or before this date. Example: `2024-12-31`
</ParamField>

<ParamField query="status" type="string">
  Comma-separated list of status values. Example: `contacted,sold`
</ParamField>

<ParamField query="assignedToUserId" type="string">
  Comma-separated list of user IDs. Admin and owner only. Example: `12,34`
</ParamField>

<ParamField query="rep" type="string">
  Comma-separated list of rep full names. Admin and owner only. Example: `Jane Smith,Bob Jones`
</ParamField>

<ParamField query="tagId" type="string">
  Comma-separated list of tag display values (not IDs). Example: `solar,roofing`
</ParamField>

<ParamField query="city" type="string">
  Comma-separated list of city names. Example: `Grand Rapids,Holland`
</ParamField>

<ParamField query="search" type="string">
  Full-text search across name, phone, email, address, and notes.
</ParamField>

<ParamField query="page" type="number" default="1">
  Page number (1-indexed).
</ParamField>

<ParamField query="pageSize" type="number" default="50">
  Number of records per page.
</ParamField>

### Response

<ResponseField name="items" type="object[]">
  Array of prospect objects.

  <Expandable title="prospect object">
    <ResponseField name="id" type="number">Unique prospect ID.</ResponseField>
    <ResponseField name="name" type="string | null">Prospect's full name.</ResponseField>
    <ResponseField name="phoneNumber" type="string | null">Primary phone number.</ResponseField>
    <ResponseField name="secondaryPhoneNumber" type="string | null">Secondary phone number.</ResponseField>
    <ResponseField name="emailAddress" type="string | null">Email address.</ResponseField>
    <ResponseField name="lat" type="number | null">Latitude coordinate.</ResponseField>
    <ResponseField name="lng" type="number | null">Longitude coordinate.</ResponseField>
    <ResponseField name="source" type="string | null">How the prospect was added (e.g. `csv-import`).</ResponseField>
    <ResponseField name="customFieldData" type="object | null">Key/value store for custom fields.</ResponseField>
    <ResponseField name="createdAt" type="string">ISO 8601 creation timestamp.</ResponseField>

    <ResponseField name="address" type="object | null">
      <Expandable title="address">
        <ResponseField name="id" type="number">Address ID.</ResponseField>
        <ResponseField name="address1" type="string">Street line 1.</ResponseField>
        <ResponseField name="address2" type="string | null">Street line 2.</ResponseField>
        <ResponseField name="city" type="string">City.</ResponseField>
        <ResponseField name="state" type="string">State.</ResponseField>
        <ResponseField name="zip" type="string">ZIP code.</ResponseField>
        <ResponseField name="formattedAddress" type="string | null">Full formatted address string.</ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="currentStatus" type="object | null">
      <Expandable title="status">
        <ResponseField name="id" type="number">Status ID.</ResponseField>
        <ResponseField name="value" type="string">Status display label.</ResponseField>
        <ResponseField name="color" type="string">Hex color code.</ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="assignedTo" type="object | null">
      <Expandable title="assignedTo">
        <ResponseField name="id" type="number">User ID.</ResponseField>
        <ResponseField name="firstName" type="string">First name.</ResponseField>
        <ResponseField name="lastName" type="string">Last name.</ResponseField>
        <ResponseField name="email" type="string">Email address.</ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="tags" type="object[]">
      Array of `{ tag: { id, value, color } }` objects.
    </ResponseField>

    <ResponseField name="appointments" type="object[]">
      Up to one upcoming appointment. See [Appointments](/api/appointments) for the full shape.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="total" type="number">Total number of matching prospects.</ResponseField>
<ResponseField name="page" type="number">Current page number.</ResponseField>
<ResponseField name="pageSize" type="number">Records per page.</ResponseField>

<CodeGroup>
  ```bash cURL theme={null}
  curl --request GET \
    --url 'https://app.leadscoutapp.com/api/prospects?status=contacted&page=1&pageSize=25' \
    --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    'https://app.leadscoutapp.com/api/prospects?status=contacted&page=1&pageSize=25',
    { headers: { Authorization: `Bearer ${accessToken}` } }
  );
  const { items, total } = await response.json();
  ```
</CodeGroup>

***

## Create a prospect

```
POST /api/prospects
```

### Request body

<ParamField body="name" type="string">
  Prospect's full name.
</ParamField>

<ParamField body="phoneNumber" type="string">
  Primary phone number.
</ParamField>

<ParamField body="secondaryPhoneNumber" type="string">
  Secondary phone number.
</ParamField>

<ParamField body="emailAddress" type="string">
  Must be a valid email format if provided.
</ParamField>

<ParamField body="lat" type="number">
  Latitude coordinate.
</ParamField>

<ParamField body="lng" type="number">
  Longitude coordinate.
</ParamField>

<ParamField body="addressId" type="number">
  ID of an existing address record to associate.
</ParamField>

<ParamField body="currentStatusId" type="number">
  ID of a lead status. If provided, a status history entry is created automatically.
</ParamField>

<ParamField body="assignedToUserId" type="number">
  ID of the user to assign this prospect to.
</ParamField>

<ParamField body="source" type="string">
  Origin string (e.g. `api`, `csv-import`).
</ParamField>

<ParamField body="sourceId" type="string">
  External ID from the originating system.
</ParamField>

<ParamField body="sourceCreatedAt" type="string">
  ISO 8601 timestamp from the originating system.
</ParamField>

<ParamField body="customFieldData" type="object">
  Arbitrary key/value pairs for custom fields.
</ParamField>

Returns `201` with the created prospect object on success.

<CodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
    --url https://app.leadscoutapp.com/api/prospects \
    --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
    --header 'Content-Type: application/json' \
    --data '{
      "name": "Jane Smith",
      "phoneNumber": "616-555-0100",
      "emailAddress": "jane@example.com",
      "lat": 42.9634,
      "lng": -85.6681,
      "currentStatusId": 3,
      "assignedToUserId": 7
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://app.leadscoutapp.com/api/prospects', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${accessToken}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      name: 'Jane Smith',
      phoneNumber: '616-555-0100',
      emailAddress: 'jane@example.com',
      lat: 42.9634,
      lng: -85.6681,
      currentStatusId: 3,
      assignedToUserId: 7,
    }),
  });
  const prospect = await response.json();
  ```
</CodeGroup>

***

## Get a prospect

```
GET /api/prospects/:id
```

Returns a single prospect with its full history, including up to 5 recent notes, all appointments, and the complete status history.

### Path parameters

<ParamField path="id" type="number" required>
  The prospect ID.
</ParamField>

Returns `404` if the prospect does not exist or belongs to a different company.

<CodeGroup>
  ```bash cURL theme={null}
  curl --request GET \
    --url https://app.leadscoutapp.com/api/prospects/42 \
    --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://app.leadscoutapp.com/api/prospects/42', {
    headers: { Authorization: `Bearer ${accessToken}` },
  });
  const prospect = await response.json();
  ```
</CodeGroup>

***

## Update a prospect

```
PATCH /api/prospects/:id
```

All body fields are optional. Only the fields you send are changed. If you change `currentStatusId`, a new status history entry is created.

### Path parameters

<ParamField path="id" type="number" required>
  The prospect ID.
</ParamField>

### Request body

<ParamField body="name" type="string">Full name.</ParamField>
<ParamField body="phoneNumber" type="string">Primary phone number.</ParamField>
<ParamField body="secondaryPhoneNumber" type="string">Secondary phone number.</ParamField>
<ParamField body="emailAddress" type="string">Valid email address.</ParamField>
<ParamField body="lat" type="number">Latitude coordinate.</ParamField>
<ParamField body="lng" type="number">Longitude coordinate.</ParamField>
<ParamField body="addressId" type="number">Address record ID.</ParamField>
<ParamField body="currentStatusId" type="number">New lead status ID.</ParamField>
<ParamField body="assignedToUserId" type="number">User ID to (re-)assign to.</ParamField>
<ParamField body="assignedByUserId" type="number">User ID of the person performing the assignment.</ParamField>
<ParamField body="source" type="string">Origin string.</ParamField>
<ParamField body="sourceId" type="string">External ID.</ParamField>
<ParamField body="customFieldData" type="object">Custom field key/value pairs.</ParamField>

<CodeGroup>
  ```bash cURL theme={null}
  curl --request PATCH \
    --url https://app.leadscoutapp.com/api/prospects/42 \
    --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
    --header 'Content-Type: application/json' \
    --data '{ "currentStatusId": 5, "assignedToUserId": 12 }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://app.leadscoutapp.com/api/prospects/42', {
    method: 'PATCH',
    headers: {
      Authorization: `Bearer ${accessToken}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ currentStatusId: 5, assignedToUserId: 12 }),
  });
  const updated = await response.json();
  ```
</CodeGroup>

***

## Delete a prospect

```
DELETE /api/prospects/:id
```

Deletes the prospect. The record is excluded from all list and single-get responses immediately, but is not permanently destroyed so your data history is preserved.

### Path parameters

<ParamField path="id" type="number" required>
  The prospect ID.
</ParamField>

Returns `{ "id": <number> }` on success.

<CodeGroup>
  ```bash cURL theme={null}
  curl --request DELETE \
    --url https://app.leadscoutapp.com/api/prospects/42 \
    --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
  ```

  ```javascript JavaScript theme={null}
  await fetch('https://app.leadscoutapp.com/api/prospects/42', {
    method: 'DELETE',
    headers: { Authorization: `Bearer ${accessToken}` },
  });
  ```
</CodeGroup>

***

## Export prospects as CSV

```
GET /api/prospects/export
```

Returns a downloadable `prospects.csv` file. Supports the same filter parameters as the list endpoint (`bbox`, `dateFrom`, `dateTo`, `status`, `assignedToUserId`, `tagId`). The file is streamed in batches of 500 records — there is no page limit.

### CSV columns

`id`, `name`, `phone`, `email`, `lat`, `lng`, `address1`, `address2`, `city`, `state`, `zip`, `status`, `assignedTo`, `assignedToEmail`, `tags` (semicolon-separated), `notes` (most recent), `createdBy`, `source`, `createdAt`

<CodeGroup>
  ```bash cURL theme={null}
  curl --request GET \
    --url 'https://app.leadscoutapp.com/api/prospects/export?status=sold' \
    --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
    --output prospects.csv
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    'https://app.leadscoutapp.com/api/prospects/export?status=sold',
    { headers: { Authorization: `Bearer ${accessToken}` } }
  );
  const blob = await response.blob();
  // In a browser: trigger download
  const url = URL.createObjectURL(blob);
  ```
</CodeGroup>

***

## Import prospects from CSV

```
POST /api/prospects/import
```

<Warning>
  This endpoint requires the `canManageProspects` permission. Sales reps without that permission receive a `403`.
</Warning>

Upload a CSV file as `multipart/form-data`. Each row creates one prospect. Rows missing both an address (`address1` + `city` + `state` + `zip`) and coordinates (`lat` + `lng`) are skipped.

### Form fields

<ParamField body="file" type="file" required>
  A CSV file. The first row must be a header row. Supported columns: `name`, `phone`, `email`, `lat`, `lng`, `address1`, `address2`, `city`, `state`, `zip`, `status` (matched by display value), `assignedTo` (matched by email address), `tags` (semicolon-separated tag values), `notes`.
</ParamField>

### Response

<ResponseField name="imported" type="number">Number of successfully created prospects.</ResponseField>
<ResponseField name="skipped" type="number">Number of rows that were skipped due to errors.</ResponseField>

<ResponseField name="errors" type="object[]">
  Array of `{ row: number, message: string }` objects describing each skipped row.
</ResponseField>

<CodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
    --url https://app.leadscoutapp.com/api/prospects/import \
    --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
    --form 'file=@/path/to/prospects.csv'
  ```

  ```javascript JavaScript theme={null}
  const formData = new FormData();
  formData.append('file', csvFile); // File object from an <input type="file">

  const response = await fetch('https://app.leadscoutapp.com/api/prospects/import', {
    method: 'POST',
    headers: { Authorization: `Bearer ${accessToken}` },
    body: formData,
  });
  const { imported, skipped, errors } = await response.json();
  ```
</CodeGroup>

***

## Get map pins

```
GET /api/prospects/pins
```

Returns a lightweight array of coordinate and color data for rendering map pins. Supports the same filter parameters as the list endpoint. Use this endpoint instead of the full list when you only need to render markers on a map — it returns far less data.

### Response

Returns an array of pin objects directly (not paginated).

<ResponseField name="id" type="number">Prospect ID.</ResponseField>
<ResponseField name="lat" type="number">Latitude.</ResponseField>
<ResponseField name="lng" type="number">Longitude.</ResponseField>
<ResponseField name="statusColor" type="string">Hex color from the prospect's current status, or `#9CA3AF` if no status is set.</ResponseField>

<CodeGroup>
  ```bash cURL theme={null}
  curl --request GET \
    --url 'https://app.leadscoutapp.com/api/prospects/pins?bbox=-85.7,42.9,-85.5,43.1' \
    --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    'https://app.leadscoutapp.com/api/prospects/pins?bbox=-85.7,42.9,-85.5,43.1',
    { headers: { Authorization: `Bearer ${accessToken}` } }
  );
  const pins = await response.json();
  // [{ id: 1, lat: 42.96, lng: -85.66, statusColor: '#22C55E' }, ...]
  ```
</CodeGroup>
