Contacts CSV import API

contacts_v1

low9 fields · 1 required · 2 validatedPack · CRM

Import this template via API. Import CRM contacts from CSV. Account-linked, email-validated, decision-maker flag, multilingual headers.

30-second curl

curl -X POST https://api.adaptivmapr.com/v1/uploads \
  -H "Authorization: Bearer $ADAPTIVMAPR_API_KEY" \
  -F "template=contacts_v1" \
  -F "file=@your_data.csv"

At a glance

Pack
CRM
FHIR resource
Risk level
low
Fields
9 (1 required, 2 validated)

Why it exists

Why this template?

The Contacts template is people at named accounts — the post-qualification population that leads convert into. Each row carries an id, a foreign key account_id, identity fields (first_name, last_name), contact details (email, phone), a job title, a decision-maker boolean, and a last_contacted_at timestamp. Sales-ops teams use this template after a leads import to materialise the contacts-at-accounts relationship, after a CRM migration to reconstruct the org chart, and before a campaign to refresh the decision-maker flag. The is_decision_maker field is a boolean rather than an enum because nuanced authority (economic buyer vs technical buyer vs influencer) belongs in a separate model — the canonical row tracks the binary: does this person sign or not.

account_id is not required because contacts can exist before their account is created — but most downstream systems eventually want the link. last_contacted_at parses across formats; null means the relationship is dormant. Title hints cover DE, FR, IT, ES so a multilingual CRM export does not escalate to the LLM.

Migration scenarios & common foreign headers

Migration scenarios for the Contacts template: CRM migrations (Salesforce → HubSpot, Pipedrive → Close), enrichment runs that refresh titles after a quarterly outreach campaign, post-acquisition imports where the acquiring team needs the acquired company's contact graph in place, and ABM list uploads that target specific personas at named accounts. Foreign headers we see routinely: "Account ID / Konto / Cuenta / Vorname / Prénom / Nombre / Nachname / Nom / Apellido / Email / Telefon / Téléphone / Teléfono / Titel / Titre / Titolo / Cargo / Job Title / Entscheider / Décideur / Decisor / Last Contacted / Letzter Kontakt". The cascade picks up the multilingual job-title vocabulary at zero cost — title is the single most-localised field in CRM data, and the heuristic layer absorbs it without escalating.

Canonical columns

Schema

The canonical column set, with the type each row carries, whether it is required, the field-level validators that fire on commit, and the multilingual header hints the cascade resolves against.

ColumnTypeRequiredValidatorsHints
idstringyes
account_idstringkonto · compte · account · cuenta
first_namestringvorname · prenom · prénom · nombre · given name
last_namestringnachname · nom · cognome · apellido · surname
emailemailemaile-mail · mail · correo
phonephonephonetelefon · téléphone · telefono · phone · mobile
titlestringtitel · titre · titolo · cargo · job title
is_decision_makerbooleanentscheider · décideur · decisor
last_contacted_atdate

The cascade

How AdaptivMapr maps your headers to this template

Five layers run in order, cheapest first. Layer 1 (Statistics) auto-accepts headers that have been mapped the same way across past uploads. Layer 2 (Heuristic) compares your header to the column name, the optional label, and every registered hint (DE / FR / IT / EN / ES) after a Unicode-and-punctuation-normalising pass. Layer 3 (Fuzzy) catches typos and reordered words. Layer 4 (Semantic) uses cached embeddings to catch the long tail of paraphrases. Layer 5 (LLM) only fires on genuinely ambiguous columns, constrained to the template’s allowed column set so it cannot invent a field. When a layer auto-accepts, the lower-cost layers below it never run — that is the cost lever.

REST · POST /v1/uploads

Pass the template_id; the cascade picks up the rest.

curl -X POST https://api.adaptivmapr.com/v1/uploads \
  -H "Authorization: Bearer $ADAPTIVMAPR_API_KEY" \
  -F "template=contacts_v1" \
  -F "file=@your_data.csv"

The canonical template definition is read-only at GET /v1/templates/contacts_v1.

MCP · Cursor / Claude Desktop

Drop AdaptivMapr into your IDE. Schema-only calls need no key and draw only the small flat per-map fee.

// In Cursor or Claude Desktop with the AdaptivMapr MCP server installed:
adaptivmapr.match_headers({
  template: "contacts_v1",
  headers: ["id", "account_id", "first_name", "last_name"]
})
MCP install instructions →

Questions

FAQ — Contacts CSV import

Why is is_decision_maker a boolean instead of a role enum?

Sales-process role taxonomies (champion, blocker, influencer) are team-specific and shift across deal stages. The canonical row tracks the binary so cross-team reports compose.

Can a contact belong to multiple accounts?

Each row is one membership. Multi-account contacts get one row per account — the contact id stays stable, the account_id varies.

How do I handle contacts who left the company?

Add an `is_active` flag via a fork, or maintain a separate departed-contacts table. The canonical template assumes current.

Does the template validate phone numbers as E.164?

The phone validator checks shape (digits, plus sign, separators) but does not enforce strict E.164. A downstream libphonenumber pass normalises to E.164 cleanly because the cascade guarantees a parseable shape.

Keep exploring

Browse other templates in the CRM pack