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

# Contacts

> Manage the people your Retell agents call and text: contact records keyed by phone number, custom contact fields, post-call data mappings, and CRM sync.

Contacts is your workspace's record of the people your agents talk to. Each contact is keyed by phone number and collects the conversations you've had with that person, along with any fields you choose to store about them. Those fields reach the agent as [dynamic variables](/build/dynamic-variables) on the next phone call or SMS chat. [Contact memory](/features/contact-memory) adds a running brief of previous conversations.

Open it from the **Contacts** tab under **Data** in the dashboard.

<Frame caption="The Contacts page, showing each contact's conversation count and last conversation.">
  <div style={{ aspectRatio: '16 / 9', display: 'flex', alignItems: 'center', justifyContent: 'center', width: '100%' }}>
    <img src="https://mintcdn.com/retellai/sRyxHQPc2FNpy8QJ/images/contacts/contacts-list.png?fit=max&auto=format&n=sRyxHQPc2FNpy8QJ&q=85&s=28bf12cfc0e8f089b81e62a819da38d2" alt="Contacts page in the Retell dashboard showing a table of contacts with columns for phone number, first name, last name, related conversations, latest conversation, do not call, external ID, and a custom email field. Custom field columns continue off to the right." style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }} width="1600" height="900" data-path="images/contacts/contacts-list.png" />
  </div>
</Frame>

## When to use it

* **Your CRM is the source of truth.** Sync contacts in from [your CRM](/integrations/crm-overview) and map their fields to agent variables once, instead of passing the same values on every API call.
* **Conversations span more than one call.** When a long call drops or the person calls back, the agent picks up with the context from last time rather than restarting discovery.
* **You run follow-up or chase sequences.** The next call can act on what the last one produced.
* **You want one set of fields across agents.** Post-call data mappings are set per workspace, not per agent, so every agent writes to the same contact fields.

### Example

A tutoring company runs 20-minute enrollment calls. They store `program_interest`, `budget_range`, and `last_topic_discussed` as contact fields, filled from [Post Call Extraction](/features/post-call-analysis-overview). When a prospect calls back after a dropped call, the agent already has all three and resumes at the pricing conversation instead of starting over.

## How contacts are created

Contacts arrive through these flows, all matched by phone number:

