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

> ## Agent Instructions
> Use the public API base URL: https://api.teamfollowup.ai/api.
> Authenticate public API requests with Authorization: Bearer YOUR_API_KEY.
> Use product-owned terms: agents, campaigns, projects (GoHighLevel sub-accounts), contacts, calls, outcomes, skills, cadences, phone numbers.
> Scope requests by locationId rather than projectName.
> Read the guide linked from each API reference group before recommending an endpoint.

# Contacts and leads

> A contact is a person the platform has dialled or answered. Read their outcome history, see when they are next due a call, and control who must never be called.

A **contact** is one person, keyed by phone number, that a campaign has called
or that has called you. The contact record is where you answer "how many times
did we try, what happened, and when do we try again?" It is also where you say
"never call this person".

Contacts come from GoHighLevel. The platform does not keep its own address
book. It keeps the calling history against each GoHighLevel contact.

## What one contact holds

`GET /api/contacts` returns one row per unique contact.

| Field                          | Meaning                                                                                                     |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------- |
| `id`                           | The contact record id.                                                                                      |
| `contactId`                    | The GoHighLevel contact id. About 2% of contacts have none and are reachable only by number.                |
| `phoneNumber` and `leadName`   | Who they are.                                                                                               |
| `projectName` and `locationId` | Which project they belong to. `locationId` also builds the deep link into the sub-account.                  |
| `dateAdded`                    | When the platform first saw them.                                                                           |
| `callCount`                    | How many calls they have had.                                                                               |
| `disposition`                  | The most recent outcome, as `type`, `label`, `color`, and the appointment details when there was a booking. |
| `nextScheduledCall`            | `nextCallTime` and `cadenceStep` when the [power dialer](/power-dialer/overview) has a call queued.         |
| `isInternal`                   | `true` when you have marked this contact as one of your own test leads.                                     |

`GET /api/contacts/{phoneNumber}/calls` returns everything the platform has
done with one person: their calls and a `dispositionSummary` counting how the
calls ended.

## Outcome types on a contact

A contact's `disposition.type` and the `disposition` filter use these values:

| Value            | Meaning                                                                                                   |
| ---------------- | --------------------------------------------------------------------------------------------------------- |
| `appointment`    | Booked, confirmed or rescheduled an appointment.                                                          |
| `callBack`       | Asked to be called back, or asked for information.                                                        |
| `liveTransfer`   | Was handed to a person.                                                                                   |
| `failedTransfer` | A transfer was attempted and did not connect.                                                             |
| `killSwitch`     | Opted out. Asked not to be called again.                                                                  |
| `tagged`         | The call applied a CRM tag. `tagged` never masks another outcome. Tagged plus booked reads `appointment`. |

These are the contact-level names. The per-call outcome constants that
workflows route on, such as `SUCCESS` and `KILL_SWITCH`, are listed in
[What your agent records](/agents/outcomes).

## Four ways to stop calling someone

They look similar and they are not. Pick the one that matches who decided and
how wide it reaches.

| Mechanism            | Who decides                       | Reach                | How                                                                                                                                                         |
| -------------------- | --------------------------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Exit tag**         | Your CRM automation, or you       | One campaign         | The contact picks up a tag listed in the campaign's `inactiveTags` and leaves that campaign's list. See [Who gets called](/campaigns/audience).             |
| **Opt-out outcome**  | The agent, on the call            | The whole project    | The lead asks to stop. The call ends `KILL_SWITCH`, the contact is tagged `tfu_ai_kill_switch`, and every campaign in the project treats them as opted out. |
| **Do-not-call flag** | You, deliberately                 | The whole project    | `POST /api/contacts/{contactId}/do-not-call` with the project's `locationId`. `DELETE` the same path to clear it.                                           |
| **GoHighLevel DND**  | The contact record in GoHighLevel | Per campaign setting | A campaign skips contacts with Do Not Disturb on unless its `callIfDnd` is `true`.                                                                          |

<Warning>
  Clearing a do-not-call flag can produce a call that should not be placed.
  Treat `DELETE /api/contacts/{contactId}/do-not-call` as a deliberate act, and
  scope API keys that hold `contacts:write` accordingly.
</Warning>

## Your own test leads

You will dial yourself and your team while building. Mark those contacts as
internal with `POST /api/contacts/internal`, identifying the contact by
`contactId`, by `phoneNumber`, or by both, with the project's `locationId`.

* Their calls are left out of every performance figure: lead counts, booking
  and transfer rates, pickup, trends and the heatmap.
* Their cost is kept. The minutes were really spent and really billed, so the
  dashboard stays in step with your wallet.
* They still get called. The mark changes reporting only.

`GET /api/contacts` lists them by default with `isInternal` set on each row.
Send `internal=only` to see just them, or `internal=exclude` to hide them.
Clear the mark with `DELETE /api/contacts/internal`.

## Finding contacts

| To find                                                                                        | Send                                                                                                                |
| ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| One project's contacts                                                                         | `locationId`. Several at once: `locationIds`, comma-separated. Names are display labels and cannot select contacts. |
| Contacts one campaign dialled                                                                  | `campaignId`                                                                                                        |
| Contacts an entire [master agent](/master-agent/overview) dialled, across every linked project | `masterCampaignId`. Mutually exclusive with `campaignId`.                                                           |
| Contacts one [split-test variant](/split-testing/overview) spoke to                            | `agentVariantId`, together with `campaignId`                                                                        |
| By outcome                                                                                     | `disposition`, repeated or comma-joined                                                                             |
| By name, number or id                                                                          | `search`                                                                                                            |
| Added in a date range                                                                          | `dateFromUTC` and `dateToUTC`                                                                                       |

Sort with `sortBy` (`leadName`, `phoneNumber`, `projectName`, `dateAdded`,
`callCount`) and `sortOrder` (`asc`, `desc`). Page with `page` and `limit`.
`GET /api/contacts/filters` returns the projects and dispositions present in
your data.

## Boundaries

* A contact is unique per phone number within a project.
* `projectName` on a write is a display label only. `locationId` is the tenant
  identity.
* Marking a contact internal never suppresses a call. Use the do-not-call flag
  for that.

## In the API

* [List contacts](/api-reference/contacts/list-contacts) and
  [List contact filter options](/api-reference/contacts/list-contact-filter-options)
* [List contact calls](/api-reference/contacts/list-contact-calls)
* [Set contact do-not-call](/api-reference/contacts/set-contact-do-not-call) and
  [Clear contact do-not-call](/api-reference/contacts/clear-contact-do-not-call)
* [Mark contact internal](/api-reference/contacts/mark-contact-internal) and
  [Clear contact internal mark](/api-reference/contacts/clear-contact-internal-mark)
* Every field above is defined in the [Glossary](/glossary#contacts)

## Related

* [Call records](/calls/overview) hold the per-call detail behind each contact.
* [Backfill existing leads](/campaigns/backfill-existing-leads) enrols contacts
  that were already in the CRM.
