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

# Importing & Exporting Contacts (CSV)

> How to bulk-import contacts from a CSV file — flexible column headings, duplicate handling, and typed custom-variable mapping — and how to export a filtered contact list that can be re-imported later.

## Overview

The **Contacts** page imports and exports contacts as CSV files — CSV is the only supported file format. Both actions live in the table toolbar at the top of the page:

* **Upload CSV** — opens the **Upload Contacts** dialog to import contacts from a file.
* **Download CSV** — exports the contacts currently shown in the table.

The two formats are designed to round-trip: an export uses the same column headings as the import template, so you can download your contacts, edit them in a spreadsheet, and upload the file again to apply the changes.

Everything you import becomes available to your voice agents on calls. For example, a contact's name is spoken through `{{contact.first_name}}` (string, e.g. `Jane`) and their number dialled from `{{contact.phone}}` (string, e.g. `+61412345678`) — see [Custom Variables](/custom-variables/overview) for how contact data flows into scripts.

***

## Preparing your CSV file

Click **Upload CSV** on the Contacts page to open the **Upload Contacts** dialog, then drop a `.csv` file onto the upload area or click **Browse Files**. A **Download CSV Template** button below the upload area gives you a ready-made file (`contacts_template.csv`) with three example rows showing accepted phone formats.

### Flexible column headings

You don't need to match the template headings exactly — each contact field accepts several common spellings:

| Contact field | Accepted column headings                                |
| ------------- | ------------------------------------------------------- |
| Full Name     | `Full Name`, `full_name`, `name`, `full name`           |
| First Name    | `First Name`, `first_name`, `first name`                |
| Last Name     | `Last Name`, `last_name`, `surname`, `last name`        |
| Phone Number  | `Phone Number`, `phone_number`, `phone`, `phone number` |
| Email         | `Email`, `email`                                        |
| Address       | `Address`, `address`                                    |
| Company       | `Company`, `company`, `company_name`, `company name`    |
| Status        | `Status`, `status`                                      |
| Age           | `Age`, `age`                                            |
| Gender        | `Gender`, `gender`                                      |
| Location      | `Location`, `location`                                  |
| Title         | `Title`, `title`                                        |

If a row has a **Full Name** but no first or last name, the name is split automatically: the first word becomes the first name and the rest becomes the last name.

### Validation rules

| Field                     | Required | Rules                                                                                  |
| ------------------------- | -------- | -------------------------------------------------------------------------------------- |
| First Name                | Yes      | Up to 255 characters. Can be derived from Full Name.                                   |
| Phone Number              | Yes      | Must be a valid number in international format after automatic formatting (see below). |
| Last Name, Company, Title | No       | Up to 255 characters each.                                                             |
| Email                     | No       | Must be a valid email address when present.                                            |
| Address                   | No       | Up to 500 characters.                                                                  |
| Age                       | No       | A whole number from 0 to 150.                                                          |
| Gender                    | No       | `male`, `female` or `other` (any case). Other values are ignored rather than rejected. |
| Status, Location          | No       | Free text.                                                                             |

### Phone number formatting

Phone numbers are converted to international format (e.g. `+61412345678`) automatically. Australian numbers are recognised in their everyday forms — mobiles (`0423 456 789`), landlines (`(08) 9123 4567`), and 13/1300/1800 numbers — with spaces, brackets and dashes stripped. Numbers already carrying a `+` country code (such as `+64` or `+44`) are kept as they are; a number with no country code and no leading `0` is assumed to be Australian. Rows whose number still isn't valid after formatting are rejected with the message *Please use international format (e.g., +61400123456)*.

***

## Reviewing the import

After the file is parsed, the dialog shows a review screen. Every row lands in one of three groups:

* **Invalid contacts** — rows that failed validation, listed with the reason (e.g. *First name is required*). These cannot be imported; fix the file and click **Change File** to upload it again.
* **Existing contacts to update** — rows whose phone number matches a contact you already have. These are **not selected by default**: updating an existing contact is opt-in. Tick the rows you want, and the CSV's values will overwrite that contact's details.
* **Select contacts to create** — new, valid rows. These are all selected by default; untick any you don't want.

If the same phone number appears more than once within the file, only the first row is kept — the repeats are silently skipped.

When you're ready, click the import button — it's labelled with a live count, e.g. **Import 25 Contacts (20 new, 5 update)**. A summary appears when the import finishes, e.g. *Contacts imported: 20 created, 5 updated*, with any failures counted separately.

Importing does **not** check numbers against the Do Not Call Register — newly imported contacts start as *Not washed*. See [DNCR Washing](/contacts/dncr-washing) before calling them in bulk.

***

