CSV format
How to structure a contact list for campaign upload.
When you upload leads to a campaign, you can either POST a CSV string directly or send a JSON array. CSV is recommended for spreadsheet exports.
Required column
| Column | Format | Notes |
|---|---|---|
phone (or phone_number, number, phoneNumber) | E.164 (+919876543210) | One required. Case-insensitive header match. |
Optional columns
Every other column becomes a per-call variable, referenceable in the agent's system prompt and welcome message via {{column_name}}.
Column names can include:
- letters, digits, underscores, hyphens, dots, and single inline spaces
- Examples:
first_name,Client Name,tracking-id,order.id - 1–64 characters
- not collide with the phone column
So a CSV header like phone,Client Name,company produces {{Client Name}} and {{company}} as variables in your agent's prompt. Leading/trailing/consecutive whitespace is rejected.
Example
phone,first_name,company,renewal_date,policy_type,premium,sales_rep
+919876543210,Arjun,Acme Industries,2026-05-28,Health,12450,Priya
+919876543211,Meera,BlueLeaf Ltd,2026-06-02,Auto,8900,Raj
+919876543212,Vivek,Cool Foods,2026-06-15,Term Life,15600,PriyaReference in the agent's system prompt:
You are {{sales_rep}}'s assistant. You're calling {{first_name}} from
{{company}} about their {{policy_type}} policy ending {{renewal_date}}.
The new premium is ₹{{premium}}.Resulting first call:
"Hi Arjun, I'm Priya's assistant. I'm calling from Acme Industries about your Health policy ending May 28. The new premium is ₹12,450 — is that something I can confirm with you?"
Limits
| Limit | Value |
|---|---|
| Max leads per upload | 50,000 |
| Max columns | 50 (after phone) |
| Max value length per cell | 4,000 chars |
| Encoding | UTF-8 |
Upload
CSV (text/csv)
curl -X POST https://api.osmtalk.com/api/campaigns/{id}/leads \
-H "Authorization: Bearer $OSMTALK_API_KEY" \
-H "Content-Type: text/csv" \
--data-binary @leads.csvJSON
curl -X POST https://api.osmtalk.com/api/campaigns/{id}/leads \
-H "Authorization: Bearer $OSMTALK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"leads": [
{ "phoneNumber": "+919876543210", "variables": { "first_name": "Arjun", "company": "Acme" } },
{ "phoneNumber": "+919876543211", "variables": { "first_name": "Meera", "company": "BlueLeaf" } }
]
}'CSV string inside JSON
curl ... -H "Content-Type: application/json" -d '{
"csv": "phone,first_name\\n+919876543210,Arjun\\n+919876543211,Meera"
}'Response
{
"inserted": 2,
"csvErrors": [
"Row 4: invalid phone \"98765\" (must be E.164 like +919876543210)"
]
}Bad rows are skipped — the rest are inserted. Re-upload to add more leads to the same campaign.
Validation tips
- Always include the
+and country code —9876543210is rejected (TRAI E.164 requirement). - No commas inside cells unless wrapped in
"quotes". Standard CSV escaping rules apply. - Test with 5 leads first before uploading 50,000. The response will show any column-format issues.
- De-duplication happens inside the upload — if the same phone number appears twice, only the first occurrence is kept.
- Duplicates across uploads are NOT de-duplicated. If you upload the same CSV twice you'll get 2x the calls.
DNC interaction
Uploaded leads that match your DNC list at dial time are auto-marked dnc_blocked — they don't consume an attempt and they don't get dialed.
DNC is checked at dial time, not upload time, so a number added to DNC after upload will still be blocked when its turn comes.