* **Automatically, after a conversation.** When a phone call or SMS chat ends, Retell looks up the number (the caller's number on inbound, the number you dialed on outbound). If no contact matches, it creates one, then updates the contact's conversation count and last-conversation time. Web calls and web chats have no phone number, so they don't create contacts.
* **Manually**, from **Actions → Add contact**, or through **Actions → Upload CSV**.
* **From your CRM**, if you've connected [a CRM integration](/integrations/crm-overview) and configured inbound sync.

A phone number identifies exactly one contact. Adding a contact whose number already exists fails with "A contact with phone number +14155551000 already exists."

## Add a contact

<Steps>
  <Step title="Open the form">
    Select **Actions → Add contact**.

    <Frame caption="The Add Contact form, with the workspace's custom fields below the built-in ones.">
      <img src="https://mintcdn.com/retellai/sRyxHQPc2FNpy8QJ/images/contacts/add-contact.png?fit=max&auto=format&n=sRyxHQPc2FNpy8QJ&q=85&s=45724227a9183109c65793cc3310fcf1" alt="Add Contact dialog with a required phone number field showing the placeholder +14155552671, first name, last name, a Do not call dropdown set to False, and a Custom fields section listing the workspace's own fields: Company, Email, Preferred language, an Account tier selector, and a Renewal date picker." style={{ maxHeight: 560 }} width="1202" height="1010" data-path="images/contacts/add-contact.png" />
    </Frame>
  </Step>

  <Step title="Enter the phone number">
    Required, and it has to be a valid number. Use E.164 format, for example `+14155552671`. This is the key everything else matches on.
  </Step>

  <Step title="Fill in the rest">
    First name, last name, **Do not call**, and tags are optional, as are any custom fields you've defined. Custom field values are checked against the field's type, so a number field rejects text and an enum field rejects values outside its options.
  </Step>

  <Step title="Create">
    Select **Create**. The contact appears in the table right away, with no conversations attached until one happens.
  </Step>
</Steps>

## Work with the contacts table

The table lists every contact in the workspace with these built-in columns, plus one for each custom field you've defined:

| Column | What it shows |
| - | - |
| Phone Number | The contact's number, and the key used to match conversations. |
| First Name / Last Name | Set manually, synced from your CRM, or written by Post Call Extraction. |
| Contact ID | The record's identifier, for example `contact_9f2c41ab77de05c3aa61e480`. |
| Related Conversations | How many calls and chats are attached to this contact. |
| Latest Conversation | When you last spoke to them. |
| Do Not Call | A flag you can set, filter on, and sync with your CRM. Outbound calls, SMS, and campaigns set to honor DNC skip these contacts, and [Do-not-contact Handling](/build/do-not-call) sets it when a caller asks not to be called. |
| External ID | The record ID in the connected CRM, when the contact came from one. |
| Tags | Custom labels for filtering and organizing contacts. |

The settings icon above the table, labelled **Manage table**, controls which columns appear and in what order. The arrangement is saved for the workspace, so everyone sees the same table.

**Search** matches phone number, first name, last name, external ID, and custom field values.

**Filters** narrow by phone number, external ID (including whether one exists at all), do-not-call, last conversation time, tags, and any custom field.

## Open a contact

Selecting a row opens a panel with two halves:

* **Contact information** lists every field on the record and lets you edit them in place. Saving an edit on a CRM-linked contact also pushes the change back to your CRM, if outbound sync is configured.
* **Conversations** lists the calls and chats attached to that number, newest first, with total time and a split of inbound calls, outbound calls, and messages. Selecting one opens the full session.

Use the up and down arrow keys to step through contacts without closing the panel.

<Frame caption="A contact's fields on the left, every call and chat with that number on the right.">
  <img src="https://mintcdn.com/retellai/sRyxHQPc2FNpy8QJ/images/contacts/contact-detail.png?fit=max&auto=format&n=sRyxHQPc2FNpy8QJ&q=85&s=12cf2855335a386bf3c6e08babc7c5b3" alt="Contact detail panel for Ada Lovelace showing Contact information with first and last name, related conversations, latest conversation, do not call, external ID, contact ID, and custom fields such as Company, Account tier, Renewal date, and Situation summary, beside a Conversations panel with total time, average call length, an inbound and outbound split bar, and a list of call summaries tagged successful or unsuccessful with sentiment and disconnection reason." style={{ maxHeight: 560 }} width="1812" height="1520" data-path="images/contacts/contact-detail.png" />
</Frame>

## View and edit conversation memory

The **Conversation Memory** field in **Contact information** holds the contact's running brief. Select **View all** to expand a long memory and **View less** to collapse it.

If the contact has no saved memory, the field shows “No memory yet. Conversation memory can be enabled in agent settings.” This message appears regardless of the agents' settings. To check whether an agent saves memory, open **Post call memory settings** on that agent and check **Save conversation to memory**.

<Frame caption="An empty memory shows the same message regardless of whether an agent has saving enabled.">
  <img src="https://mintcdn.com/retellai/1okZAjshfQRF7k8p/images/contact-memory-empty-state.png?fit=max&auto=format&n=1okZAjshfQRF7k8p&q=85&s=995dbe2937f471fa74b9a91ee86175cd" alt="Ada Lovelace's contact detail panel with Conversation Memory highlighted in blue. The empty field reads: No memory yet. Conversation memory can be enabled in agent settings." style={{ maxHeight: 560 }} width="696" height="478" data-path="images/contact-memory-empty-state.png" />
</Frame>

The editor appears once a contact has nonempty memory. For an empty contact, generate memory from an eligible conversation or use [backfill](#backfill-fields-from-past-conversations) first.

To update existing memory:

<Steps>
  <Step title="Edit Contact information">
    Open the contact and select **Edit** in **Contact information**. Update **Conversation Memory** inline, or use its expand control for a larger editor.
  </Step>

  <Step title="Apply the draft">
    In the expanded editor, select **Save** to place your draft back into the contact form. This does **not** save the contact yet. **Cancel** discards edits made inside that dialog.
  </Step>

  <Step title="Save the contact">
    Select **Save** in **Contact information** to persist the memory and any other field edits. Memory accepts up to **2,000 characters** (as of September 2026); over-limit text blocks saving. If saving fails, keep the form open and retry after resolving the error.
  </Step>
</Steps>

<Frame caption="The expanded memory editor stages changes; save Contact information afterward to apply them.">
  <img src="https://mintcdn.com/retellai/xbVqX5sb0RvVRdbO/images/contact-memory-editor.png?fit=max&auto=format&n=xbVqX5sb0RvVRdbO&q=85&s=fe8eb881e84b52bfc7205461c1e965d5" alt="Conversation Memory dialog over the contact detail panel, with an editable memory brief and a character counter out of 2000. The description says to save Contact information after editing this memory. Cancel and Save are at the bottom." style={{ maxHeight: 560 }} width="840" height="565" data-path="images/contact-memory-editor.png" />
</Frame>

To clear memory, delete its text and save Contact information. Clearing it doesn't disable future updates. Later conversations can write new memory if **Save conversation to memory** remains enabled on their agents. See [agent memory settings](/features/contact-memory#set-up-memory-on-an-agent) for saving, reading, and the workspace prompt.

## Define contact fields

Beyond the built-in fields, you can define custom fields to store anything else you want to keep about a person. Open **Actions → Manage contact fields**.

The fields table shows, for each field, its type, the CRM field it syncs with, the Post Call Extraction field that writes to it, and when it last changed.

<Frame caption="Contact fields, with CRM sync and post-call mappings shown per field.">
  <div style={{ aspectRatio: '16 / 9', display: 'flex', alignItems: 'center', justifyContent: 'center', width: '100%' }}>
    <img src="https://mintcdn.com/retellai/sRyxHQPc2FNpy8QJ/images/contacts/contact-fields.png?fit=max&auto=format&n=sRyxHQPc2FNpy8QJ&q=85&s=3d484b76b4738a21a7ed8506eb354f68" alt="Contact Fields page listing the built-in Phone Number, First Name, Last Name, and Do Not Call fields above custom fields such as Company, Email, Account tier, and Renewal date. Each row shows the HubSpot field it syncs with, the Post Call Extraction field that writes to it, an update mode badge reading Overwrite, Fill only if empty, or Accumulate and summarize, and when it last changed." style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }} width="1600" height="900" data-path="images/contacts/contact-fields.png" />
  </div>
