UC-020 — Import Contacts from VCard
| Field | Value |
|---|---|
| ID | UC-020 |
| Goal | Import contacts from VCard files and verify the import |
| Channel | All |
| Complexity | Intermediate |
| Estimated time | 10 minutes |
| APIs involved | POST /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
}
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
- Format validation: The parser verifies that the file is a valid VCard (header
BEGIN:VCARD, footerEND:VCARD). - Field extraction: The fields
FN(full name),TEL(phone),EMAILandADR(address) are extracted. TheTELfield is mandatory. - Number normalization: Phone numbers are normalized to E.164 format (e.g.
347 123 4567becomes+393471234567). If the international prefix is missing, the account default is applied. - Deduplication: Contacts are compared by normalized phone number: an existing contact is updated, otherwise a new one is created.
- 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.
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
- Indexing: After import, contacts are indexed by name, phone and email to enable fast searches.
- Segmentation: Imported contacts can be grouped further with smart lists, whose
filtersmatch contact fields such ascityortags(see UC-023).
Expected result
| Step | Action | Result |
|---|---|---|
| 1 | POST /contacts/upload/vcard | File imported, summary with counts |
| 2 | POST /contacts/list/contacts | Imported contacts added to the list |
| 3 | GET /contacts/list/{listId}/contacts | Contacts 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
- UC-007 — Manage Contacts and Lists: Manage and segment imported contacts
- UC-006 — Bulk SMS Campaign: Send a campaign to the newly imported list
- UC-016 — Monitor Credit and Subscription: Check your credit before sending