Contacts
The address book holds persons and companies, per entity. Contacts are linked to signature requests, registered mails and tasks (contactId), and their activity lists those resources.
- GET
/v1/contactsList contacts - POST
/v1/contactsCreate a contact - GET
/v1/contacts/duplicatesFind possible duplicates - GET
/v1/contacts/tagsList contact tags - GET
/v1/contacts/company-lookupSearch the French business registry - GET
/v1/contacts/exportExport contacts (CSV) - POST
/v1/contacts/importImport contacts (CSV) - GET
/v1/contacts/{id}Retrieve a contact - PATCH
/v1/contacts/{id}Update a contact - DELETE
/v1/contacts/{id}Delete a contact - POST
/v1/contacts/{id}/mergeMerge two contacts - GET
/v1/contacts/{id}/activityList the activity of a contact
Visibility
Section titled “Visibility”- Shared contacts are visible to everyone with
contacts.readin the entity. - Private contacts (
isPrivate: true) are visible to their creator only, and are never sent to webhooks. - Editing requires
contacts.writeon your own contacts,contacts.manageon the others. Import, export and merge requirecontacts.manage.
Create a contact
Section titled “Create a contact”curl -s -X POST "$MLT_API_URL/v1/contacts" \ -H "Authorization: Bearer $MLT_TOKEN" -H "Content-Type: application/json" \ -d '{ "entityId": "0192f3a1-7c2e-7b4d-9a61-200000000002", "kind": "person", "civility": "mrs", "firstName": "Marie", "lastName": "Durand", "email": "marie.durand@example.fr", "mobilePhone": "06 12 34 56 78", "address": { "line1": "12 rue Vendôme", "postalCode": "69006", "city": "Lyon", "country": "FR" }, "tags": ["locataire"], "externalRef": "CRM-00421" }'const contact = await fetch(`${process.env.MLT_API_URL}/v1/contacts`, { method: 'POST', headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ entityId, kind: 'person', civility: 'mrs', firstName: 'Marie', lastName: 'Durand', email: 'marie.durand@example.fr', mobilePhone: '06 12 34 56 78', address: { line1: '12 rue Vendôme', postalCode: '69006', city: 'Lyon', country: 'FR' }, tags: ['locataire'], externalRef: 'CRM-00421', }),}).then((r) => r.json());console.log(contact.mobilePhone); // "+33612345678"contact = requests.post(f"{api}/v1/contacts", headers=headers, json={ "entityId": entity_id, "kind": "person", "civility": "mrs", "firstName": "Marie", "lastName": "Durand", "email": "marie.durand@example.fr", "mobilePhone": "06 12 34 56 78", "address": {"line1": "12 rue Vendôme", "postalCode": "69006", "city": "Lyon", "country": "FR"}, "tags": ["locataire"], "externalRef": "CRM-00421",}).json()print(contact["mobilePhone"]) # "+33612345678"$contact = json_decode((string) $http->post("$api/v1/contacts", [ 'headers' => $headers, 'json' => [ 'entityId' => $entityId, 'kind' => 'person', 'civility' => 'mrs', 'firstName' => 'Marie', 'lastName' => 'Durand', 'email' => 'marie.durand@example.fr', 'mobilePhone' => '06 12 34 56 78', 'address' => ['line1' => '12 rue Vendôme', 'postalCode' => '69006', 'city' => 'Lyon', 'country' => 'FR'], 'tags' => ['locataire'], 'externalRef' => 'CRM-00421', ],])->getBody(), true);- Phone numbers are normalized to E.164; national French numbers are accepted. SIREN (9 digits) and SIRET (14 digits) are checked (Luhn).
- A person can be linked to a company contact of the same entity with
companyId(“works at”). externalRefstores your own identifier (e.g. the CRM id): use it to find the contact again.
Sync from another system
Section titled “Sync from another system”- Look for a match with
GET /v1/contacts/duplicates?entityId=…&email=…(alsosiret,firstName/lastName,companyName). Each match lists itsreasons(email,siret,name). - Update with
PATCH /v1/contacts/{id}(omitted fields unchanged,nullclears), or create it. - Listen to
contact.createdandcontact.updatedwebhooks to sync in the other direction.
GET /v1/contacts supports full-text search (q over names, company, emails, phones, SIREN/SIRET and tags, accent and case insensitive), filters (kind, tag, visibility, companyId, createdByMe) and pagination.
Import and export CSV
Section titled “Import and export CSV”POST /v1/contacts/import takes a CSV (file) and a mapping (data) of target fields to CSV column names:
{ "entityId": "0192f3a1-7c2e-7b4d-9a61-200000000002", "mapping": { "firstName": "Prénom", "lastName": "Nom", "email": "Email", "mobilePhone": "Mobile", "companyName": "Société" }, "onDuplicate": "skip", "tags": ["import-octobre"], "dryRun": true}Run it with dryRun: true first: the report lists the invalid rows (errors) and the rows matching existing contacts (duplicates) without creating anything. GET /v1/contacts/export returns the contacts matching the same filters as the list, as CSV.
Merge and delete
Section titled “Merge and delete”POST /v1/contacts/{id}/mergewith{ "sourceId": "…", "takeFromSource": ["mobilePhone"] }merges the source into{id}and deletes the source.DELETE /v1/contacts/{id}deletes permanently (right to erasure). Links to other resources are removed.