Manage contacts
Add, update or delete a contact from your own system — matched by email or phone, so you never have to store our ids.
One endpoint covers all three operations, because each of them starts the same way: finding the person you mean. Set action to add or delete to say what happens once we have.
add is an upsert. If the email or phone already belongs to a contact, that contact is updated rather than duplicated — so you can send the same record repeatedly without checking whether it exists first.
Body parameters
| Field | Type | Required | Description |
|---|---|---|---|
| action | string | optional | add (default) or delete. |
| string | optional | Used to match an existing contact, case-insensitively. One of email, phone or id is required. | |
| phone | string | optional | Any format — +91 98765 43210, 919876543210 and 9876543210 all resolve to the same contact. |
| id | string | optional | A BigRadar contact id, if you stored one. Takes precedence over email and phone. |
| firstName | string | optional | Given name. |
| lastName | string | optional | Family name. |
| company | string | optional | Company name. |
| status | string | optional | One of active, lead, customer, qualified, unsubscribed, churned. Defaults to active. |
| tags | string[] | optional | Replaces the existing tags outright when present. |
| source | string | optional | Where the contact came from, shown in the dashboard. Defaults to api. |
| attributes | object | optional | Your own custom fields, merged key by key. Optional — see Custom fields. |
| hard | boolean | optional | delete only. Removes the record permanently instead of marking it deleted. |
Add or update
curl -X POST 'https://api.bigradar.io/api/public/v1/contacts' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"action": "add",
"phone": "919876543210",
"email": "priya@example.com",
"firstName": "Priya",
"lastName": "Raman",
"company": "Acme Inc.",
"status": "lead",
"tags": ["trial", "india"]
}'Response · 201 Created
A brand-new contact returns 201. An upsert that landed on an existing one returns 200 with "action": "updated", so you can tell the two apart without a second request.
{
"action": "created",
"contact": {
"id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"email": "priya@example.com",
"phone": "919876543210",
"firstName": "Priya",
"lastName": "Raman",
"status": "lead",
"tags": ["trial", "india"],
"attributes": { "company": "Acme Inc." }
}
}How updates are applied
Only the fields you send are touched. Anything you leave out keeps its current value, so a job that syncs phone numbers will never wipe a name someone typed into the dashboard. To clear a field on purpose, send it as an empty string.
Fields you do send replace what was there. Sending a number that already exists with a different name renames that contact:
{
"action": "updated",
"contact": {
"id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"email": "priya@example.com",
"phone": "+91 98765 43210",
"firstName": "Priya",
"lastName": "Sharma",
"status": "customer",
"tags": ["trial", "india"],
"attributes": { "company": "Acme Inc." }
}
}Two exceptions to that rule. tags are replaced outright, because a merge would leave you no way to remove one. attributes are merged key by key, because other integrations write into the same object and a replace would silently drop everything you did not know about.
Custom fields
The fields above are the same ones the Add contact dialog in your dashboard offers, and you can ignore attributes entirely if that is all you need.
It exists for anything BigRadar has no dedicated field for — a plan name, a renewal date, an internal id. Whatever you put there becomes filterable when you build a segment or pick a campaign audience, exactly like the built-in fields.
curl -X POST 'https://api.bigradar.io/api/public/v1/contacts' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"phone": "919876543210",
"attributes": {
"plan": "gold",
"renewsOn": "2027-01-15",
"accountId": "cus_9f3a21"
}
}'company is stored inside this same object as attributes.company — it simply has its own field because the dashboard has its own input for it. Setting either one has the same effect.
Matching by phone number
Phone numbers are compared on their digits, so formatting never creates a duplicate — +91 98765 43210, 919876543210 and (91) 98765-43210 are one contact. If no exact match is found, we fall back to comparing the last 10 digits, which is what lets a number stored without its country code still match one sent with it.
Delete
By default a delete marks the contact as deleted and keeps its history. Pass "hard": true to remove the record entirely — useful for honouring an erasure request.
curl -X POST 'https://api.bigradar.io/api/public/v1/contacts' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"action": "delete",
"phone": "919876543210"
}'Errors
| Code | Status | Means |
|---|---|---|
| missing_identifier | 400 | No id, email or phone was sent, so there is nothing to match on. |
| invalid_action | 400 | action was something other than add or delete. |
| contact_not_found | 404 | Nothing matched a delete, or the id you sent does not exist. |
| ambiguous_match | 409 | The email and the phone belong to two different contacts. Both ids are named in the message. |
| invalid_status | 400 | status was not one of the six accepted values. |
| contact_limit_reached | 402 | Creating this contact would exceed your plan's contact allowance. |
{
"status": 409,
"code": "ambiguous_match",
"message": "This email belongs to contact a1b2c3d4-… and this phone to contact 9f8e7d6c-….",
"hint": "Send only the field that identifies the person you mean, or send `id` to target one of them directly."
}