API reference / Contacts
Contacts
A contact is one person, with their phone numbers, email, custom field values, lists and tags. You create contacts before you add them to lists for campaigns. You look them up to check their consent and do-not-contact status before you send. Tags, notes, activity history, follow-ups, owners and dispositions for a single contact are on Contact details.
Routes
| Method | Route | Scope | What it does |
|---|---|---|---|
GET |
/contact/public/contacts |
contacts:read |
List contacts, with filters |
GET |
/contact/public/contacts/search |
contacts:read |
Find contacts by phone number or email |
POST |
/contact/public/contacts |
contacts:write |
Create contacts, or update the ones that already exist |
GET |
/contact/public/contacts/{contact_id} |
contacts:read |
Get one contact in full |
PUT |
/contact/public/contacts/{contact_id} |
contacts:write |
Update a contact's field values |
DELETE |
/contact/public/contacts/{contact_id} |
contacts:write |
Delete a contact |
List contacts
Returns a page of contacts. Page with offset and limit, and stop when you've read total_contacts. Pass sort_by when you page, so the order stays the same from page to page.
| Field | Type | Required | Description |
|---|---|---|---|
list_id |
string | No | Only contacts on this list. |
search_term |
string | No | Free-text search across field values, such as a name, phone number or email. |
disposition |
string | No | Only contacts with this disposition id. none returns contacts without one. |
owner |
string | No | Only contacts owned by this user id. |
brand_id |
string | No | Only contacts of this brand. Without it you get every brand. |
sort_by |
string | No | modified_at, created_at, last_activity, last_called_at or first_name. |
sort_order |
string | No | asc or desc. |
limit |
integer | No | Page size. Default 25. |
offset |
integer | No | Number of contacts to skip. Default 0. |
curl "https://api-v2.dropcowboy.com/contact/public/contacts?list_id=3b2f0314-e849-4799-9969-af93349bef75&sort_by=created_at&limit=25&offset=0" \
-H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET"
{
"data": {
"contacts": [
{
"contact_id": "756c1b7d-c27d-4faf-9365-bb83f0cbed66",
"first_name": "Dana",
"last_name": "Reyes",
"email": "dana@example.com",
"main_phone": "+13125550142",
"phone_numbers": ["+13125550142"],
"list_ids": ["3b2f0314-e849-4799-9969-af93349bef75"],
"tags": [
{
"tag_id": "fbd9fdcb-59ac-42ba-991e-3b469b9df791",
"tagged_at": 1790870333466,
"tagged_by": "d8ea4045-3e3c-45e6-b2ba-3917287c378c",
"deleted_at": null,
"deleted_by": null
}
],
"owner": "d8ea4045-3e3c-45e6-b2ba-3917287c378c",
"dnc": false,
"email_dnc": false,
"has_tcpa_consent": true,
"created_at": 1790870333466,
"modified_at": 1790870333466
}
],
"total_contacts": 1,
"next_cursor": null
},
"meta": { "request_id": "35f86685-859f-4a8d-926a-45ec7fba7ddc" }
}
Each contact also carries its standard field values flattened by type, such as company or city, plus disposition, location and activity summaries (call_info, message_info, email_info). The sample leaves those out.
Search contacts
Finds contacts with an exact phone number or email. Use it to look someone up before you create them or send to them. Send the phone number in E.164 format, URL-encoded (%2B13125550142). Emails match without regard to case.
| Field | Type | Required | Description |
|---|---|---|---|
phone |
string | One of phone or email |
Phone number in E.164 format. |
email |
string | One of phone or email |
Email address. |
brand_id |
string | No | Only contacts of this brand. |
limit |
integer | No | Page size. Default 25. |
offset |
integer | No | Number of contacts to skip. Default 0. |
curl "https://api-v2.dropcowboy.com/contact/public/contacts/search?phone=%2B13125550142" \
-H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET"
The response has the same shape as List contacts. No match returns an empty contacts array.
Create contacts
Creates one or more contacts in a single call. You describe your columns once in fields, then send one row per contact in values. A row that matches an existing contact by record_id, email or phone number updates that contact instead, following conflict_mode.
By default this route doesn't send webhooks or start automations. Set fire_webhook_events or fire_automation_events if you want them.
| Field | Type | Required | Description |
|---|---|---|---|
fields |
array | Yes | One mapping per column, such as { "type": "first_name" }. For a custom field use { "type": "custom_field", "field_id": "<custom_field_id>" }. |
values |
array | Yes | One array per contact, with values in the same order as fields. |
add_list_ids |
array | No | List ids to add every contact in this call to. |
add_tag_ids |
array | No | Tag ids to add to every contact in this call. |
conflict_mode |
string | No | How to treat a row that matches an existing contact. append (default) keeps existing values and only fills empty fields. overwrite replaces the values of the fields you send and leaves the rest alone. replace makes the row's values win and keeps existing values only where the row has none. |
owner |
string | No | User id that owns the contacts. |
region |
string | No | Two-letter country code for reading phone numbers that don't start with +. Default US. |
return_counts |
boolean | No | Return totals instead of per-row results. Use it for large batches. |
fire_webhook_events |
boolean | No | Send contact.created, contact.updated and list webhooks. Default false. |
fire_automation_events |
boolean | No | Start automations triggered by these contacts. Default false. |
Common field types: first_name, last_name, email, main_phone, mobile_phone, home_phone, office_phone, other_phone, company, website, address, city, state, zip_code, country, record_id, lead_source, tcpa_consent, tcpa_consent_date and custom_field. Get your custom field ids from List custom fields.
Every row needs a record_id, an email or a phone number. Rows without one are rejected.
curl -X POST "https://api-v2.dropcowboy.com/contact/public/contacts" \
-H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET" \
-H "Content-Type: application/json" \
-d '{
"fields": [
{ "type": "first_name" },
{ "type": "last_name" },
{ "type": "main_phone" },
{ "type": "email" },
{ "type": "custom_field", "field_id": "34f38d24-632d-4a9c-bf89-b9371a722b35" }
],
"values": [
["Dana", "Reyes", "+13125550142", "dana@example.com", "Gold"],
["Sam", "Okafor", "+13125550187", "", "Silver"]
],
"add_list_ids": ["3b2f0314-e849-4799-9969-af93349bef75"],
"conflict_mode": "append"
}'
The response is 201. index is the row's position in values.
{
"data": {
"inserted": [
{ "index": 1, "contact_id": "22b934c0-e7e6-4f07-8608-e2bc91f06e39" }
],
"updated": [
{ "index": 0, "contact_id": "756c1b7d-c27d-4faf-9365-bb83f0cbed66" }
],
"rejected": []
},
"meta": { "request_id": "8e42bc36-efeb-42c1-b99b-41ae9c60aa66" }
}
With return_counts: true, data is { "accepted_count", "rejected_count", "inserted_count", "updated_count" }.
Get a contact
Returns everything about one contact: field values, phone numbers, lists, tags, pinned notes, consent and do-not-contact flags. Read the consent flags here before you choose a channel. Consent explains each one.
curl "https://api-v2.dropcowboy.com/contact/public/contacts/756c1b7d-c27d-4faf-9365-bb83f0cbed66" \
-H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET"
{
"data": {
"status": 200,
"contact": {
"contact_id": "756c1b7d-c27d-4faf-9365-bb83f0cbed66",
"first_name": "Dana",
"last_name": "Reyes",
"email": "dana@example.com",
"main_phone": "+13125550142",
"field_data": [
{
"field_id": "8e42bc36-efeb-42c1-b99b-41ae9c60aa66",
"type": "first_name",
"display_name": "First Name",
"value": "Dana"
},
{
"field_id": "c99a62ba-d867-42e7-8814-c718d2254493",
"type": "main_phone",
"display_name": "Main Phone",
"value": "+13125550142"
}
],
"phone_numbers": ["+13125550142"],
"list_ids": ["3b2f0314-e849-4799-9969-af93349bef75"],
"tags": [],
"notes": [],
"owner": "d8ea4045-3e3c-45e6-b2ba-3917287c378c",
"dnc": false,
"email_dnc": false,
"has_tcpa_consent": true,
"tcpa_opted_out_at": null,
"has_sms_consent": true,
"sms_opted_out_at": null,
"has_email_consent": false,
"email_opted_out_at": null,
"created_at": 1790870333466
}
},
"meta": { "request_id": "c99a62ba-d867-42e7-8814-c718d2254493" }
}
The contact is in data.contact. If no contact has that id, the response is still 200 and data.contact is null, so check for it.
field_data holds every field value with its field_id. You need those ids to update a contact. notes holds only the notes pinned to the contact.
Update a contact
Changes a contact's field values. Send a contact object with the field_data entries you want to change. Each entry needs the field_id from Get a contact and the new value. To add a field the contact doesn't have yet, send a new UUID as its field_id.
Top-level fields such as first_name don't change the contact's values. Change them in field_data. Use the dedicated routes for lists, tags, the owner and the disposition.
| Field | Type | Required | Description |
|---|---|---|---|
contact.field_data |
array | Yes | Entries of { "field_id", "type", "value" }. |
curl -X PUT "https://api-v2.dropcowboy.com/contact/public/contacts/756c1b7d-c27d-4faf-9365-bb83f0cbed66" \
-H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET" \
-H "Content-Type: application/json" \
-d '{
"contact": {
"field_data": [
{ "field_id": "8e42bc36-efeb-42c1-b99b-41ae9c60aa66", "type": "first_name", "value": "Danielle" }
]
}
}'
The response is the updated contact as stored, with its full field_data.
{
"data": {
"contact_id": "756c1b7d-c27d-4faf-9365-bb83f0cbed66",
"field_data": [
{
"field_id": "8e42bc36-efeb-42c1-b99b-41ae9c60aa66",
"type": "first_name",
"display_name": "First Name",
"value": "Danielle"
}
],
"phone_numbers": ["+13125550142"],
"list_ids": ["3b2f0314-e849-4799-9969-af93349bef75"],
"modified_at": 1790870396012
},
"meta": { "request_id": "34f38d24-632d-4a9c-bf89-b9371a722b35" }
}
The sample is shortened. The full response includes every stored field of the contact.
Delete a contact
Deletes a contact. It no longer appears when you list, search or get contacts.
curl -X DELETE "https://api-v2.dropcowboy.com/contact/public/contacts/756c1b7d-c27d-4faf-9365-bb83f0cbed66" \
-H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET"
The response is the deleted contact with deleted_at and deleted_by set.
{
"data": {
"contact_id": "756c1b7d-c27d-4faf-9365-bb83f0cbed66",
"deleted_at": 1790870421733,
"deleted_by": "d8ea4045-3e3c-45e6-b2ba-3917287c378c"
},
"meta": { "request_id": "9782bc36-7d8f-413c-9a21-228562d0b10c" }
}
The sample is shortened.
Errors
On these routes, the type URL in an error doesn't tell errors apart. Branch on status.
| Status | When | What to do |
|---|---|---|
400 |
Search without phone or email. |
Send one of them. |
400 |
Create without fields and values, or the batch can't be read. |
Check that every row has one value per entry in fields. |
400 |
Update fails validation. | Check each field_data value against its type, for example a valid email for email. |
402 |
Create while your subscription is inactive. | See Payment required. |
403 |
Update changes the owner of a contact someone else owns. | Only the current owner or a manager can reassign it. |
404 |
Update or delete a contact that doesn't exist or that you can't see. | Check the contact_id. Contacts owned by others may be hidden from your user. |
A row in rejected isn't an error for the whole call. Read its reasons, fix the row and send it again on its own.
For everything else, see Responses, errors and limits.
While Drop Cowboy provides tools to support compliance efforts, customers remain solely responsible for obtaining proper consent, maintaining opt-out lists, and complying with all federal and state telemarketing regulations. Consult with your legal counsel to ensure your specific use case and consent mechanisms comply with applicable laws.