Data import formats
Column mapping and validation rules for the contacts CSV import and the property-units Excel/CSV import.
Avensa has two distinct bulk-import flows: a contacts CSV/Excel import (manual column mapping in the UI) and a property units Excel/CSV import (auto-detected headers, used when adding units to a building). Both run client-side in the app; there is no /api/v1 upload endpoint for either today — use POST /api/v1/contacts / unit creation per-row if you need a programmatic path, or the /api/v1/imports endpoints to track import jobs created some other way.
Contacts import
Where: Contacts → Import (CSV or Excel). Limit: 500 rows per import.
You map each source column to one of these fields yourself in the wizard (nothing is auto-guessed except by matching your header text to the field label):
| Field | Group | Required |
|---|---|---|
first_name | Essentials | required |
last_name | Essentials | |
email | Essentials | |
phone_number | Essentials | |
company_name | Company | |
legal_name | Company | |
job_title | Company | |
city | Real estate | |
budget_min, budget_max | Real estate | |
lead_source | Segmentation | must match a valid lead source value |
lifecycle_stage | Segmentation | must match a valid lifecycle stage value |
lead_rating | Segmentation | must match hot / warm / cold |
tags | Segmentation | comma, semicolon, or pipe separated |
owner_email | Segmentation | resolves to a team member by email |
notes | Segmentation |
A few more fields are accepted by the underlying schema even though the wizard doesn't map them by default: secondary_email, secondary_phone, budget_currency, budget_type, contact_types, gdpr_consent, marketing_opt_in.
Boolean-like cells (gdpr_consent, marketing_opt_in) accept true/false, yes/no, 1/0, and their Bulgarian equivalents (да/не). List cells (tags, contact_types) split on comma, semicolon, or pipe. An unrecognized or empty cell leaves the field unset rather than failing the row.
Download the in-app sample template for a working example — its header row auto-maps on re-import:
First Name, Last Name, Email, Phone, Company, Legal Name, Job Title, City, Budget Min, Budget Max, Lead Source, Lifecycle Stage, Lead Rating, Tags, Owner Email, Notes
Property units import (Excel/CSV)
Where: Properties → New building → Import units. Limit: 500 rows, 10 MB file size.
Unlike contacts, headers are auto-detected — you don't map columns by hand. The parser scans for a header row (skipping title/caption rows above it), matching header text case- and accent-insensitively against known variants in both English and Bulgarian. unit_number and price are the two required columns; import fails with a clear message naming the missing column and its accepted header variants if either is absent.
| Field | Accepted header variants (subset) |
|---|---|
unit_number (required) | unit_number, unit, apartment, apt, #, №, номер, апартамент, обект, имот |
price (required) | price, cost, amount, value, asking price, цена, стойност, цена eur, цена лв |
property_subtype | type, subtype, category, тип, подтип, категория |
transaction_type | transaction_type, sale type, тип сделка, продажба/наем |
status | status, availability, state, статус, наличност |
area_total | area, size, sqm, m2, m², площ, квадратура, кв.м |
bedrooms | bedrooms, beds, br, спални, брой спални |
Notes:
- Currency is always EUR.
- Cyrillic headers and values are supported; CSVs may use
;as the separator (common for Bulgarian Excel exports) and are read as Windows-1251 when needed so Cyrillic isn't mangled. - Numbers accept either
,or.as the decimal separator (localized formats like1 250,50are parsed correctly). - Blank rows are ignored.
Importing programmatically (headless)
POST /api/v1/imports is a separate, headless entry point into the same import pipeline the in-app wizards use — it creates an import_jobs row and starts processing immediately, auto-detecting field mappings when you don't supply them.
POST /api/v1/imports
| Field | Notes |
|---|---|
entity_type | contacts, properties, or deals |
source_type | inline (send records directly) or api_url (server fetches from source_url — requires the host to be allowlisted via IMPORT_API_ALLOWED_HOSTS) |
records | Array of row objects, for source_type: "inline". Capped at 500 records / 2 MB serialized. |
field_mapping | Optional column → field map; omitted fields are auto-detected the same way the wizard does. |
batch_size | 10–500, optional |
skip_duplicates, duplicate_check_fields | Optional dedupe controls |
import_images | Optional, for property imports |
suppress_automations | Optional (defaults to unset, never silently true — always echoed back in the response) |
Track a job and its per-row results:
GET /api/v1/imports
GET /api/v1/imports/{id}
GET /api/v1/imports/{id}/items