Skip to content

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.

POST/contacts/

Create a contact in your SMBcrm account/location.

scope contacts.writeauth Location token or PIT

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.
Terminal window
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": "jordan@example.com",
"phone": "+15125550142",
"tags": ["website-lead"],
"source": "public-api",
"customFields": [
{ "id": "<field_id>", "fieldValue": "Referral" }
]
}'
201 Created
{
"contact": {
"id": "<contact_id>",
"locationId": "<location_id>",
"name": "Jordan Lee",
"firstName": "Jordan",
"lastName": "Lee",
"email": "jordan@example.com",
"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"
}
}

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.

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.

POST/contacts/upsert

Create a contact, or update the existing one that matches your duplicate-contact setting.

scope contacts.writeauth Location token or PIT

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.
Terminal window
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": "jordan@example.com",
"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.

200 OK
{
"new": false,
"contact": {
"id": "<contact_id>",
"locationId": "<location_id>",
"firstName": "Jordan",
"email": "jordan@example.com",
"companyName": "Lee Plumbing"
},
"traceId": "<trace_id>"
}
GET/contacts/{contactId}

Fetch a single contact by ID.

scope contacts.readonlyauth Location token or PIT
Terminal window
curl https://services.smbcrm.com/contacts/<contact_id> \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{
"contact": {
"id": "<contact_id>",
"locationId": "<location_id>",
"name": "Jordan Lee",
"firstName": "Jordan",
"lastName": "Lee",
"email": "jordan@example.com",
"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.

POST/contacts/search

Search the contacts in a location with advanced filters. Use it to list contacts.

scope contacts.readonlyauth Location token or PIT

Send the locationId to search. pageLimit sets how many contacts come back in a page.

Terminal window
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
}'
200 OK
{
"contacts": [{ "id": "<contact_id>", "firstName": "Jordan", "email": "jordan@example.com" }],
"total": 1
}
GET/contacts/lookup

Find contacts by exact email or phone number, including a contact's additional emails and phone numbers.

scope contacts.readonlyauth Location token or PIT

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.
Terminal window
curl "https://services.smbcrm.com/contacts/lookup?locationId=<location_id>&email=jordan@example.com" \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{
"contacts": [
{
"id": "<contact_id>",
"locationId": "<location_id>",
"firstName": "Jordan",
"lastName": "Lee",
"email": "jordan@example.com",
"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:

GET/contacts/search/duplicate

Check whether a contact already exists, matching by phone number or email.

scope contacts.readonlyauth Location token or PIT
Parameter Type Required Description
locationId string Yes The location to check.
email string No Email address, URL-encoded. test+abc@gmail.com 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.

Terminal window
curl "https://services.smbcrm.com/contacts/search/duplicate?locationId=<location_id>&email=jordan@example.com" \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
Terminal window
curl "https://services.smbcrm.com/contacts/search/duplicate?locationId=<location_id>&number=%2B15125550142" \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
PUT/contacts/{contactId}

Update fields on an existing contact.

scope contacts.writeauth Location token or PIT

The request takes the same fields as create, except locationId, gender, and companyName. Send only the fields you want to change.

Terminal window
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" }'
200 OK
{
"succeeded": true,
"contact": {
"id": "<contact_id>",
"locationId": "<location_id>",
"firstName": "Jordan",
"city": "Austin",
"state": "TX"
}
}
DELETE/contacts/{contactId}

Permanently delete a contact.

scope contacts.writeauth Location token or PIT
Terminal window
curl -X DELETE https://services.smbcrm.com/contacts/<contact_id> \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{ "succeeded": true }
POST/contacts/{contactId}/tags

Add one or more tags to a contact.

scope contacts.writeauth Location token or PIT
Terminal window
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.

201 Created
{ "tags": ["website-lead", "vip", "webinar-2026"] }
DELETE/contacts/{contactId}/tags

Remove one or more tags from a contact.

scope contacts.writeauth Location token or PIT
Terminal window
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"] }'
200 OK
{ "tags": ["website-lead", "vip"] }
POST/contacts/bulk/tags/update/{type}

Add tags to, or remove tags from, many contacts in one request.

scope contacts.writeauth Location token or PIT

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.
Terminal window
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.

201 Created
{
"succeeded": true,
"errorCount": 0,
"responses": [
{ "contactId": "<contact_id>", "message": "Tags updated", "type": "success" },
{ "contactId": "<contact_id_2>", "message": "Tags updated", "type": "success" }
]
}

To create a note, body is required. You can also send userId (the author), title, color (a hex color code), and pinned.

GET/contacts/{contactId}/notes

List notes on a contact.

scope contacts.readonlyauth Location token or PIT
Terminal window
curl https://services.smbcrm.com/contacts/<contact_id>/notes \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{
"notes": [
{
"id": "<note_id>",
"contactId": "<contact_id>",
"body": "Called and left a voicemail.",
"userId": "<user_id>",
"dateAdded": "2026-07-08T15:10:00.000Z"
}
]
}
POST/contacts/{contactId}/notes

Add a note to a contact.

scope contacts.writeauth Location token or PIT
Terminal window
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." }'
201 Created
{
"note": {
"id": "<note_id>",
"contactId": "<contact_id>",
"body": "Called and left a voicemail.",
"dateAdded": "2026-07-08T15:10:00.000Z"
}
}
GET/contacts/{contactId}/notes/{id}

Fetch a single note by ID.

scope contacts.readonlyauth Location token or PIT
Terminal window
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.

PUT/contacts/{contactId}/notes/{id}

Update a note.

scope contacts.writeauth Location token or PIT

All fields are optional. Send the ones you want to change.

Terminal window
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.

DELETE/contacts/{contactId}/notes/{id}

Delete a note.

scope contacts.writeauth Location token or PIT
Terminal window
curl -X DELETE https://services.smbcrm.com/contacts/<contact_id>/notes/<note_id> \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{ "succeeded": true }

To create a task, title, dueDate (ISO 8601), and completed are required. You can also send body and assignedTo (a user ID).

GET/contacts/{contactId}/tasks

List tasks on a contact.

scope contacts.readonlyauth Location token or PIT
Terminal window
curl https://services.smbcrm.com/contacts/<contact_id>/tasks \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{
"tasks": [
{
"id": "<task_id>",
"contactId": "<contact_id>",
"title": "Follow up",
"dueDate": "2026-07-15T17:00:00.000Z",
"completed": false
}
]
}
POST/contacts/{contactId}/tasks

Create a task for a contact.

scope contacts.writeauth Location token or PIT
Terminal window
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 }'
201 Created
{
"task": {
"id": "<task_id>",
"contactId": "<contact_id>",
"title": "Follow up",
"dueDate": "2026-07-15T17:00:00.000Z",
"completed": false
}
}
GET/contacts/{contactId}/tasks/{taskId}

