Skip to main content

UC-020 — Import Contacts from VCard

FieldValue
IDUC-020
GoalImport contacts from VCard files and verify the import
ChannelAll
ComplexityIntermediate
Estimated time10 minutes
APIs involvedPOST /api/partner-gateway/v1/contacts/upload/vcard, GET /api/partner-gateway/v1/contacts, POST /api/partner-gateway/v1/contacts/list/contacts, GET /api/partner-gateway/v1/contacts/list/{listId}/contacts

Real-world scenarios​

  • Migrate from CRM: SalesForce-Pro exports contacts from the old CRM in VCard format and imports them into the Qlara platform to launch SMS campaigns.
  • Import from phone: The sales representative exports the company phone's address book to .vcf and uploads it to create a business contact list.
  • Sync Outlook: The marketing team periodically syncs Outlook contacts exported in VCard to keep mailing lists up to date.

Import flow​

The diagram shows the complete flow: file upload, parsing, saving, addition to the list and verification.

Prerequisites​

  • Active API Key with contact management permissions
  • VCard file (.vcf) in vCard 3.0 or 4.0 format
  • Destination list already created (or create a new one with POST /contacts/list, see Variants)

Step 1 — Upload the VCard file​

Send the .vcf file via multipart form-data, with the file name in fileName.

curl -X POST https://api.qlara.ai/api/partner-gateway/v1/contacts/upload/vcard \
-H "X-Api-Key: YOUR_API_KEY" \
-F "file=@/path/to/contacts-export.vcf" \
-F "fileName=contacts-export.vcf"

Response — Import completed​

{
"numContact": 250,
"addedContact": 230,
"updatedContact": 15,
"listId": null,
"listName": null,
"numError": 5
}
Existing contacts

The import runs in CREATE_UPDATE mode: new contacts are created (addedContact), while contacts that already exist, matched by phone number, are updated with the VCard data (updatedContact). numError counts the entries that could not be imported. listId and listName stay null because the upload has no destination-list parameter: Step 2 adds the contacts to the list.

Behind the scenes — VCard file parsing
  1. Format validation: The parser verifies that the file is a valid VCard (header BEGIN:VCARD, footer END:VCARD).
  2. Field extraction: The fields FN (full name), TEL (phone), EMAIL and ADR (address) are extracted. The TEL field is mandatory.
  3. Number normalization: Phone numbers are normalized to E.164 format (e.g. 347 123 4567 becomes +393471234567). If the international prefix is missing, the account default is applied.
  4. Deduplication: Contacts are compared by normalized phone number: an existing contact is updated, otherwise a new one is created.
  5. Address book only: The imported contacts are saved in the address book without being added to any list; the list assignment is a separate call (Step 2).

Step 2 — Add the imported contacts to the list​

Find the IDs of the imported contacts with GET /contacts: notListIds=4821 returns the contacts that are not in the destination list yet, up to 1,000 per page. Keep the ones from your file (for example by phone number) and add them to the list:

curl -X GET "https://api.qlara.ai/api/partner-gateway/v1/contacts?notListIds=4821&page=0&limit=1000" \
-H "X-Api-Key: YOUR_API_KEY"
curl -X POST https://api.qlara.ai/api/partner-gateway/v1/contacts/list/contacts \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"listIds": [4821],
"contactIds": [72045, 72046, 72047]
}'

Response — Contacts added​

[90311, 90312, 90313]

The response lists the IDs of the associations created.

Whole address book

When the list must contain your entire address book, as in a CRM migration to a new account, send "allContacts": true instead of contactIds: every contact is added, except those listed in excludeIdsAllContacts.

Step 3 — Verify imported contacts​

Retrieve the contact list to verify that the import was successful.

curl -X GET "https://api.qlara.ai/api/partner-gateway/v1/contacts/list/4821/contacts?limit=10" \
-H "X-Api-Key: YOUR_API_KEY"

Response — Contacts in the list​

