osmTalk Docs
Campaigns

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

ColumnFormatNotes
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,Priya

Reference 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

LimitValue
Max leads per upload50,000
Max columns50 (after phone)
Max value length per cell4,000 chars
EncodingUTF-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.csv

JSON

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 code9876543210 is 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.