## Importing custom variables with your contacts

The review screen ends with a **Per-contact custom variables** section, which maps extra CSV columns onto a [custom variable type](/custom-variables/types) so each imported contact arrives with a linked custom variable — no second import needed.

1. Pick a type from the **Select a custom variable type** dropdown (the default is **Do not import custom variables**).
2. Every CSV column that isn't a recognised contact column is listed with its own mapping dropdown. Each one is matched to a field automatically where possible; set any column to **Ignore column** to skip it.
3. Each mapping option shows the destination and its rules, e.g. *Booking → Preferred date (date, required)*.

### Stable column headings

The most reliable way to head a custom column is the `custom.{type}.{field}` pattern — for example `custom.booking.preferred_date` for the `preferred_date` field of a `booking` type. Columns named this way (or matching a field's name or label, ignoring case and punctuation) are mapped automatically when you select the type. Click **Typed template** to download a CSV pre-headed with First Name, Last Name, Phone Number and Email, plus one `custom.{type}.{field}` column per field, each with an example value.

### Value formats

Values are validated against each field's data type before anything is imported:

| Field type | Accepted values                                                                                                                        |                   |             |
| ---------- | -------------------------------------------------------------------------------------------------------------------------------------- | ----------------- | ----------- |
| Text       | Any text. Date-formatted fields require `YYYY-MM-DD`; date-and-time fields require a full timestamp, e.g. `2026-07-10T09:30:00+10:00`. |                   |             |
| Number     | Digits — `$` and `,` are stripped automatically, and minimum/maximum limits on the field are enforced.                                 |                   |             |
| Yes/No     | `yes`/`no`, `true`/`false`, `y`/`n`, or `1`/`0` (any case).                                                                            |                   |             |
| Dropdown   | Must match one of the field's options (case-insensitive).                                                                              |                   |             |
| List       | Values separated by \`                                                                                                                 | `, e.g. `item one | item two\`. |

Fields marked **required** must be mapped to a column and have a value in every selected row. Any problems are listed per row — e.g. *Row 3 (+61412345678): Preferred date: must use YYYY-MM-DD* — and the import is blocked with *Fix the custom variable errors before importing* until they're resolved. If the contacts save but their custom variables cannot, you're told explicitly: *Contacts imported, but their custom variables could not be saved.*

This `custom.{type}.{field}` mapping is the same one used everywhere contacts are imported — Lists and the Batch Scheduler included — and it always creates or updates a custom variable linked to a contact; the Custom Variables page itself only offers CSV download, not upload. See [CSV Import for Custom Variables](/custom-variables/csv-import) for the full mapping and validation rules.

***

## Exporting contacts

Click **Download CSV** in the Contacts toolbar to export. The export is **filtered**: it contains exactly the contacts currently shown in the table, so the selected list in the lists panel, your search, and any active filters and sorts all apply. The file is named with your team and the date, e.g. `contacts_acme_2026-07-16.csv`.

Columns, in order:

* **Full Name, First Name, Last Name, Phone Number, Email, Address, Company, Status, Age, Gender, Location, Title** — the same headings the import accepts, so the file can be edited and re-uploaded.
* **Last Contacted** — date and time of the most recent call, if any.
* **Calls Count** — number of calls the contact has had.
* **Properties** — reserved; always empty.
* **`custom.{type}.{field}`** — one column per field of every installed custom variable type, filled from the custom variable linked to each contact. List values are joined with `|`.
* **Created At** — when the contact record was created.

On re-import, the extra columns (Last Contacted, Calls Count, Created At) are simply ignored, and the `custom.{type}.{field}` columns map straight back through the **Per-contact custom variables** section.

***

## Other places you can import

The same flexible column mapping and validation rules appear in other flows:

* **Lists** — click **New List**, choose **From File**, then use the **Add Contacts from CSV** step to import a file and add the resulting contacts straight into the new list. See [Lists](/lists/overview).
* **Batch Scheduler** — drop a CSV onto the source lists area to open **Create list from CSV**, which creates a new list from the file (see [Source Lists](/batches/source-lists)). The **Add Calls to Batch** dialog has its own **Upload CSV** tab for loading a calling queue directly (see [Adding Contacts to a Batch](/batches/adding-contacts)).

***

## Next Steps

* [Contact Records](/contacts/records) — the fields on a contact, inline editing, and per-contact call history.
* [DNCR Washing](/contacts/dncr-washing) — wash imported numbers against the Do Not Call Register before batch calling.
* [Lists](/lists/overview) — organise imported contacts into lists for batches.
* [Linking Custom Variables to Contacts](/custom-variables/linking-contacts) — how a linked custom variable travels with the contact onto calls.