</Frame>

<Steps>
  <Step title="Add the field">
    Select **Add Contact Field**, then pick a **type**: Text, Number, Boolean, Selector, Date, or Datetime. Type is fixed after creation, so choose deliberately.

    <Frame caption="Adding a contact field. The type can't be changed once the field exists.">
      <img src="https://mintcdn.com/retellai/sRyxHQPc2FNpy8QJ/images/contacts/add-contact-field.png?fit=max&auto=format&n=sRyxHQPc2FNpy8QJ&q=85&s=a60e15f5304b61bc1ef00110b00ddade" alt="Add contact field dialog with a Type dropdown set to Text, a Field name input with the placeholder 'e.g. Customer need', a note that the field type can't be changed once created, a Description box reading 'What this field captures', and a Map with Post-Call Data toggle." style={{ maxHeight: 560 }} width="1300" height="844" data-path="images/contacts/add-contact-field.png" />
    </Frame>
  </Step>

  <Step title="Name it">
    Field names are snake\_case: lowercase letters, numbers, and underscores, starting with a letter. Names can't collide with the built-in fields, can't start with `contact` or `external` (both reserved), and can't repeat an existing field.
  </Step>

  <Step title="Describe what it holds">
    The description tells you what the field captures. It does more than document: for fields filled by Post Call Extraction with **Accumulate & summarize**, the description is the instruction the model follows when combining an old value with a new one.
  </Step>

  <Step title="Map it to post-call data (optional)">
    Turn on the post-call mapping, choose the analysis field that feeds it, and pick how new values combine with existing ones:

    * **Overwrite** replaces the stored value every time.
    * **Fill only if empty** writes once and leaves it alone after that.
    * **Accumulate & summarize** merges the old and new values with a model, following your field description.

    Mappings apply to the whole workspace, so any agent producing that analysis field writes to this contact field. See [CRM data mappings](/integrations/crm-mappings) for mapping details. Built-in [contact memory](/features/contact-memory) saves a separate conversation brief without these mappings.
  </Step>
