Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/0m1n3m/contacts-db/llms.txt

Use this file to discover all available pages before exploring further.

Bulk import lets you onboard large batches of contacts at once — no manual data entry required. Upload a spreadsheet, map its columns to the Contacts DB fields, preview the first ten rows, and run the import. The importer validates each row, skips duplicates automatically, and reports a summary when it is finished.
The contact_category and relationship_status fields are required for every row. Any row missing either of these values is counted as invalid and skipped.

Supported File Formats

FormatExtensionNotes
CSV.csvComma, semicolon, or tab-delimited
TSV / text.txtTab-delimited plain text
Excel.xlsx, .xlsFirst sheet is used
The maximum file size is 10 MB. For CSV and TSV files, the importer auto-detects the delimiter by counting occurrences of \t, ,, and ; on the first line and picking the one that appears most often.

Import Process

1

Navigate to the import page

Go to /contacts/import. This page is protected by the role:admin,editor middleware — only admins and editors can access it.
2

Upload your file

Choose a .csv, .txt, .xlsx, or .xls file up to 10 MB. After submitting the upload form the server stores the file temporarily and parses it. For CSV and TSV files the delimiter (comma, semicolon, or tab) is detected automatically by scanning the first line. For Excel files the first sheet is read using the Maatwebsite Excel library. UTF-8 BOM characters are stripped from the first header cell automatically.
3

Map columns

The import mapping page (POST /contacts/import/preview) shows a list of all contact fields alongside a dropdown for each one. Select which column from your spreadsheet corresponds to each database field. The system performs auto-mapping before you arrive on this page — see Column Mapping below for the rules.
4

Preview the data

The mapping page displays the first 10 data rows of your file rendered according to the current mapping. Use this to verify that values appear in the correct fields before committing.
5

Run the import

Click Import to submit the mapping form as a POST to /contacts/import/run. The server iterates over all data rows, validates each one, runs deduplication checks, and saves new contacts. The temporary file is deleted afterwards. You are then redirected to the contacts list with a summary flash message.

Column Mapping

On the mapping screen you assign each contact field to a column from your spreadsheet. Fields marked with * are required — every row that lacks a value for these fields will be skipped.
Contact DB fieldLabelRequired
contact_categoryContact category✅ *
relationship_statusRelationship status✅ *
use_for_eventsUse for eventsNo
potential_speakerPotential speakerNo
organisation_nameOrganisation nameNo
first_nameFirst nameNo
last_nameLast nameNo
job_titleJob titleNo
emailsEmails (list)No
phonesPhones (list)No
countryCountry (ISO code)No
organisation_typesOrganisation types (list)No
keywordsKeywords (list)No
relevant_project_programmeRelevant project / programmeNo
expertise_speaking_topicsExpertise / speaking topicsNo
stakeholder_typeStakeholder typeNo
commentCommentNo

Auto-mapping

Before presenting the mapping form, the server normalises every header from your file (lowercased, spaces and slashes replaced with underscores, special characters removed) and attempts to match it to a contact field. If your column header matches a field name exactly, or matches one of the aliases in the table below, the mapping is pre-filled automatically.
Spreadsheet header (normalised)Maps to field
email, e_mailemails
phone, telephone, telphones
organisation, organization, orgorganisation_name
organization_types, org_typesorganisation_types
expertise, speaking_topicsexpertise_speaking_topics
project_programmerelevant_project_programme
You can override any auto-mapped field on the mapping screen.

Multi-Value Columns

The emails, phones, organisation_types, keywords, and expertise_speaking_topics fields store arrays. The importer accepts several cell formats for these columns:
["alice@example.com","alice@work.org"]
The importer tries JSON parsing first. If the cell value starts with [ and decodes to a valid JSON array, each element becomes an array item. Otherwise it looks for ;, then ,, then | as delimiters and splits on the first one it finds. If none are present, the entire cell is treated as a single-element array. Each resulting item is trimmed and blank items are discarded.
For the cleanest round-trip experience — especially when re-importing contacts that were previously exported — keep the JSON array format (["value1","value2"]) in your spreadsheet cells. The exporter always writes this format, so a downloaded CSV can be re-imported without reformatting.

Deduplication

The importer checks each incoming row against existing contacts before inserting. Rows identified as duplicates are skipped and counted in the result summary.

Primary check — email match

If the row contains one or more valid email addresses (validated with FILTER_VALIDATE_EMAIL), the importer queries the contacts table for any existing contact whose emails JSON array contains any of those addresses (case-insensitive). If a match is found, the entire row is treated as a duplicate and skipped.

Fallback check — name and organisation match

If the row has no valid email addresses, the importer falls back to matching on the combination of organisation_name, first_name, and last_name (all compared case-insensitively). If all three values match an existing contact, the row is skipped.
The fallback check only runs when no valid email is present. Rows with no email and no name/organisation data are not deduplicated — they will always be inserted if they pass validation.

Import Result

After the import completes you are redirected to the contacts list (/contacts) with a flash message in the following format:
Import finished. Imported: 42. Skipped invalid: 3. Skipped duplicates: 5.
CounterMeaning
ImportedRows successfully saved as new contacts
Skipped invalidRows missing contact_category or relationship_status, or rows that threw an unexpected error during save
Skipped duplicatesRows that matched an existing contact via email or name/organisation fallback

Exporting Contacts

Export is available to all authenticated users — no special role is required.
1

Select contacts on the list page

Use the row checkboxes in the contacts list at /contacts to select the records you want to export. The toolbar shows the current count: Export selected (CSV) (N). Only admins see the checkboxes on their own; editors and viewers also see checkboxes next to the export button.
2

Download

Click Export selected (CSV). The browser submits a POST to /contacts/export with the selected IDs and immediately streams a CSV file download.
The exported file:
  • Is named contacts-selected-YYYYMMDD-HHmmss.csv
  • Is encoded as UTF-8 with BOM (\xEF\xBB\xBF) so Microsoft Excel opens it without encoding issues
  • Contains all 20 columns: id, contact_category, relationship_status, use_for_events, potential_speaker, organisation_name, first_name, last_name, job_title, emails, phones, country, organisation_types, keywords, relevant_project_programme, expertise_speaking_topics, stakeholder_type, comment, created_at, updated_at
  • Exports use_for_events and potential_speaker as 1 or 0
  • Exports JSON array columns (emails, phones, organisation_types, keywords, expertise_speaking_topics) as JSON strings, for example ["a@b.com","c@d.com"]
Before importing a large file, test the process with a small sample of 5–10 rows. This lets you verify that your column mapping is correct and that deduplication behaves as expected without risking unwanted bulk inserts.

Overview & Data Model

Full reference for every field, type, and access-control rule in the Contacts module.

Managing Contacts

Create, edit, search, and delete contacts individually or in bulk.

Build docs developers (and LLMs) love