Contacts
Contacts are the people in your SMBcrm account, including leads and customers, along with their details, tags, custom fields, notes, and tasks.
Base URL: https://services.smbcrm.com · Version header: v3 ·
Scopes: contacts.readonly (read), contacts.write (create/update/delete), and
campaigns.readonly (list campaigns). See Scopes.
Create a contact
Section titled “Create a contact”locationId is the only required field. Send any subset of the others.
| Field | Type | Description |
|---|---|---|
locationId |
string | Required. The location to create the contact in. |
firstName |
string | First name. |
lastName |
string | Last name. |
name |
string | Full name. |
email |
string | Email address. |
phone |
string | Phone number, for example +15125550142. |
gender |
string | Gender. |
address1 |
string | Street address. |
city |
string | City. |
state |
string | State. |
postalCode |
string | Postal code. |
country |
string | Country code in ISO 3166-1 alpha-2 format, for example US. |
website |
string | Website URL. |
timezone |
string | Timezone. |
dateOfBirth |
string | Birth date. Accepted formats: YYYY/MM/DD, MM/DD/YYYY, YYYY-MM-DD, MM-DD-YYYY, YYYY.MM.DD, MM.DD.YYYY, YYYY_MM_DD, MM_DD_YYYY. |
companyName |
string | Company name. |
assignedTo |
string | ID of the user the contact is assigned to. See Users. |
source |
string | Where the contact came from. |
tags |
array of strings | Tags to assign to the contact. |
customFields |
array of objects | Custom field values. See Custom field values. |
dnd |
boolean | Turns Do Not Disturb on or off for the contact. |
dndSettings |
object | Do Not Disturb settings for each channel. See Do Not Disturb. |
inboundDndSettings |
object | Inbound Do Not Disturb setting. See Do Not Disturb. |
curl -X POST https://services.smbcrm.com/contacts/ \ -H "Authorization: Bearer <token>" \ -H "Version: v3" \ -H "Content-Type: application/json" \ -d '{ "locationId": "<location_id>", "firstName": "Jordan", "lastName": "Lee", "email": "[email protected]", "phone": "+15125550142", "tags": ["website-lead"], "source": "public-api", "customFields": [ { "id": "<field_id>", "fieldValue": "Referral" } ] }'{ "contact": { "id": "<contact_id>", "locationId": "<location_id>", "name": "Jordan Lee", "firstName": "Jordan", "lastName": "Lee", "phone": "+15125550142", "source": "public-api", "tags": ["website-lead"], "customFields": [{ "id": "<field_id>", "value": "Referral" }], "dateAdded": "2026-07-08T15:04:00.000Z", "dateUpdated": "2026-07-08T15:04:00.000Z" }}Custom field values
Section titled “Custom field values”customFields is an array. Identify each field with its id or its key and put the value
in fieldValue. Find field IDs and keys in
Custom Fields, Values & Tags.
{ "customFields": [ { "id": "<field_id>", "fieldValue": "Referral" }, { "key": "<field_key>", "fieldValue": ["email", "sms"] } ]}The type of fieldValue depends on the type of the custom field:
| Custom field type | fieldValue |
|---|---|
| Text, large text, single select, radio | A string. |
| Numeric, monetary | A number. |
| Checkbox, multi select | An array of strings. |
| File upload | An object that maps a file UUID to the file’s metadata and download URL. |
field_value is deprecated. Use fieldValue. The same shape applies when you create,
upsert, and update a contact. Responses return each custom field as an object with id and
value, so you send fieldValue and read value.
Do Not Disturb
Section titled “Do Not Disturb”Create, upsert, and update accept three Do Not Disturb inputs. Send dnd: true to turn Do
Not Disturb on for the contact. For per-channel control, send dndSettings: an object keyed
by channel, using any of call, email, sms, whatsApp, gmb, and fb. Each channel
takes these fields:
| Field | Type | Description |
|---|---|---|
status |
string | Required. active, inactive, or permanent. |
message |
string | Custom message to store with the setting. |
code |
string | Do Not Disturb code or reason. |
inboundDndSettings.all sets the inbound setting for all channels. It takes a required
status (active or inactive) and an optional message.
{ "dndSettings": { "sms": { "status": "active", "message": "Opted out" }, "email": { "status": "inactive" } }}Contact responses return the current dndSettings.
Upsert a contact
Section titled “Upsert a contact”The request takes the same fields as create plus
createNewIfDuplicateAllowed. If one contact matches the email and a different contact
matches the phone, the contact that matches the first field in your configured order is
updated and the second field is ignored.
tags replaces the contact’s entire tag list. To add or remove individual tags, use the
tag endpoints.
| Field | Type | Description |
|---|---|---|
createNewIfDuplicateAllowed |
boolean | Default false. When true and your account allows duplicate contacts, a new contact is created right away without a duplicate check. When true and your account doesn’t allow duplicates, the flag is ignored. When false or omitted, the normal upsert applies. |
curl -X POST https://services.smbcrm.com/contacts/upsert \ -H "Authorization: Bearer <token>" \ -H "Version: v3" \ -H "Content-Type: application/json" \ -d '{ "locationId": "<location_id>", "email": "[email protected]", "firstName": "Jordan", "companyName": "Lee Plumbing" }'The response status is 200 whether the call created or updated a contact. new is true
when a contact was created and false when an existing one was updated.
{ "new": false, "contact": { "id": "<contact_id>", "locationId": "<location_id>", "firstName": "Jordan", "companyName": "Lee Plumbing" }, "traceId": "<trace_id>"}Retrieve a contact
Section titled “Retrieve a contact”curl https://services.smbcrm.com/contacts/<contact_id> \ -H "Authorization: Bearer <token>" \ -H "Version: v3"{ "contact": { "id": "<contact_id>", "locationId": "<location_id>", "name": "Jordan Lee", "firstName": "Jordan", "lastName": "Lee", "phone": "+15125550142", "source": "public-api", "assignedTo": "<user_id>", "tags": ["website-lead"], "customFields": [{ "id": "<field_id>", "value": "Referral" }], "dateAdded": "2026-07-08T15:04:00.000Z", "dateUpdated": "2026-07-08T15:04:00.000Z" }}Every endpoint that returns a contact uses this shape. A contact can also include
emailLowerCase, type, companyName, address1, city, state, country,
postalCode, website, timezone, dateOfBirth, dnd, dndSettings, lastActivity,
businessId, attributionSource, lastAttributionSource, and visitorId.
Search contacts
Section titled “Search contacts”Send the locationId to search. pageLimit sets how many contacts come back in a page.
curl -X POST https://services.smbcrm.com/contacts/search \ -H "Authorization: Bearer <token>" \ -H "Version: v3" \ -H "Content-Type: application/json" \ -d '{ "locationId": "<location_id>", "pageLimit": 20 }'{ "total": 1}Look up a contact by email or phone
Section titled “Look up a contact by email or phone”Send locationId and exactly one of email or phone.
| Parameter | Type | Required | Description |
|---|---|---|---|
locationId |
string | Yes | The location to search. |
email |
string | One of email or phone |
Exact email address. Matching is case-insensitive. |
phone |
string | One of email or phone |
Exact phone number in E.164 format. Encode the + as %2B. |
limit |
integer | No | Contacts per page. The default and the maximum are 20. |
nextCursor |
string | No | The nextCursor value from the previous page. |
-H "Authorization: Bearer <token>" \ -H "Version: v3"{ "contacts": [ { "id": "<contact_id>", "locationId": "<location_id>", "firstName": "Jordan", "lastName": "Lee", "phone": "+15125550142" } ]}contacts is an empty array when nothing matches. When a page is full, the response also
includes a nextCursor. Send it as nextCursor on the next request to get the following
page. The last page can come back with an empty contacts array.
To check for an existing match before creating a contact:
| Parameter | Type | Required | Description |
|---|---|---|---|
locationId |
string | Yes | The location to check. |
email |
string | No | Email address, URL-encoded. [email protected] becomes test%2Babc%40gmail.com. |
number |
string | No | Phone number, URL-encoded. +15125550142 becomes %2B15125550142. The parameter is number, not phone. |
When Allow Duplicate Contact is off in your settings, the search uses the global unique
identifier. When it is on, the endpoint matches on email first and then on number.
curl "https://services.smbcrm.com/contacts/search/duplicate?locationId=<location_id>&[email protected]" \ -H "Authorization: Bearer <token>" \ -H "Version: v3"curl "https://services.smbcrm.com/contacts/search/duplicate?locationId=<location_id>&number=%2B15125550142" \ -H "Authorization: Bearer <token>" \ -H "Version: v3"Update & delete
Section titled “Update & delete”The request takes the same fields as create, except locationId,
gender, and companyName. Send only the fields you want to change.
curl -X PUT https://services.smbcrm.com/contacts/<contact_id> \ -H "Authorization: Bearer <token>" \ -H "Version: v3" \ -H "Content-Type: application/json" \ -d '{ "firstName": "Jordan", "city": "Austin", "state": "TX" }'{ "succeeded": true, "contact": { "id": "<contact_id>", "locationId": "<location_id>", "firstName": "Jordan", "city": "Austin", "state": "TX" }}curl -X DELETE https://services.smbcrm.com/contacts/<contact_id> \ -H "Authorization: Bearer <token>" \ -H "Version: v3"{ "succeeded": true }curl -X POST https://services.smbcrm.com/contacts/<contact_id>/tags \ -H "Authorization: Bearer <token>" \ -H "Version: v3" \ -H "Content-Type: application/json" \ -d '{ "tags": ["vip", "webinar-2026"] }'The response lists the contact’s tags after the call.
{ "tags": ["website-lead", "vip", "webinar-2026"] }curl -X DELETE https://services.smbcrm.com/contacts/<contact_id>/tags \ -H "Authorization: Bearer <token>" \ -H "Version: v3" \ -H "Content-Type: application/json" \ -d '{ "tags": ["webinar-2026"] }'{ "tags": ["website-lead", "vip"] }Update tags on many contacts
Section titled “Update tags on many contacts”Set type in the path to add or remove.
| Field | Type | Required | Description |
|---|---|---|---|
locationId |
string | Yes | The location the contacts belong to. |
contacts |
array of strings | Yes | IDs of the contacts to update. |
tags |
array of strings | Yes | Tags to add or remove. |
removeAllTags |
boolean | No | When true, removes every tag from the contacts. Only works with the remove type. |
curl -X POST https://services.smbcrm.com/contacts/bulk/tags/update/add \ -H "Authorization: Bearer <token>" \ -H "Version: v3" \ -H "Content-Type: application/json" \ -d '{ "locationId": "<location_id>", "contacts": ["<contact_id>", "<contact_id_2>"], "tags": ["vip"] }'responses has one entry for each contact in the request, and errorCount counts the
entries that failed.
{ "succeeded": true, "errorCount": 0, "responses": [ { "contactId": "<contact_id>", "message": "Tags updated", "type": "success" }, { "contactId": "<contact_id_2>", "message": "Tags updated", "type": "success" } ]}Notes & tasks
Section titled “Notes & tasks”To create a note, body is required. You can also send userId (the author), title,
color (a hex color code), and pinned.
curl https://services.smbcrm.com/contacts/<contact_id>/notes \ -H "Authorization: Bearer <token>" \ -H "Version: v3"{ "notes": [ { "id": "<note_id>", "contactId": "<contact_id>", "body": "Called and left a voicemail.", "userId": "<user_id>", "dateAdded": "2026-07-08T15:10:00.000Z" } ]}curl -X POST https://services.smbcrm.com/contacts/<contact_id>/notes \ -H "Authorization: Bearer <token>" \ -H "Version: v3" \ -H "Content-Type: application/json" \ -d '{ "body": "Called and left a voicemail." }'{ "note": { "id": "<note_id>", "contactId": "<contact_id>", "body": "Called and left a voicemail.", "dateAdded": "2026-07-08T15:10:00.000Z" }}curl https://services.smbcrm.com/contacts/<contact_id>/notes/<note_id> \ -H "Authorization: Bearer <token>" \ -H "Version: v3"The response is { "note": { ... } }, the same note object the create call returns.
All fields are optional. Send the ones you want to change.
curl -X PUT https://services.smbcrm.com/contacts/<contact_id>/notes/<note_id> \ -H "Authorization: Bearer <token>" \ -H "Version: v3" \ -H "Content-Type: application/json" \ -d '{ "body": "Updated note", "pinned": true }'The response is { "note": { ... } } with the updated note.
curl -X DELETE https://services.smbcrm.com/contacts/<contact_id>/notes/<note_id> \ -H "Authorization: Bearer <token>" \ -H "Version: v3"{ "succeeded": true }To create a task, title, dueDate (ISO 8601), and completed are required. You can also
send body and assignedTo (a user ID).
curl https://services.smbcrm.com/contacts/<contact_id>/tasks \ -H "Authorization: Bearer <token>" \ -H "Version: v3"{ "tasks": [ { "id": "<task_id>", "contactId": "<contact_id>", "title": "Follow up", "dueDate": "2026-07-15T17:00:00.000Z", "completed": false } ]}curl -X POST https://services.smbcrm.com/contacts/<contact_id>/tasks \ -H "Authorization: Bearer <token>" \ -H "Version: v3" \ -H "Content-Type: application/json" \ -d '{ "title": "Follow up", "dueDate": "2026-07-15T17:00:00.000Z", "completed": false }'{ "task": { "id": "<task_id>", "contactId": "<contact_id>", "title": "Follow up", "dueDate": "2026-07-15T17:00:00.000Z", "completed": false }}curl https://services.smbcrm.com/contacts/<contact_id>/tasks/<task_id> \ -H "Authorization: Bearer <token>" \ -H "Version: v3"The response is { "task": { ... } }, the same task object the create call returns.
All fields are optional: title, body, dueDate, completed, and assignedTo.
curl -X PUT https://services.smbcrm.com/contacts/<contact_id>/tasks/<task_id> \ -H "Authorization: Bearer <token>" \ -H "Version: v3" \ -H "Content-Type: application/json" \ -d '{ "title": "Follow up by phone", "dueDate": "2026-07-16T17:00:00.000Z" }'The response is { "task": { ... } } with the updated task.
completed is required.
curl -X PUT https://services.smbcrm.com/contacts/<contact_id>/tasks/<task_id>/completed \ -H "Authorization: Bearer <token>" \ -H "Version: v3" \ -H "Content-Type: application/json" \ -d '{ "completed": true }'The response is { "task": { ... } } with the updated task.
curl -X DELETE https://services.smbcrm.com/contacts/<contact_id>/tasks/<task_id> \ -H "Authorization: Bearer <token>" \ -H "Version: v3"{ "succeeded": true }Followers
Section titled “Followers”Users can follow a contact. Both calls take a followers array of user IDs. See Users for how to find them.
curl -X POST https://services.smbcrm.com/contacts/<contact_id>/followers \ -H "Authorization: Bearer <token>" \ -H "Version: v3" \ -H "Content-Type: application/json" \ -d '{ "followers": ["<user_id>"] }'followers is the contact’s full list after the call, and followersAdded lists the users
this call added.
{ "followers": ["<user_id>"], "followersAdded": ["<user_id>"]}curl -X DELETE https://services.smbcrm.com/contacts/<contact_id>/followers \ -H "Authorization: Bearer <token>" \ -H "Version: v3" \ -H "Content-Type: application/json" \ -d '{ "followers": ["<user_id>"] }'{ "followers": [], "followersRemoved": ["<user_id>"]}Appointments
Section titled “Appointments”curl https://services.smbcrm.com/contacts/<contact_id>/appointments \ -H "Authorization: Bearer <token>" \ -H "Version: v3"{ "events": [ { "id": "<event_id>", "calendarId": "<calendar_id>", "locationId": "<location_id>", "contactId": "<contact_id>", "title": "Sales Consultation", "appointmentStatus": "confirmed", "assignedUserId": "<user_id>", "startTime": "2026-07-15T20:00:00.000Z", "endTime": "2026-07-15T20:30:00.000Z" } ]}To book, update, or cancel appointments, see Calendars.
Businesses
Section titled “Businesses”| Parameter | Type | Required | Description |
|---|---|---|---|
businessId |
string | Yes | Path parameter. The business ID. |
locationId |
string | Yes | The location the business belongs to. |
limit |
string | No | Records per page. The maximum is 100 and the default is 25. |
skip |
string | No | Number of records to skip. |
query |
string | No | Search text matched against name, email, and phone. |
startAfter |
array | No | Pagination cursor as a comma-separated name,id pair. |
curl "https://services.smbcrm.com/contacts/business/<business_id>?locationId=<location_id>&limit=25" \ -H "Authorization: Bearer <token>" \ -H "Version: v3"{ "contacts": [ { "id": "<contact_id>", "locationId": "<location_id>", "businessId": "<business_id>", "tags": ["website-lead"], "dateAdded": "2026-07-08T15:04:00.000Z" } ], "count": 1}| Field | Type | Required | Description |
|---|---|---|---|
locationId |
string | Yes | The location the contacts belong to. |
ids |
array of strings | Yes | IDs of the contacts to update. The maximum is 50. |
businessId |
string or null | Yes | The business to assign. Send null to remove the contacts’ business association. |
curl -X POST https://services.smbcrm.com/contacts/bulk/business \ -H "Authorization: Bearer <token>" \ -H "Version: v3" \ -H "Content-Type: application/json" \ -d '{ "locationId": "<location_id>", "ids": ["<contact_id>", "<contact_id_2>"], "businessId": "<business_id>" }'{ "success": true, "ids": ["<contact_id>", "<contact_id_2>"]}Automations
Section titled “Automations”Add a contact to one of your account’s workflows or campaigns to trigger follow-up, or remove the contact from one.
Workflows
Section titled “Workflows”See Workflows for how to list the workflow IDs available in your
account. Both calls require a JSON body. eventStartTime (ISO 8601) is the only field and
it’s optional, so send {} when you don’t need it.
curl -X POST https://services.smbcrm.com/contacts/<contact_id>/workflow/<workflow_id> \ -H "Authorization: Bearer <token>" \ -H "Version: v3" \ -H "Content-Type: application/json" \ -d '{ "eventStartTime": "2026-10-15T09:00:00-05:00" }'{ "succeeded": true }curl -X DELETE https://services.smbcrm.com/contacts/<contact_id>/workflow/<workflow_id> \ -H "Authorization: Bearer <token>" \ -H "Version: v3" \ -H "Content-Type: application/json" \ -d '{}'{ "succeeded": true }Campaigns
Section titled “Campaigns”Find campaign IDs with the list call below. Adding a contact to a campaign requires a JSON
body, so send {}.
locationId is required. status filters the list, for example draft.
curl "https://services.smbcrm.com/campaigns/?locationId=<location_id>" \ -H "Authorization: Bearer <token>" \ -H "Version: v3"{ "campaigns": [ { "id": "<campaign_id>", "name": "Spring follow-up", "status": "published", "locationId": "<location_id>" } ]}curl -X POST https://services.smbcrm.com/contacts/<contact_id>/campaigns/<campaign_id> \ -H "Authorization: Bearer <token>" \ -H "Version: v3" \ -H "Content-Type: application/json" \ -d '{}'{ "succeeded": true }curl -X DELETE https://services.smbcrm.com/contacts/<contact_id>/campaigns/<campaign_id> \ -H "Authorization: Bearer <token>" \ -H "Version: v3"{ "succeeded": true }curl -X DELETE https://services.smbcrm.com/contacts/<contact_id>/campaigns/remove-all \ -H "Authorization: Bearer <token>" \ -H "Version: v3"{ "succeeded": true }Related
Section titled “Related”- Custom Fields, Values & Tags. Define the
customFieldsyou send here. - Conversations & Messages. Message a contact.
- Opportunities & Pipelines. Track a contact through a sales pipeline.
- Calendars & Appointments. Book and manage a contact’s appointments.
- Users. Find the user IDs for
assignedToand followers.