</Steps>

Built-in fields behave differently from custom ones. First name, last name, do-not-call, and tags can be edited and mapped, but not deleted. Phone number is fixed. Custom fields can be edited or deleted.

## Import from CSV

Use **Actions → Upload CSV** to import a contact list, such as leads from an event. Include a header row and a phone number column. CSV files can be up to **50 MB**.

Contacts are matched by phone number. If a number already exists, the import overwrites its mapped fields and leaves unmapped fields unchanged. New numbers create new contacts. Imported tags are added to existing tags without duplicates.

<Steps>
  <Step title="Upload and preview">
    Select your CSV file, review the preview, then select **Continue**.

    <Frame caption="Preview a CSV with 12 sample contacts, starting with Ada Lovelace.">
      <img src="https://mintcdn.com/retellai/tmZkSrjibf0XZ68U/images/contacts/contacts-csv-preview.png?fit=max&auto=format&n=tmZkSrjibf0XZ68U&q=85&s=5268d2e8eb3072389064dda7ddd3f29b" alt="Preview CSV uploading dialog showing computer-science-contacts.csv with 12 contacts, phone_number, first_name, and last_name columns, and sample rows starting with Ada Lovelace, Alan Turing, and Grace Hopper. The upload is completed and Continue is available." style={{ maxHeight: 560 }} width="1088" height="716" data-path="images/contacts/contacts-csv-preview.png" />
    </Frame>
  </Step>

  <Step title="Map the columns">
    Select the columns to import and map each to a contact field. Map exactly one column to **Phone Number**; each contact field can receive only one CSV column. You can select an existing field or create a custom field from the mapping selector.

    Choose the default country for phone numbers that don't include a country code, then select **Confirm mapping**.
  </Step>

  <Step title="Add tags and confirm">
    Optionally select existing tags or type to create new ones, for example `event_lead`. These tags apply to every contact in the import. Leaving this step empty keeps existing contacts' tags unchanged.

    Select **Confirm** to submit the import.
  </Step>
</Steps>

## Use contact data in a conversation

When a phone call or SMS chat starts, Retell looks up the contact by number and passes its fields to the agent as dynamic variables: `first_name`, `last_name`, `do_not_call`, `contact_memory` when stored, and one per custom field, each named after the field. Reference them in the prompt the same way as any other [dynamic variable](/build/dynamic-variables), for example `{{first_name}}`.

This applies to inbound calls, outbound calls, [batch calls](/deploy/make-batch-call), and SMS chats. If no contact matches the number, the variables are absent, so write prompts that read naturally without them. Enable **Use contact memory** to include stored memory in the agent's context automatically, without adding a variable to its prompt.

## Read contacts from the API

The [Contact API](/api-references/get-contact) returns the same records the dashboard shows, so your own systems can check who you've already spoken to before placing a call. Every contact carries:

| Field | What it holds |
| - | - |
| `contact_id`, `phone_number` | The record's identifier and its E.164 phone number. |
| `first_name`, `last_name`, `external_id` | Name, and the record ID in your connected CRM. |
| `do_not_call` | The do-not-call flag. |
| `contact_tags`, `custom_fields` | Tags, and one value per custom contact field. |
| `conversation_count` | How many phone calls and chats are attached to the number. |
| `last_conversation_timestamp` | Start time of the most recent conversation, in epoch milliseconds. |
| `created_timestamp`, `user_modified_timestamp` | When the contact was created and last edited, in epoch milliseconds. |

Use these endpoints to read them:

* [Get contact by phone](/api-references/get-contact-by-phone) looks up one number. Send it in E.164 format.
* [List contacts](/api-references/list-contacts) filters the whole set by `last_conversation_timestamp`, `do_not_call`, `external_id`, tags, and custom fields, up to 1,000 per page.
* [List contact conversations](/api-references/list-contact-conversations) returns every call and chat with the number, newest first, with each one's start time, duration, direction, disconnection reason, summary, sentiment, and success flag.

The counts update when a phone call or SMS chat ends, after post-call analysis runs, so expect a short delay after hang-up. Every outbound phone call counts as a conversation, including ones that reach voicemail or go unanswered, so a cooldown based on `last_conversation_timestamp` also covers dial attempts. Web calls and web chats never count.

## Limit how often you call a number

Retell doesn't cap how often your agent calls a number. [Create Phone Call](/api-references/create-phone-call) checks `do_not_call` only when you pass `honor_internal_dnc: true` (see [do-not-call requests](/build/do-not-call#skip-do-not-call-contacts)), and [batch calls](/deploy/make-batch-call) don't check it. To avoid calling someone too often, check the contact before you dial.

A debt collection team, for example, calls each customer at most once every 48 hours. Before each call, their dialer looks up the number and skips it if the last conversation was too recent:

```bash theme={"dark"}
curl "https://api.retellai.com/get-contact-by-phone/+14155551000" \
  -H "Authorization: Bearer $RETELL_API_KEY"
```

```json theme={"dark"}
{
  "contact_id": "contact_9f2c41ab77de05c3aa61e480",
  "phone_number": "+14155551000",
  "do_not_call": false,
  "conversation_count": 4,
  "last_conversation_timestamp": 1790380800000,
  "created_timestamp": 1787702400000
}
```

Skip the call if `do_not_call` is `true` or `last_conversation_timestamp` is less than 48 hours ago. A `404` means you've never spoken to that number, so it's safe to call.

To build a whole call list at once, ask List contacts for everyone last spoken to before your cutoff who isn't marked do-not-call:

```bash theme={"dark"}
curl -X POST "https://api.retellai.com/list-contacts" \
  -H "Authorization: Bearer $RETELL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "limit": 1000,
    "sort_order": "asc",
    "filter_criteria": {
      "last_conversation_timestamp": { "type": "number", "op": "lt", "value": 1790208000000 },
      "do_not_call": { "type": "boolean", "op": "eq", "value": false }
    }
  }'
```

For a rule like "no more than three calls a week", list the contact's conversations and count the calls whose `start_timestamp` falls inside the window.

## Backfill fields from past conversations

Enabling memory saving or adding an extraction mapping only affects future conversations. To populate contacts from past phone calls and SMS chats, open **Actions → Backfill**. The dialog is titled **Backfill from past conversations**.

<Steps>
  <Step title="Choose the fields">
    Select **Memory**, mapped contact fields, or both. **Memory** is always a built-in target and needs no Post Call Extraction mapping. Other fields appear only when they have an analysis mapping.
  </Step>

  <Step title="Filter the conversations">
    Choose an **Agent** filter, optionally with versions, or a **Conversation time** filter. At least one agent or time bound is required. Review the selected range before running the job.
  </Step>

  <Step title="Start and monitor the backfill">
    Select **Backfill**. The Contacts header shows backfill activity, and a notification tracks the job and reports completion or errors. If starting the job fails, the dialog stays open with your selection and an error.
  </Step>
</Steps>

