Contacts
Contacts represent the people you call. Each contact is unique within your organization by phone number.
The Contact Object
{
"id": "clxxx123",
"name": "Priya Sharma",
"phoneNumber": "+919876543210",
"language": "hi-IN",
"metadata": {
"city": "Mumbai",
"tier": "premium"
},
"organizationId": "org_1",
"createdAt": "2026-03-01T10:00:00.000Z",
"updatedAt": "2026-03-15T08:30:00.000Z"
}List Contacts
GET /v1/contactsQuery Parameters:
| Parameter | Type | Description |
|---|---|---|
page | integer | Page number (default: 1) |
limit | integer | Items per page (default: 20, max: 100) |
search | string | Search by name or phone number |
Response:
{
"data": [/* Contact objects */],
"total": 1500,
"page": 1,
"limit": 20,
"totalPages": 75
}Get a Contact
GET /v1/contacts/:idResponse: A single Contact object.
Get Contact History
GET /v1/contacts/:id/historyCross-campaign call & intent history for a contact, unified by phone number and scoped to your organization. History is returned newest-first.
Response:
{
"contact": {
"id": "clxxx123",
"name": "Priya Sharma",
"phoneNumber": "+919876543210",
"doNotContact": false,
"doNotContactReason": null,
"doNotContactAt": null
},
"history": [
{
"campaignId": "camp_def456",
"campaignName": "Mumbai Outreach - March",
"useCaseType": "COLLECTIONS",
"callId": "CA...",
"outcome": "Connected",
"status": "COMPLETED",
"attempts": 1,
"durationSeconds": 87,
"callAt": "2026-03-10T09:08:27.000Z",
"scheduledAt": null,
"intentLabel": { "id": "lbl_abc", "name": "Interested in Paying", "color": "#16a34a", "isPositive": true },
"intentUndetermined": false,
"flaggedForReview": false
}
],
"bestTime": {
"label": "10 AM–11 AM (Individual, based on 5 calls)",
"source": "individual",
"basisCount": 5
},
"hasNegativeIntent": false,
"negativeLabels": []
}| Field | Description |
|---|---|
outcome | Connected, No Answer, Failed, Skipped, In Progress, or Pending |
bestTime | Preferred call window — source is individual, demographic, or default; label is null when there's not enough data. See best-time. |
hasNegativeIntent | true if any history entry has a suppress/negative intent (warns against re-engagement) |
negativeLabels | The distinct negative labels found, for display |
contact.doNotContact | true if the contact is suppressed org-wide |
Create a Contact
POST /v1/contactsRequest Body:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Contact's full name |
phoneNumber | string | Yes | E.164 format (e.g., +919876543210) |
language | string | No | Preferred language code (e.g., hi-IN) |
metadata | object | No | Custom key-value pairs |
ageBand | string | No | Demographic — e.g. 26-35 |
gender | string | No | Demographic |
cityTier | string | No | Metro, Tier 1, Tier 2, Rural |
occupation | string | No | Demographic |
incomeBand | string | No | Demographic |
productType | string | No | e.g. loan, insurance |
Demographic fields are optional and used for best-time-to-call clustering. The same fields are accepted by Update a Contact.
Example:
{
"name": "Priya Sharma",
"phoneNumber": "+919876543210",
"language": "hi-IN",
"metadata": { "city": "Mumbai", "tier": "premium" }
}Response: 201 Created with the Contact object.
If a contact with the same phone number already exists in your organization, a 409 Conflict is returned.
Update a Contact
PATCH /v1/contacts/:idPartial update — only include fields you want to change.
Request Body: Any subset of Contact fields (except id, organizationId, createdAt).
Example:
{
"language": "en-IN",
"metadata": { "city": "Delhi", "tier": "standard" }
}Response: The updated Contact object.
Delete a Contact
DELETE /v1/contacts/:idResponse: 200 OK with { "success": true }.
Deleting a contact removes them from all audiences. Past call records are preserved.
Bulk Create Contacts
POST /v1/contacts/bulkCreate or update multiple contacts in one request.
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
contacts | array | Yes | Array of contact objects (max 1,000) |
Contact fields: same as Create a Contact.
Example:
{
"contacts": [
{
"name": "Priya Sharma",
"phoneNumber": "+919876543210",
"language": "hi-IN",
"metadata": { "city": "Mumbai" }
},
{
"name": "Ravi Kumar",
"phoneNumber": "+919123456789",
"language": "en-IN"
}
]
}Response:
{
"created": 2,
"updated": 0,
"failed": 0,
"contacts": [/* created/updated Contact objects */],
"errors": []
}If some contacts fail validation, they're reported in errors with the index and reason. The rest are still created.
Bulk Delete Contacts
POST /v1/contacts/bulk-deleteRequest Body:
{
"contactIds": ["clxxx123", "clxxx456", "clxxx789"]
}Response:
{
"deleted": 3
}Add Contact to Audience
POST /v1/contacts/add-to-audienceRequest Body:
{
"contactIds": ["clxxx123", "clxxx456"],
"audienceId": "aud_abc123"
}Response: 200 OK with updated audience contact count.