curl --request POST \
--url https://api.upliftai.org/v1/campaigns/{campaignId}/contacts \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"contacts": [
{
"externalRef": "ord-48812",
"name": "عائشہ صدیقی",
"phone": "+923001234567",
"attributes": {
"order": "48812",
"amount": "Rs 4,500",
"city": "لاہور"
}
},
{
"externalRef": "ord-47190",
"name": "بلال احمد",
"phone": "03219876543",
"attributes": {
"order": "47190",
"amount": "Rs 12,000"
}
},
{
"externalRef": "ord-48814",
"name": "فرحان قریشی",
"phone": "0300-123"
}
]
}
'{
"results": [
{
"contactId": "evt#ord-48812",
"status": "enrolled"
},
{
"contactId": "evt#ord-47190",
"status": "rearmed"
},
{
"status": "skipped",
"reason": "invalidPhone"
}
],
"summary": {
"enrolled": 1,
"rearmed": 1,
"alreadyPending": 0,
"inFlight": 0,
"skipped": 1
}
}Append contacts to a campaign
The only way to add contacts after launch — the other ways in: Contacts. Only a continuous campaign that is running or paused takes them. Draft, completed, closed and bounded campaigns all 409 — a bounded campaign’s contacts are fixed at the snapshot taken at launch. A bad row is rejected on its own — the rest of the batch still lands, and the response is a 200 either way. Read summary for what was actually accepted and why the rest were excluded. Column naming rules: Special column names.
curl --request POST \
--url https://api.upliftai.org/v1/campaigns/{campaignId}/contacts \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"contacts": [
{
"externalRef": "ord-48812",
"name": "عائشہ صدیقی",
"phone": "+923001234567",
"attributes": {
"order": "48812",
"amount": "Rs 4,500",
"city": "لاہور"
}
},
{
"externalRef": "ord-47190",
"name": "بلال احمد",
"phone": "03219876543",
"attributes": {
"order": "47190",
"amount": "Rs 12,000"
}
},
{
"externalRef": "ord-48814",
"name": "فرحان قریشی",
"phone": "0300-123"
}
]
}
'{
"results": [
{
"contactId": "evt#ord-48812",
"status": "enrolled"
},
{
"contactId": "evt#ord-47190",
"status": "rearmed"
},
{
"status": "skipped",
"reason": "invalidPhone"
}
],
"summary": {
"enrolled": 1,
"rearmed": 1,
"alreadyPending": 0,
"inFlight": 0,
"skipped": 1
}
}Authorizations
Project API key (sk_api_…).
Path Parameters
Body
- Inline rows
- Uploaded file
- Connected sheet
Send exactly one variant — none, or fields from two, is a 400.
Up to 1000 rows per request.
1 - 1000 elementsShow child attributes
Show child attributes
Response
A 200 says the batch was processed, not that every row was accepted — read summary.
One entry per inline row, in the same order. Upload and sheet rows dropped at import appear only in excluded.
Show child attributes
Show child attributes
The results statuses counted up.
Show child attributes
Show child attributes
Upload and sheet appends only: rows the import pipeline dropped before any write.
Show child attributes
Show child attributes