<Frame caption="Select Memory to summarize historical conversations independently of mapped fields.">
  <img src="https://mintcdn.com/retellai/xbVqX5sb0RvVRdbO/images/contact-memory-backfill.png?fit=max&auto=format&n=xbVqX5sb0RvVRdbO&q=85&s=13b24385a369aba801d5e8647954220d" alt="Backfill from past conversations dialog with Memory selected at $0.005 per conversation, the mapped contact fields unchecked, and a Conversation time filter. The Backfill button starts the job; Cancel closes the dialog." style={{ maxHeight: 560 }} width="840" height="750" data-path="images/contact-memory-backfill.png" />
</Frame>

For **memory backfill**:

* The agent's **latest configuration** must have **Save conversation to memory** enabled. This lets you process earlier conversations even if saving wasn't enabled when they happened.
* Only ended phone calls and SMS chats with retained transcripts are eligible. Conversations stored with **Basic Attributes Only**, missing or unreadable transcripts, and transcripts with failed PII redaction are skipped. A conversation also needs a usable user message to generate memory.
* Retell starts with the contact's current memory and processes selected conversations oldest first, using the **current workspace memory prompt**. A failed or empty rewrite keeps the previous brief.
* The price is **\$0.005 per conversation processed** as of September 2026, not per contact. Repeating a backfill can process and charge for the same conversations again.

Mapped fields use existing Post Call Extraction results and their configured update modes. To regenerate those extraction results, [rerun analysis](/features/rerun-call-analysis) first.

Only one contact backfill can run at a time per workspace. If one is already running, wait for it to finish before starting another. After completion, open a contact to check the result. If memory is still empty, check agent eligibility, the selected time range, and transcript availability before retrying.

## Keep contacts in sync with your CRM

With [a CRM connected](/integrations/crm-overview), contacts sync both directions: CRM records flow in as contacts, and edits flow back out. Two entries in the **Actions** menu control it, both disabled until a CRM is connected:

* **Manage CRM sync** opens the field mapping settings. See [CRM data mappings](/integrations/crm-mappings).
* **Run full sync** re-imports the full contact set instead of waiting for the next scheduled sync.

While two-way sync is active, contacts that came from the CRM are locked against deletion, so the CRM stays the source of truth for those records.

## Who can use it

Contacts needs CRM view permission to open, and CRM edit permission for anything that changes data: adding contacts, editing fields or memory, running a backfill, or triggering a full sync. Without edit permission the controls are visible but disabled. See [Access Control](/accounts/access-control).

## FAQ

<AccordionGroup>
  <Accordion title="Can I import contacts from a CSV?">
    Yes. [Import from CSV](#import-from-csv) to map your columns to contact fields and optionally tag the imported contacts. If your contacts live in a CRM, [connect the CRM](/integrations/crm-overview) and let inbound sync bring them in instead.
  </Accordion>

  <Accordion title="Why do contacts appear that I never added?">
    Ending a phone call or SMS chat with a number that has no contact creates one. That's what links a conversation to a person and lets the next call reuse what the last one learned.
  </Accordion>

  <Accordion title="Can two contacts share a phone number?">
    No. The number is the identifier, and creating a duplicate is rejected.
  </Accordion>

  <Accordion title="Why doesn't a contact show a conversation I know happened?">
    Conversations attach by phone number, so check that the number on the call matches the contact exactly. Web calls and web chats carry no phone number and never attach to a contact.
  </Accordion>

  <Accordion title="Can I delete a contact?">
    Use [Delete Contact](/api-references/delete-contact); the dashboard doesn't offer contact deletion today. You can clear a contact's field values by editing it, and you can delete custom contact fields from the contact fields page. Contacts synced from a CRM are locked against deletion while two-way sync is active.
  </Accordion>

  <Accordion title="What happens to my contacts if I disconnect the CRM?">
    The contacts stay. They keep their fields and their conversation history, and the External ID showing where they came from. Syncing stops, so later changes on either side no longer cross over.
  </Accordion>
</AccordionGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.