Fetch a single task by ID.

scope contacts.readonlyauth Location token or PIT
Terminal window
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.

PUT/contacts/{contactId}/tasks/{taskId}

Update a task.

scope contacts.writeauth Location token or PIT

All fields are optional: title, body, dueDate, completed, and assignedTo.

Terminal window
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.

PUT/contacts/{contactId}/tasks/{taskId}/completed

Mark a task complete or incomplete.

scope contacts.writeauth Location token or PIT

completed is required.

Terminal window
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.

DELETE/contacts/{contactId}/tasks/{taskId}

Delete a task.

scope contacts.writeauth Location token or PIT
Terminal window
curl -X DELETE https://services.smbcrm.com/contacts/<contact_id>/tasks/<task_id> \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{ "succeeded": true }

Users can follow a contact. Both calls take a followers array of user IDs. See Users for how to find them.

POST/contacts/{contactId}/followers

Add users as followers of a contact.

scope contacts.writeauth Location token or PIT
Terminal window
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.

201 Created
{
"followers": ["<user_id>"],
"followersAdded": ["<user_id>"]
}
DELETE/contacts/{contactId}/followers

Remove users as followers of a contact.

scope contacts.writeauth Location token or PIT
Terminal window
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>"] }'
200 OK
{
"followers": [],
"followersRemoved": ["<user_id>"]
}
GET/contacts/{contactId}/appointments

List the appointments booked for a contact.

scope contacts.readonlyauth Location token or PIT
Terminal window
curl https://services.smbcrm.com/contacts/<contact_id>/appointments \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{
"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.

GET/contacts/business/{businessId}

List the contacts associated with a business.

scope contacts.readonlyauth Location token or PIT
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.
Terminal window
curl "https://services.smbcrm.com/contacts/business/<business_id>?locationId=<location_id>&limit=25" \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{
"contacts": [
{
"id": "<contact_id>",
"locationId": "<location_id>",
"email": "jordan@example.com",
"businessId": "<business_id>",
"tags": ["website-lead"],
"dateAdded": "2026-07-08T15:04:00.000Z"
}
],
"count": 1
}
POST/contacts/bulk/business

Add many contacts to a business, or remove their business association.

scope contacts.writeauth Location token or PIT
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.
Terminal window
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>"
}'
200 OK
{
"success": true,
"ids": ["<contact_id>", "<contact_id_2>"]
}

Add a contact to one of your account’s workflows or campaigns to trigger follow-up, or remove the contact from one.

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.

POST/contacts/{contactId}/workflow/{workflowId}

Add a contact to a workflow.

scope contacts.writeauth Location token or PIT
Terminal window
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" }'
200 OK
{ "succeeded": true }
DELETE/contacts/{contactId}/workflow/{workflowId}

Remove a contact from a workflow.

scope contacts.writeauth Location token or PIT
Terminal window
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 '{}'
200 OK
{ "succeeded": true }

Find campaign IDs with the list call below. Adding a contact to a campaign requires a JSON body, so send {}.

GET/campaigns/

List the campaigns in a location.

scope campaigns.readonlyauth Location token or PIT

locationId is required. status filters the list, for example draft.

Terminal window
curl "https://services.smbcrm.com/campaigns/?locationId=<location_id>" \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{
"campaigns": [
{
"id": "<campaign_id>",
"name": "Spring follow-up",
"status": "published",
"locationId": "<location_id>"
}
]
}
POST/contacts/{contactId}/campaigns/{campaignId}

Add a contact to a campaign.

scope contacts.writeauth Location token or PIT
Terminal window
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 '{}'
201 Created
{ "succeeded": true }
DELETE/contacts/{contactId}/campaigns/{campaignId}

Remove a contact from a campaign.

scope contacts.writeauth Location token or PIT
Terminal window
curl -X DELETE https://services.smbcrm.com/contacts/<contact_id>/campaigns/<campaign_id> \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{ "succeeded": true }
DELETE/contacts/{contactId}/campaigns/remove-all

Remove a contact from every campaign it is enrolled in.

scope contacts.writeauth Location token or PIT
Terminal window
curl -X DELETE https://services.smbcrm.com/contacts/<contact_id>/campaigns/remove-all \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{ "succeeded": true }