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

# Importing contacts

> CSV import, mapping and deduplication.

Import is one upload, not a wizard. There's no separate column-mapping screen — your CSV's header row *is* the mapping.

## The columns Tied actually reads

Four headers are read by name: `name`, `email`, `identifier`, `phone_number`. A `company` or `city` column, if present, is recognized too. Anything else in your header row still gets imported — but as a custom attribute, keyed by whatever you named that column.

<Warning>
  **An unrecognized column doesn't get ignored — it becomes a custom attribute.** A leftover `id` or `row_number` column from wherever you exported the CSV will land on every contact as a custom attribute called exactly that. Drop columns that don't mean anything to you before uploading, rather than assuming Tied will skip them.
</Warning>

The import dialog offers a sample CSV to show the shape of a header row — matching it is the entire mapping step, since there's no separate field-by-field picker to walk through. But don't upload the sample file itself unedited: it ships its own `id` and `ip_address` columns, and per the warning above, both of those land on every contact as their own custom attribute. Treat it as a template for your own headers, not a file to import as-is.

## Deduplication

Import uses the same identity priority as everything else in Tied: **identifier, then email, then phone number.** A row that matches an existing contact updates it instead of creating a duplicate — but the update overwrites: any column your row supplies a value for replaces what's already on the contact, even if that value is different from what was there. A row matched on identifier with a different email, for instance, replaces the existing email. Only columns your row leaves out entirely are left alone. A row that matches nothing becomes a new contact. See [Contacts overview](/contacts) for the same logic applied to live messages arriving on a channel.

A second, database-level check backs this up for two of the three: unique indexes on email and identifier mean a colliding row can't actually be written, even if two rows in the same file would have collided. Phone number uniqueness is enforced at the model level instead of by a database index.

## What happens after you upload

The file is processed in the background, not synchronously — expect a short delay before contacts show up. Processing moves through pending, then processing, then completed or failed, with a count of how many rows succeeded against how many were rejected.

Rows that fail — an invalid phone format, a malformed email, anything that fails a normal contact validation — don't block the rest of the file. They're collected separately with a reason attached to each one. The rejected-rows file is only ever reachable by email: it's linked from the "Contact Import Completed" notification, sent to your account's administrators. There is no dashboard list of past imports to revisit it from later, so if that email is lost, the rejected-row detail goes with it.

## Next

<CardGroup cols={2}>
  <Card title="Contacts overview" icon="users" href="/contacts">
    The identity rules import reuses.
  </Card>

  <Card title="Attributes and custom fields" icon="list" href="/contacts/attributes">
    Naming a column so it lands as the custom attribute you intend.
  </Card>

  <Card title="Segments and saved filters" icon="funnel" href="/contacts/segments">
    Filtering the contacts you just imported.
  </Card>
</CardGroup>


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