UC-007 — Manage Contacts and Lists for Campaigns
| Field | Value |
|---|---|
| ID | UC-007 |
| Goal | Import contacts, create segmented lists, and prepare them for use in campaigns |
| Channel | All |
| Complexity | Intermediate |
| Estimated time | 20 minutes |
| APIs involved | POST/GET/DELETE /api/partner-gateway/v1/contacts, PUT /contacts/{id}, POST/GET /contacts/list, POST /contacts/list/contacts, POST /contacts/upload, POST /contacts/upload/vcard |
Real-world scenarios
- ShopItalia — Customer address book import: Import the export from the company CRM (CSV with 5,000 customers) into the platform to prepare the Black Friday campaign.
- TurismoVeneto — Regional segmentation: Create separate lists for customers in Lombardia, Veneto, and Emilia-Romagna to send geo-targeted promotions on summer stays.
- Studio Legale Ferrara — Phone address book: Import the corporate address book in VCard format to send institutional communications via SMS.
Prerequisites
Before you begin, make sure you have:
- Active API Key → How to get one
- Sufficient credit → Check in the Qlara Dashboard
- CSV or VCard file ready for import
Add "simulation": true in the request body to validate the flow without actually sending messages and without consuming credit.
Contact management flow
The diagram shows the three import paths: manual addition, CSV/Excel upload, or VCard import. Uploaded contacts land in the address book and are then added to the list. All paths converge into verification and campaign use.
Step 1 — Create a contact list
Create an empty list that will serve as a container for the contacts.
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": "Clienti Nord Italia",
"description": "Clienti delle regioni Lombardia, Piemonte, Veneto, Emilia-Romagna"
}'
Response — List created
{
"id": 87,
"name": "Clienti Nord Italia",
"description": "Clienti delle regioni Lombardia, Piemonte, Veneto, Emilia-Romagna",
"filters": null,
"companyId": 4618,
"numContact": 0,
"isTest": false,
"isDeleted": false,
"createdAt": "2026-04-09 09:00:04.512+0000",
"updatedAt": "2026-04-09 09:00:04.512+0000"
}
The id field is the identifier you will use to add contacts and associate the list with campaigns.
Step 2a — Add contacts individually
Create a new contact in the address book and associate it with the list.
curl -X POST https://api.qlara.ai/api/partner-gateway/v1/contacts \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"firstName": "Giulia",
"lastName": "Rossi",
"phoneNumbers": ["+393401234567"],
"emailAddresses": ["giulia.rossi@example.it"],
"gender": "F",
"city": "Milano"
}'
Response — Contact created
{
"contacts": [
{
"id": 24501,
"fullName": "Giulia Rossi",
"firstName": "Giulia",
"lastName": "Rossi",
"gender": "F",
"phoneNumbers": ["+393401234567"],
"emailAddresses": ["giulia.rossi@example.it"],
"city": "Milano",
"isValidMobilePhoneNumber": true,
"isValidEmail": true,
"mobilePhoneNumber": "+393401234567",
"isTest": false,
"createdAt": "2026-04-09 09:01:12.284+0000"
}
],
"errors": []
}
Associate the contact with the list:
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 '{
"contactIds": [24501],
"listIds": [87]
}'
The response lists the IDs of the associations created:
[90412]
You can pass multiple contactIds and multiple listIds in a single request to associate N contacts with M lists at once.
Step 2b — Bulk import from CSV
For mass imports, upload a CSV or Excel file. The process happens in two phases: the upload, which maps the columns and imports the contacts in a single call, then the addition of the imported contacts to the list.
Expected CSV format
The columns are mapped automatically from the header names, so use the names of the contact fields (such as firstName, lastName, phoneNumber, email):
firstName,lastName,phoneNumber,email
Marco,Bianchi,+393489876543,m.bianchi@example.it
Anna,Verdi,+393331122334,anna.verdi@example.it
Luca,Neri,+393201234567,l.neri@example.it
Phase 1 — Upload and import
Send the file and its name; removeHead=true keeps the header row from being imported as a contact:
curl -X POST "https://api.qlara.ai/api/partner-gateway/v1/contacts/upload?removeHead=true" \
-H "X-Api-Key: YOUR_API_KEY" \
-F "file=@clienti_nord_italia.csv" \
-F "fileName=clienti_nord_italia.csv"
Response — Import completed
{
"numContact": 5230,
"addedContact": 5104,
"updatedContact": 98,
"listId": null,
"listName": null,
"numError": 28
}
addedContact counts the new contacts, updatedContact the existing ones (matched by phone number) updated with the file data, and numError the rows that could not be imported. listId and listName are null because the upload has no destination-list parameter: the contacts land in your address book.
Phase 2 — Add the imported contacts to the list
Find the IDs of the imported contacts with GET /contacts: notListIds=87 returns the contacts that are not in the list yet, up to 1,000 per page. Keep the ones whose phone number is in your file and add them to the list (three IDs shown here):
curl -X GET "https://api.qlara.ai/api/partner-gateway/v1/contacts?notListIds=87&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": [87],
"contactIds": [24502, 24503, 24504]
}'
Response — Contacts added to the list
[90413, 90414, 90415]
Behind the scenes — CSV import process
- Upload and parsing: The file is uploaded and parsed, and its columns are mapped to contact fields from their header names. With
removeHead=truethe header row is not imported as a contact. - Import: In the same call the contacts are saved in the address book (created, or updated as in point 4). They are not added to any list: that is Phase 2.
- Number validation: Numbers are validated in international format. Malformed numbers or those without a prefix are discarded.
- Deduplication: Contacts whose phone number already exists are updated with the file data instead of being inserted again, and are counted in
updatedContact.
Since the mapping is automatic and the import happens in a single call, check the header names and try a small sample file before importing thousands of records.
Step 2c — Import from VCard
To import contacts from a phone address book in .vcf format:
curl -X POST https://api.qlara.ai/api/partner-gateway/v1/contacts/upload/vcard \
-H "X-Api-Key: YOUR_API_KEY" \
-F "file=@rubrica_aziendale.vcf" \
-F "fileName=rubrica_aziendale.vcf"
Response — VCard imported
{
"numContact": 342,
"addedContact": 335,
"updatedContact": 4,
"listId": null,
"listName": null,
"numError": 3
}
As with the CSV, the import happens in this single call and the contacts land in the address book: add them to the list as in Phase 2 of Step 2b.
Where the CSV relies on its header names, VCard contacts use standard fields (FN, TEL, EMAIL, ADR) that are mapped automatically, with no configuration.
Step 3 — Verify the contacts in the list
View the contacts present in the list with pagination.
curl -X GET "https://api.qlara.ai/api/partner-gateway/v1/contacts/list/87/contacts?page=0&limit=10" \
-H "X-Api-Key: YOUR_API_KEY"
Response — Contact listing
{
"data": [
{
"id": 24501,
"fullName": "Giulia Rossi",
"firstName": "Giulia",
"lastName": "Rossi",
"phoneNumbers": ["+393401234567"],
"emailAddresses": ["giulia.rossi@example.it"],
"mobilePhoneNumber": "+393401234567",
"isValidMobilePhoneNumber": true,
"listIds": [87]
},
{
"id": 24502,
"fullName": "Marco Bianchi",
"firstName": "Marco",
"lastName": "Bianchi",
"phoneNumbers": ["+393489876543"],
"emailAddresses": ["m.bianchi@example.it"],
"mobilePhoneNumber": "+393489876543",
"isValidMobilePhoneNumber": true,
"listIds": [87]
}
],
"page": 0,
"limit": 10,
"totalCount": 5542,
"totalPages": 555
}
Step 4 — Use the list in a campaign
Pass the list id in the campaign's contactListIds:
curl -X PUT https://api.qlara.ai/api/partner-gateway/v1/campaigns/1542 \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"smsSender": "ShopItalia",
"smsBody": "Offerta esclusiva per i clienti del Nord Italia! -30% su tutto con codice NORD30.",
"contactListIds": [87]
}'
See UC-006 — Bulk SMS Campaign for the complete campaign sending flow.
Additional operations
Remove contacts from a list
curl -X DELETE https://api.qlara.ai/api/partner-gateway/v1/contacts/list/contacts \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"contactIds": [24501],
"listIds": [87]
}'
true
Search contacts by filter
curl -X GET "https://api.qlara.ai/api/partner-gateway/v1/contacts?search=Rossi&isValid=true&page=0&limit=20" \
-H "X-Api-Key: YOUR_API_KEY"
Quick endpoint reference
| Action | Method | Endpoint |
|---|---|---|
| List contacts | GET | /contacts |
| Create contact | POST | /contacts |
| Update contact | PUT | /contacts/{id} |
| Delete contacts | DELETE | /contacts |
| List of lists | GET | /contacts/list |
| Create list | POST | /contacts/list |
| Add to list | POST | /contacts/list/contacts |
| Remove from list | DELETE | /contacts/list/contacts |
| Contacts in list | GET | /contacts/list/{id}/contacts |
| Upload CSV | POST | /contacts/upload |
| Upload VCard | POST | /contacts/upload/vcard |
Common errors
| Problem | Probable cause | Solution |
|---|---|---|
HTTP 401 | Missing or invalid API Key | Check X-Api-Key header |
accepted: false | Insufficient credit or invalid number | Check credit; verify E.164 format |
HTTP 400 — Invalid CSV format | Malformed CSV or missing required columns | Verify the file has a header row and phone numbers in E.164 format |
HTTP 409 — Duplicate contact | Phone number already exists in the system | Use the existing contact ID or update instead of creating |
| VCard parse error | Unsupported VCard version or missing TEL field | Ensure VCard 3.0/4.0 format with valid phone numbers |
Expected result
| Step | Action | Result |
|---|---|---|
| 1 | POST /contacts/list | List created with id |
| 2a | POST /contacts + POST /contacts/list/contacts | Contact created and associated with list |
| 2b | POST /contacts/upload + POST /contacts/list/contacts | 5,202 contacts imported from CSV (5,104 new, 98 updated) and added to the list |
| 2c | POST /contacts/upload/vcard + POST /contacts/list/contacts | 339 contacts imported from VCard and added to the list |
| 3 | GET /contacts/list/{id}/contacts | Paginated listing of contacts in the list |
| 4 | PUT /campaigns/{id} with contactListIds | List associated with campaign |
Next steps
- UC-006 — Bulk SMS Campaign: Use the newly created lists to launch campaigns
- Contacts and Lists Guide: Deep dive into filters, pagination, and advanced management
- Export Guide: Export contacts for external analysis