First Contact Import
Move your existing book of business into Olyron CRM with a guided CSV upload. The importer at /dashboard/import parses your file in the browser, auto-maps columns to CRM fields (including your custom fields), previews the first ten rows, and writes records straight into your tenant. This page covers the supported format, field mapping, where records land, and the programmatic import API.
#What the importer does
The importer lives at /dashboard/import ("Import Data"). You pick an import type, upload a CSV, map columns to fields, review a preview, and run the import. Everything is scoped to your current tenant, so imported records only ever appear in your own workspace.
There are two import types, chosen with the toggle at the top of the page. Each writes to a different table and shows up in a different part of the app:
| Import type | Table written | Where records land |
|---|---|---|
| Leads | crm_leads | Leads / CRM pipeline views |
| Contacts | crm_contacts | Contacts at /dashboard/contacts |
.csv files only. Export your spreadsheet (Excel, Google Sheets, another CRM) to CSV first. The first row must be a header row of column names.#Prepare your CSV
The parser reads the first line as headers, handles quoted values, and understands doubled quotes ("") as an escaped quote inside a field. Values are trimmed and fully blank rows are skipped automatically. Commas are the default delimiter.
Core fields you can map
Each import type exposes a fixed set of core fields. Fields marked required must be mapped, or the import will not start. Rows that are missing a value for a required field are skipped and counted separately.
emailrequired- Contact / lead email. Required for both leads and contacts.
first_namerequired- Given name. Required for both types.
last_namerequired- Family name. Required for both types.
phoneoptional- Phone number, any format (e.g. (555) 123-4567).
companyleads only- Company name. A leads-only core field on the import page.
statusleads only- Lead status such as new. Defaults to new if left blank (database default).
sourceleads only- Lead source such as website or referral; the CSV importer writes it to the lead's source column as entered.
addresscontacts only- Street address for the contact.
#Run an import step by step
- 1Open Import DataGo to /dashboard/import and choose Leads or Contacts with the toggle. Switching types clears the current mapping, preview, and result.
- 2Upload your CSVClick the file picker and select a .csv file. The file is parsed in your browser — nothing is uploaded to a server at this stage.
- 3Review the auto-mappingThe importer matches each CSV header to a field by normalizing names (lowercasing, stripping non-alphanumerics) and looking for exact or partial matches. Adjust any dropdown that guessed wrong, and set unwanted columns to "-- Skip --".
- 4Check the previewThe first 10 rows render in a table so you can confirm the data lines up with your columns. The total row count is shown beneath it.
- 5ImportClick "Import N Records". Records are inserted in batches of 100 directly into crm_leads or crm_contacts, and an import_jobs record tracks progress.
- 6Read the resultA summary shows imported, failed, and skipped counts. Any database errors are listed under "View Errors". The run also appears in Import History (last 10 jobs).
#Custom fields
Any custom fields you have defined for the selected object type are loaded automatically and appear under a "Custom Fields" group in each mapping dropdown. The page shows a note like "3 custom fields will be available for mapping" when custom fields exist.
- Custom-field columns are mapped with a
cf:prefix internally (for examplecf:policy_number). - Mapped custom values are collected into the record's
custom_fieldsJSONB column, not into a dedicated table column. - The programmatic leads API (below) folds a lead's
companyvalue intocustom_fields.company, sincecrm_leadshas no dedicated company column.
#Import history and job records
Every run is recorded in the import_jobs table and the most recent ten are shown in the Import History panel. Each job captures how many records were attempted, how many succeeded, and how many failed.
import_typetext- "leads" or "contacts".
statustext- Progresses from processing to completed (or completed_with_errors when some batches fail).
total_recordsint- Number of records that passed required-field validation and were queued.
processedint- Records successfully inserted.
failedint- Records in batches that hit a database error.
errorsjsonb- Any database error messages captured during the run, or null.
completed_attimestamptz- When the job finished.
#Programmatic import (API)
To load leads without the UI — for example from a script or another system — post a JSON array of leads to /api/v1/import/leads. This endpoint is leads-only and takes JSON, not CSV. It requires an authenticated request that resolves to a tenant (the same auth the app uses).
curl -X POST https://your-workspace.olyron.app/api/v1/import/leads \
-H "Content-Type: application/json" \
--cookie "your-session-cookie" \
-d '{
"leads": [
{
"email": "john@example.com",
"first_name": "John",
"last_name": "Doe",
"phone": "(555) 123-4567",
"company": "Acme Corp",
"status": "new",
"source": "referral",
"custom_fields": { "policy_number": "A-1042" }
}
]
}'Each lead requires email; rows without it are rejected and reported per-index. source (or lead_source) is normalized to a canonical value, company is folded into custom_fields, and the endpoint writes its own import_jobs record. The response reports what happened:
{
"success": true,
"imported": 1,
"failed": 0,
"errors": null,
"data": [ { "id": "…", "email": "john@example.com", "status": "new" } ]
}#Limits and troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Import button blocked with "Required field not mapped" | A required column (email/first/last name) has no mapping | Map every required field before importing |
| Fewer records imported than rows | Rows blank on a required field are skipped | Check the "Skipped" count and fill in missing required values |
| Failed count above zero with errors listed | A batch hit a database error (bad value, constraint) | Open "View Errors", correct the offending rows, re-import only those |
| Duplicate contacts after re-upload | No de-dup on import | De-duplicate the source file; import each record once |
| Custom column has no field to map to | The custom field is not defined yet | Create the custom field first, then re-upload |
For very large books, split the file into batches. The importer processes rows in batches of 100, and the leads API and export endpoint are bounded (the LinkedIn importer, for example, caps a request at 20,000 rows; exports return up to 10,000 rows per call).