{
"data": [
{
"id": 72045,
"fullName": "Marco Rossi",
"firstName": "Marco",
"lastName": "Rossi",
"phoneNumbers": ["+393471234567"],
"emailAddresses": ["marco.rossi@email.com"],
"mobilePhoneNumber": "+393471234567",
"isValidMobilePhoneNumber": true,
"createdAt": "2026-04-09 09:00:10.215+0000",
"listIds": [4821]
},
{
"id": 72046,
"fullName": "Giulia Bianchi",
"firstName": "Giulia",
"lastName": "Bianchi",
"phoneNumbers": ["+393489876543"],
"emailAddresses": ["g.bianchi@company.it"],
"mobilePhoneNumber": "+393489876543",
"isValidMobilePhoneNumber": true,
"createdAt": "2026-04-09 09:00:10.231+0000",
"listIds": [4821]
}
],
"page": 0,
"limit": 10,
"totalCount": 245,
"totalPages": 25
}
Behind the scenes — Indexing and search
  1. Indexing: After import, contacts are indexed by name, phone and email to enable fast searches.
  2. Segmentation: Imported contacts can be grouped further with smart lists, whose filters match contact fields such as city or tags (see UC-023).

Expected result​

StepActionResult
1POST /contacts/upload/vcardFile imported, summary with counts
2POST /contacts/list/contactsImported contacts added to the list
3GET /contacts/list/{listId}/contactsContacts visible in the list

Complete end-to-end example​

Scenario SalesForce-Pro: contact migration from the old CRM.

# 1. Import the VCard file
echo "=== VCard Import ==="
IMPORT_RESULT=$(curl -s -X POST https://api.qlara.ai/api/partner-gateway/v1/contacts/upload/vcard \
-H "X-Api-Key: YOUR_API_KEY" \
-F "file=@./crm-export-2026-04.vcf" \
-F "fileName=crm-export-2026-04.vcf")

echo "$IMPORT_RESULT" | jq '{numContact, addedContact, updatedContact, numError}'

# 2. Add the imported contacts to the migration list
# (in a new account, the contacts not yet in the list are the ones just imported)
LIST_ID=4821
CONTACT_IDS=$(curl -s -X GET "https://api.qlara.ai/api/partner-gateway/v1/contacts?notListIds=${LIST_ID}&page=0&limit=1000" \
-H "X-Api-Key: YOUR_API_KEY" | jq -c '[.data[].id]')

curl -s -X POST https://api.qlara.ai/api/partner-gateway/v1/contacts/list/contacts \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d "{\"listIds\": [${LIST_ID}], \"contactIds\": ${CONTACT_IDS}}" | jq 'length'

# 3. Verify imported contacts
echo "=== First 5 imported contacts ==="
curl -s -X GET "https://api.qlara.ai/api/partner-gateway/v1/contacts/list/${LIST_ID}/contacts?limit=5" \
-H "X-Api-Key: YOUR_API_KEY" | jq '.data[] | {fullName, mobilePhoneNumber, listIds}'

Variants​

Import with existing contact update​

If you want to update the data of already existing contacts (e.g. new email address), upload the updated file: the import always runs in CREATE_UPDATE mode, so contacts matched by phone number are updated.

curl -X POST https://api.qlara.ai/api/partner-gateway/v1/contacts/upload/vcard \
-H "X-Api-Key: YOUR_API_KEY" \
-F "file=@./contacts-updated.vcf" \
-F "fileName=contacts-updated.vcf"

Import into a new list​

The upload does not create lists: create the new list first, then import the file and add the contacts to the list id returned by the first call, as in Step 2:

curl -X POST https://api.qlara.ai/api/partner-gateway/v1/contacts/list \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"name": "Outlook Sync Aprile 2026"
}'

curl -X POST https://api.qlara.ai/api/partner-gateway/v1/contacts/upload/vcard \
-H "X-Api-Key: YOUR_API_KEY" \
-F "file=@./outlook-contacts.vcf" \
-F "fileName=outlook-contacts.vcf"

Common errors​

400 Bad Request — Invalid VCard file​

{
"status": "fail",
"data": {
"file": "Invalid VCard format. Expected BEGIN:VCARD header."
}
}

Solution: Verify that the file is a valid VCard (v3.0 or v4.0). Open the file with a text editor and check that it starts with BEGIN:VCARD.

413 Payload Too Large — File too large​

{
"status": "fail",
"data": {
"file": "File size exceeds maximum allowed (10 MB)"
}
}

Solution: Split the VCard file into smaller files (max 10 MB each) and import them separately.

Next steps​

References​