CRM Contacts
CRM Contacts represent people your organization interacts with — customers, prospects, partners, or any external individuals. Each contact belongs to a tenant and can optionally be linked to an Account.
Contact Grid
The grid displays all contacts for the current tenant with columns for name, email, phone, company (account), status, source, assigned agent, and tags.
Grid Actions
- Add to List — Select contacts and click the Add to List toolbar button to add them to a static List.
- Add/Remove Tag — Right-click selected contacts to add or remove tags in bulk.
- Assign to Queue — Right-click selected contacts to assign them to a queue. This sets their visibility to “Queue” and assigns the selected queue, making them visible only to agents in that queue.
- Delete Selected — Remove selected contacts.
Filtering
The filter bar supports these criteria:
| Filter | Description |
|---|---|
| Status | Active, Inactive, or Do Not Contact |
| Source | How the contact was acquired |
| Account | Filter by linked account |
| Has Activities | Show only contacts with or without activity history |
| Tags | Search by tag text (substring match) |
Activity Timeline Badge
The grid shows an Activities badge on each contact indicating the total number of activities and interactions (e.g., “6 Activities”). Click the badge to open the contact’s timeline view, which merges CRM activities and messaging interactions in chronological order. From the timeline, you can view full conversation history for any interaction.
Create/Edit Contact
Basic Information
| Field | Description |
|---|---|
| First Name | Contact’s first name (required) |
| Last Name | Contact’s last name (required) |
| Email address | |
| Phone | Primary phone number |
| Mobile | Mobile phone number |
| Title | Job title |
| Department | Department within their organization |
Classification
| Field | Description |
|---|---|
| Account | Link to a CRM Account (company) |
| Source | How the contact was acquired: Web Form, Referral, Trade Show, Cold Call, Website, Import, Directory Import, API, Manual, Social Media, Lead Conversion |
| Status | Current status: Active, Inactive, or Do Not Contact |
| Visibility | Controls who can see this contact: All (visible to everyone), Queue (visible only to members of the assigned queue), or Owner (visible only to the assigned user). Default: All |
| Assigned Queue | The queue whose members can see this contact. Only shown when Visibility is set to “Queue” |
| Assigned To | Agent or user responsible for this contact. When Visibility is “Owner”, only this user can see the contact |
| Preferred Channel | Preferred communication channel |
| Language | Contact’s preferred language |
| Timezone | Contact’s timezone |
| Tags | Multiple tags for categorization and filtering |
Lists & Notes
| Field | Description |
|---|---|
| Lists | Read-only field showing names of static Lists this contact belongs to |
| Notes | Free-text area for additional information about the contact |
External CRM
| Field | Description |
|---|---|
| External CRM ID | Identifier in an external CRM system |
| External CRM Provider | Name of the external CRM (e.g., Salesforce, HubSpot) |
Custom Fields
If Custom Fields have been defined for contacts, they appear in a collapsible “Custom Fields” section at the bottom of the form. These fields are tenant-specific and can include text, numbers, dates, dropdowns, checkboxes, and text areas.
CSV Import
Use Import CSV in the contacts toolbar to bring contacts in from spreadsheets exported from another CRM, a directory, or any tabular source. The import runs as a three-step wizard:
Step 1 — Upload
- Choose a
.csvfile from your workstation. - Delimiter defaults to auto-detect (comma, semicolon, tab, pipe). Override when your file uses a non-standard separator.
- Uncheck First row is a header only when the CSV has no header row.
- Optional Load saved template selects a previously saved mapping profile and pre-fills the next step.
Uploads are parsed with CSV.pm and staged under the signed-in user’s scratch directory. No contacts are written until you confirm in Step 3.
Step 2 — Map fields
Each CSV column is shown as a row with a sample of its first few values and an editable Target field dropdown. The server pre-fills each row using a built-in alias map (for example, First Name, FName, and given_name all map to first_name). You can adjust any row, including mapping to:
- Core contact fields:
first_name,last_name,email,phone,mobile,title,department,status,source,preferred_channel,language,timezone,notes,assigned_to,external_crm_id,external_crm_provider,visibility,assigned_queue. - Special virtual fields:
_tag(semicolon-separated tags) and_list(row’s list name, used withlist_mode=per_row).
Columns left on (Ignore) are skipped. Click Next to continue.
Step 3 — Review & import
- On duplicate match —
Update existing(default) orSkip. Matches are detected using Match keys (any ofemail,phone,mobile,external_crm_id). - Add to list —
No list, an Existing list, or a New list created on the fly. - Dry run — Parse everything and report counts without writing. Recommended for first imports.
- Save this mapping as a template — Persists the field mapping plus the options above in
crm_import_maps, so future imports of the same source can select it in Step 1.
When you click Import the wizard reports imported / updated / skipped / error counts. Failed rows stay available as a CSV download at /api/crm-contacts/{tenant}/import-errors?token=... for the duration of the session, so you can correct them and re-import.
REST API
The same pipeline is available for automation:
POST /api/crm-contacts/{tenant}/import— inline CSV body withmapping_json.POST /api/crm-contacts/{tenant}/import-preview— header + sample rows, no write.GET|POST|PUT|DELETE /api/crm-import-maps/{tenant}[/id]— manage saved mappings.
See the Scalar UI under Configuration → Tools → OpenAPI for full request / response schemas.
Thirdlane Connect Integration
Thirdlane Connect exposes the same contacts under the Customers tab.
- A list dropdown above the contact list lets agents scope the sidebar to any static or dynamic CRM list, with live contact counts. “All contacts” returns the tenant-wide set.
- Search, alphabetical jump, and pagination all respect the selected list.
- The Upload CSV icon in the sidebar header (visible to users with CRM edit or manage permission) opens a lightweight CSV upload modal that calls the same
/api/crm-contacts/{tenant}/importendpoint. Use it for quick in-app imports; for column mapping and saved templates use the PBX Manager wizard described above.
Worked example: import 500 contacts from a HubSpot export
You exported a contacts.csv from HubSpot and want it in the CRM without creating duplicates, tagged and added to a list for a later campaign.
- Upload (Step 1). Click Import CSV, choose
contacts.csv, leave Delimiter on auto-detect and First row is a header checked. Click Next. - Map fields (Step 2). The server auto-maps obvious columns (
First Name -> first_name,Email -> email, etc.). Fix the rest by hand: map HubSpot’sPhone Numbertophone,Companyyou can ignore here (accounts are separate), and point aSegmentcolumn at the virtual_tagfield so each row’s tags import too. Leave unwanted columns on (Ignore). Click Next. - Review (Step 3). Set On duplicate match to
Update existingand Match keys toemail(unique and stable - safer than name). Under Add to list, choose New list and name itHubSpot Import Jul 2026. Turn Dry run ON for this first pass. - Dry run. Click Import. The wizard reports something like “480 imported, 15 updated, 5 errors”. Download the error CSV from the link, fix those 5 rows (usually a missing/odd email), and note the counts look right.
- Real import. Re-open the wizard, and this time load the mapping you just used - tick Save this mapping as a template on the dry run so it is available - turn Dry run OFF, and click Import for real.
- Verify. Filter the grid by the new
HubSpot Import Jul 2026list; the imported contacts appear with their tags. They are now ready to target from a Campaign.
For automation, the same thing is available as POST /api/crm-contacts/{tenant}/import with a mapping_json body - see the REST API note above.
Best practices
- Populate phone and mobile in E.164 format. Consistent numbers (for example
+14155551234) let inbound and outbound calls match the right contact automatically for caller lookup and activity logging. - Link contacts to an Account. This rolls their activity up to the company level and gives everyone a shared view.
- Use
Visibilitydeliberately. Leave it onAllfor shared customer data; useQueueorOwneronly when a contact should be restricted to a specific team or person. - Dry-run large imports. On the first import of a new source, enable Dry run to catch mapping and duplicate-match problems before writing any records.
- Choose match keys that are unique. For re-imports, match on
emailorexternal_crm_idrather than name to avoid creating duplicates.
Related documentation
- CRM Accounts - link contacts to a company.
- CRM Lists - group contacts for campaigns and segmentation.
- Custom Fields - add tenant-specific fields to the contact form.
- Activities - the timeline of interactions with a contact.
- Message Templates - contact fields fill template variables at send time.