Blue Reacher
Contacts25 / 46

Contacts

Read and create contacts in a workspace owned by the installer, and manage their tags, notes and Do-Not-Disturb.

Read and create contacts in a workspace owned by the installer, and manage their tags, notes and Do-Not-Disturb.

Every route takes Authorization: Bearer <ACCESS_TOKEN> unless the auth line says otherwise. Ids are numbers. Errors use the shape on the errors page.

RouteScopeWhat it does
GET /v1/contactscontacts.readList contacts the installer can see, with optional filtering and pagination.
GET /v1/contacts/{id}contacts.readFetch a single contact by id.
POST /v1/contactscontacts.writeCreate a contact in a workspace.
PATCH /v1/contacts/{id}contacts.writePartially update a contact.
DELETE /v1/contacts/{id}contacts.writeSoft-delete a contact.
POST /v1/contacts/check-imessagecontacts.readCheck whether a contact, phone number or iMessage email address is on iMessage.
POST /v1/contacts/{id}/tagscontacts.writeAdd one or more tags to a contact.
DELETE /v1/contacts/{id}/tagscontacts.writeRemove one or more tags from a contact.
GET /v1/contacts/{id}/notescontacts.readA contact's notes, oldest first.
POST /v1/contacts/{id}/notescontacts.writeAdd a note to a contact.
DELETE /v1/contacts/{id}/notes/{note_id}contacts.writeDelete one note.
GET /v1/contacts/{id}/dndcontacts.readA contact's Do-Not-Disturb settings.
PATCH /v1/contacts/{id}/dndcontacts.writeChange a contact's Do-Not-Disturb for one direction.

List contacts

GET https://api.bluereacher.com/v1/contacts

Auth: Bearer access token. Scope: contacts.read.

List contacts the installer can see, with optional filtering and pagination.

Returns the contacts in one workspace owned by the authenticated installer. workspace_id is required — listing across all workspaces in a single call is not supported.

Parameters

NameInTypeRequiredDescription
workspace_idquerynumberyesThe workspace to list contacts from. Must belong to the installer.
limitquerynumbernoPage size — integer clamped to [1, 200]; default 50. Out-of-range or non-numeric values are normalised, NOT rejected; the applied bounds are echoed in the response pagination object (limit, max_limit, requested_limit, normalized).
pagequerynumberno1-based page number; default 1. Clamped to >= 1 (page=0 becomes 1 and sets normalized). Rows are ordered by id descending, so with limit 200 and total 450 pages 1–3 return the full set. The applied page is echoed in pagination.page, with total_pages and the raw requested_page.

Request

curl -X GET "https://api.bluereacher.com/v1/contacts?workspace_id=7&limit=50&page=1" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Responses

A 200 reply (OK):

{
  "success": true,
  "data": [
    {
      "id": 1234,
      "first_name": "Ada",
      "last_name": "Lovelace",
      "email": "ada@example.com",
      "phone_number": "+15551234567",
      "company_name": "Analytical Engines Ltd",
      "website": "https://analyticalengines.example.com",
      "linkedin_profile": "https://linkedin.com/in/ada",
      "summary": "Mathematician + first programmer. Interested in early CRM tooling.",
      "details": {
        "source": "newsletter",
        "priority": "high"
      },
      "address": "12 Mayfair St",
      "city": "London",
      "state": "Greater London",
      "country": "United Kingdom",
      "timezone": "Europe/London",
      "custom_fields": {
        "lead_score": 92,
        "owner": "gary"
      },
      "is_verified_sms": true,
      "is_verified_imessage": false,
      "last_contacted": "2026-05-20T11:02:09.000Z",
      "notes": [
        "Spoke at conference 2026-05-15"
      ],
      "tags": [
        "lead",
        "priority"
      ],
      "workspace_id": 7,
      "user_id": 42,
      "created_at": "2026-05-21T09:14:22.000Z",
      "updated_at": "2026-05-21T09:14:22.000Z",
      "deleted_at": null
    }
  ],
  "pagination": {
    "total": 1,
    "page": 1,
    "limit": 50,
    "max_limit": 200,
    "total_pages": 1,
    "requested_page": null,
    "requested_limit": null,
    "normalized": false
  }
}
StatusWhenMessage
200OK
400Missing required parameterMissing required parameter: workspace_id
401Missing or invalid tokenInvalid or expired access token.
403Missing scopeMissing scope(s): contacts.read. This integration was granted: …
404workspace_id is not accessible to this tokenWorkspace not found or not accessible to this token

Get contact

GET https://api.bluereacher.com/v1/contacts/{id}

Auth: Bearer access token. Scope: contacts.read.

Fetch a single contact by id.

Returns the full contact row including tags, address fields, custom fields, and audit timestamps. The contact must be owned by the authenticated installer — otherwise a 404 is returned to avoid leaking IDs.

Parameters

NameInTypeRequiredDescription
idpathnumberyesContact id returned by List contacts or Create contact.

Request

curl -X GET "https://api.bluereacher.com/v1/contacts/1234" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Responses

A 200 reply (OK):

{
  "success": true,
  "data": {
    "id": 1234,
    "first_name": "Ada",
    "last_name": "Lovelace",
    "email": "ada@example.com",
    "phone_number": "+15551234567",
    "company_name": "Analytical Engines Ltd",
    "website": "https://analyticalengines.example.com",
    "linkedin_profile": "https://linkedin.com/in/ada",
    "summary": "Mathematician + first programmer. Interested in early CRM tooling.",
    "details": {
      "source": "newsletter",
      "priority": "high"
    },
    "address": "12 Mayfair St",
    "city": "London",
    "state": "Greater London",
    "country": "United Kingdom",
    "timezone": "Europe/London",
    "custom_fields": {
      "lead_score": 92,
      "owner": "gary"
    },
    "is_verified_sms": true,
    "is_verified_imessage": false,
    "last_contacted": "2026-05-20T11:02:09.000Z",
    "notes": [
      "Spoke at conference 2026-05-15"
    ],
    "tags": [
      "lead",
      "priority"
    ],
    "workspace_id": 7,
    "user_id": 42,
    "created_at": "2026-05-21T09:14:22.000Z",
    "updated_at": "2026-05-21T09:14:22.000Z",
    "deleted_at": null
  }
}
StatusWhenMessage
200OK
404Contact does not exist or belongs to a different installerContact not found
401Missing or invalid tokenInvalid or expired access token.

Response fields

contact: The contact requested. Fields:

FieldTypeDescription
idnumberUnique identifier of the contact. Example: 1234
workspace_idnumberThe workspace this contact lives in. Example: 7
user_idnumberThe installer this contact belongs to. Example: 42
first_namestring, nullableGiven name. Max 50 chars. Example: Ada
last_namestring, nullableFamily name. Max 50 chars. Example: Lovelace
emailstring, nullablePrimary email. Unique within a workspace. Normalized to lowercase. Max 100 chars. Example: ada@example.com
phone_numberstring, nullablePrimary phone number. Unique within a workspace. Max 20 chars. Example: +15551234567
company_namestring, nullableCompany / organization name. Max 100 chars. Example: Analytical Engines Ltd
websitestring, nullablePublic website URL. Max 255 chars. Example: https://analyticalengines.example.com
linkedin_profilestring, nullableLinkedIn profile URL. Max 255 chars. Example: https://linkedin.com/in/ada
summarystring (text), nullableFree-form summary / bio.
detailsobject, nullableLoosely-typed details bag (JSON). Use this for app-specific metadata that doesn't fit a column.
addressstring, nullableStreet address. Max 255 chars.
citystring, nullableCity. Max 100 chars.
statestring, nullableState / region. Max 100 chars.
countrystring, nullableCountry name. Max 100 chars.
timezonestring, nullableIANA timezone (e.g. Europe/London). Max 100 chars.
custom_fieldsobject, nullableWorkspace-defined custom fields (JSON).
tagsarray<string>, nullableUp to 20 short labels.
notesarray<string>, nullableFree-form notes. Accepts a string or an array on write; reads always return an array.
is_verified_smsboolean, nullableExample: false
is_verified_imessageboolean, nullablePhone number has been verified for iMessage. Example: false
last_contactedstring (ISO 8601), nullableWhen the contact last had a message exchange.
created_atstring (ISO 8601)When the contact was first created. Example: 2026-05-21T09:14:22.000Z
updated_atstring (ISO 8601)When the contact was last modified. Example: 2026-05-21T09:14:22.000Z
deleted_atstring (ISO 8601), nullableSet when the contact has been soft-deleted. null for active records.

Create contact

POST https://api.bluereacher.com/v1/contacts

Auth: Bearer access token. Scope: contacts.write.

Create a contact in a workspace.

workspace_id is required and must belong to the installer.

⚠️ At least one of email or phone_number is required. Sending both omitted returns 400 Either email or phone_number is required. The two fields each have their own uniqueness constraint inside a workspace, so a contact is always identifiable by at least one of them.

Every other field is optional — see the response Schema tab for the full row that comes back on success.

Parameters

NameInTypeRequiredDescription
workspace_idbodynumberyesWorkspace to attach the contact to. Must belong to the installer.
first_namebodystringnoGiven name. Max 50 chars.
last_namebodystringnoFamily name. Max 50 chars.
emailbodystringnoConditionally required — at least one of email or phone_number must be provided. Normalized to lowercase. Max 100 chars.
phone_numberbodystringnoConditionally required — at least one of email or phone_number must be provided. Max 20 chars.
company_namebodystringnoCompany / organization. Max 100 chars.
websitebodystringnoPublic website URL. Max 255 chars.
linkedin_profilebodystringnoLinkedIn profile URL. Max 255 chars.
summarybodystring (text)noFree-form summary / bio.
detailsbodyobjectnoLoosely-typed JSON details bag.
addressbodystringnoStreet address. Max 255 chars.
citybodystringnoMax 100 chars.
statebodystringnoMax 100 chars.
countrybodystringnoMax 100 chars.
timezonebodystringnoIANA timezone, e.g. Europe/London.
custom_fieldsbodyobjectnoWorkspace-defined custom fields (JSON).
tagsbodyarray<string>noUp to 20 strings, each max 64 chars.
notesbodystring | array<string>noFree-form notes. Accepts a single string or an array of strings.
is_verified_smsbodybooleanno
is_verified_imessagebodybooleannoPhone has been verified for iMessage.
last_contactedbodystring (ISO 8601)noWhen this contact was last contacted.

Request

curl -X POST "https://api.bluereacher.com/v1/contacts" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
  "workspace_id": 7,
  "first_name": "Ada",
  "last_name": "Lovelace",
  "email": "ada@example.com",
  "phone_number": "+15551234567",
  "company_name": "Analytical Engines Ltd",
  "website": "https://analyticalengines.example.com",
  "linkedin_profile": "https://linkedin.com/in/ada",
  "summary": "Mathematician + first programmer. Interested in early CRM tooling.",
  "details": {
    "source": "newsletter",
    "priority": "high"
  },
  "address": "12 Mayfair St",
  "city": "London",
  "state": "Greater London",
  "country": "United Kingdom",
  "timezone": "Europe/London",
  "custom_fields": {
    "lead_score": 92,
    "owner": "gary"
  },
  "tags": [
    "lead",
    "priority",
    "engineer"
  ],
  "notes": [
    "Spoke at conference 2026-05-15",
    "Wants a quote on the Pro tier"
  ],
  "is_verified_sms": true,
  "is_verified_imessage": false,
  "last_contacted": "2026-05-20T11:02:09.000Z"
}'

Responses

A 201 reply (Created):

{
  "success": true,
  "data": {
    "id": 1234,
    "first_name": "Ada",
    "last_name": "Lovelace",
    "email": "ada@example.com",
    "phone_number": "+15551234567",
    "company_name": "Analytical Engines Ltd",
    "website": "https://analyticalengines.example.com",
    "linkedin_profile": "https://linkedin.com/in/ada",
    "summary": "Mathematician + first programmer. Interested in early CRM tooling.",
    "details": {
      "source": "newsletter",
      "priority": "high"
    },
    "address": "12 Mayfair St",
    "city": "London",
    "state": "Greater London",
    "country": "United Kingdom",
    "timezone": "Europe/London",
    "custom_fields": {
      "lead_score": 92,
      "owner": "gary"
    },
    "is_verified_sms": true,
    "is_verified_imessage": false,
    "last_contacted": "2026-05-20T11:02:09.000Z",
    "notes": [
      "Spoke at conference 2026-05-15"
    ],
    "tags": [
      "lead",
      "priority"
    ],
    "workspace_id": 7,
    "user_id": 42,
    "created_at": "2026-05-21T09:14:22.000Z",
    "updated_at": "2026-05-21T09:14:22.000Z",
    "deleted_at": null
  }
}
StatusWhenMessage
201Created
400Missing required fieldsEither email or phone_number is required
404workspace_id not accessible to this tokenWorkspace not found or not accessible to this token
409Duplicate contact in this workspaceA contact with this email or phone number already exists in this workspace.

Response fields

contact: The newly created contact. Fields:

FieldTypeDescription
idnumberUnique identifier of the contact. Example: 1234
workspace_idnumberThe workspace this contact lives in. Example: 7
user_idnumberThe installer this contact belongs to. Example: 42
first_namestring, nullableGiven name. Max 50 chars. Example: Ada
last_namestring, nullableFamily name. Max 50 chars. Example: Lovelace
emailstring, nullablePrimary email. Unique within a workspace. Normalized to lowercase. Max 100 chars. Example: ada@example.com
phone_numberstring, nullablePrimary phone number. Unique within a workspace. Max 20 chars. Example: +15551234567
company_namestring, nullableCompany / organization name. Max 100 chars. Example: Analytical Engines Ltd
websitestring, nullablePublic website URL. Max 255 chars. Example: https://analyticalengines.example.com
linkedin_profilestring, nullableLinkedIn profile URL. Max 255 chars. Example: https://linkedin.com/in/ada
summarystring (text), nullableFree-form summary / bio.
detailsobject, nullableLoosely-typed details bag (JSON). Use this for app-specific metadata that doesn't fit a column.
addressstring, nullableStreet address. Max 255 chars.
citystring, nullableCity. Max 100 chars.
statestring, nullableState / region. Max 100 chars.
countrystring, nullableCountry name. Max 100 chars.
timezonestring, nullableIANA timezone (e.g. Europe/London). Max 100 chars.
custom_fieldsobject, nullableWorkspace-defined custom fields (JSON).
tagsarray<string>, nullableUp to 20 short labels.
notesarray<string>, nullableFree-form notes. Accepts a string or an array on write; reads always return an array.
is_verified_smsboolean, nullableExample: false
is_verified_imessageboolean, nullablePhone number has been verified for iMessage. Example: false
last_contactedstring (ISO 8601), nullableWhen the contact last had a message exchange.
created_atstring (ISO 8601)When the contact was first created. Example: 2026-05-21T09:14:22.000Z
updated_atstring (ISO 8601)When the contact was last modified. Example: 2026-05-21T09:14:22.000Z
deleted_atstring (ISO 8601), nullableSet when the contact has been soft-deleted. null for active records.

Update contact

PATCH https://api.bluereacher.com/v1/contacts/{id}

Auth: Bearer access token. Scope: contacts.write.

Partially update a contact.

Send any subset of the writable fields. Fields you omit are left untouched. Send an explicit null (or empty string) to clear a field. Moving the contact to a different workspace is allowed, but the new workspace_id must also belong to the installer.

Writable fields: the full set listed below — same fields that Create Contact accepts (except neither email nor phone_number is conditionally required on PATCH, since the contact already has at least one identifier from create-time).

Parameters

NameInTypeRequiredDescription
idpathnumberyesContact id.
workspace_idbodynumbernoMove the contact to a different workspace. Must belong to the installer.
first_namebodystringnoMax 50.
last_namebodystringnoMax 50.
emailbodystringnoNormalized to lowercase. Max 100.
phone_numberbodystringnoMax 20.
company_namebodystringnoMax 100.
addressbodystringnoMax 255.
citybodystringnoMax 100.
statebodystringnoMax 100.
countrybodystringnoMax 100.
tagsbodyarray<string>noReplaces the existing tags. Pass null or [] to clear.
websitebodystringnoPublic website URL. Max 255 chars. Send null to clear.
linkedin_profilebodystringnoLinkedIn profile URL. Max 255 chars. Send null to clear.
summarybodystring (text)noFree-form summary / bio. Send null to clear.
detailsbodyobjectnoLoosely-typed JSON details bag. Send null to clear.
timezonebodystringnoIANA timezone, e.g. Europe/London. Max 100 chars.
custom_fieldsbodyobjectnoWorkspace-defined custom fields (JSON). Send null to clear.
notesbodystring | array<string>noFree-form notes. Accepts a single string or an array of strings.
is_verified_smsbodybooleanno
is_verified_imessagebodybooleannoPhone has been verified for iMessage.
last_contactedbodystring (ISO 8601)noWhen this contact was last contacted.

Request

curl -X PATCH "https://api.bluereacher.com/v1/contacts/1234" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
  "first_name": "Augusta",
  "tags": [
    "lead",
    "priority",
    "engineer"
  ]
}'

Responses

A 200 reply (Updated):

{
  "success": true,
  "data": {
    "id": 1234,
    "first_name": "Augusta",
    "last_name": "Lovelace",
    "email": "ada@example.com",
    "phone_number": "+15551234567",
    "company_name": "Analytical Engines Ltd",
    "website": "https://analyticalengines.example.com",
    "linkedin_profile": "https://linkedin.com/in/ada",
    "summary": "Mathematician + first programmer. Interested in early CRM tooling.",
    "details": {
      "source": "newsletter",
      "priority": "high"
    },
    "address": "12 Mayfair St",
    "city": "London",
    "state": "Greater London",
    "country": "United Kingdom",
    "timezone": "Europe/London",
    "custom_fields": {
      "lead_score": 92,
      "owner": "gary"
    },
    "is_verified_sms": true,
    "is_verified_imessage": false,
    "last_contacted": "2026-05-20T11:02:09.000Z",
    "notes": [
      "Spoke at conference 2026-05-15"
    ],
    "tags": [
      "lead",
      "priority",
      "engineer"
    ],
    "workspace_id": 7,
    "user_id": 42,
    "created_at": "2026-05-21T09:14:22.000Z",
    "updated_at": "2026-05-21T09:14:22.000Z",
    "deleted_at": null
  }
}
StatusWhenMessage
200Updated
400No editable fields providedNo editable fields provided.
404Contact does not exist or is not owned by the installerContact not found
409New email or phone collides with another contact in the same workspaceAnother contact with this email or phone number already exists in this workspace.

Response fields

contact: The updated contact. Fields:

FieldTypeDescription
idnumberUnique identifier of the contact. Example: 1234
workspace_idnumberThe workspace this contact lives in. Example: 7
user_idnumberThe installer this contact belongs to. Example: 42
first_namestring, nullableGiven name. Max 50 chars. Example: Ada
last_namestring, nullableFamily name. Max 50 chars. Example: Lovelace
emailstring, nullablePrimary email. Unique within a workspace. Normalized to lowercase. Max 100 chars. Example: ada@example.com
phone_numberstring, nullablePrimary phone number. Unique within a workspace. Max 20 chars. Example: +15551234567
company_namestring, nullableCompany / organization name. Max 100 chars. Example: Analytical Engines Ltd
websitestring, nullablePublic website URL. Max 255 chars. Example: https://analyticalengines.example.com
linkedin_profilestring, nullableLinkedIn profile URL. Max 255 chars. Example: https://linkedin.com/in/ada
summarystring (text), nullableFree-form summary / bio.
detailsobject, nullableLoosely-typed details bag (JSON). Use this for app-specific metadata that doesn't fit a column.
addressstring, nullableStreet address. Max 255 chars.
citystring, nullableCity. Max 100 chars.
statestring, nullableState / region. Max 100 chars.
countrystring, nullableCountry name. Max 100 chars.
timezonestring, nullableIANA timezone (e.g. Europe/London). Max 100 chars.
custom_fieldsobject, nullableWorkspace-defined custom fields (JSON).
tagsarray<string>, nullableUp to 20 short labels.
notesarray<string>, nullableFree-form notes. Accepts a string or an array on write; reads always return an array.
is_verified_smsboolean, nullableExample: false
is_verified_imessageboolean, nullablePhone number has been verified for iMessage. Example: false
last_contactedstring (ISO 8601), nullableWhen the contact last had a message exchange.
created_atstring (ISO 8601)When the contact was first created. Example: 2026-05-21T09:14:22.000Z
updated_atstring (ISO 8601)When the contact was last modified. Example: 2026-05-21T09:14:22.000Z
deleted_atstring (ISO 8601), nullableSet when the contact has been soft-deleted. null for active records.

Delete contact

DELETE https://api.bluereacher.com/v1/contacts/{id}

Auth: Bearer access token. Scope: contacts.write.

Soft-delete a contact.

The contact is soft-deleted — it stops appearing in API results and behaves exactly like one that never existed: a subsequent GET / PATCH / DELETE on its id returns 404 Not Found. Contact Blue Reacher support if you need a contact permanently removed.

Parameters

NameInTypeRequiredDescription
idpathnumberyesContact id.

Request

curl -X DELETE "https://api.bluereacher.com/v1/contacts/1234" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Responses

A 200 reply (Deleted):

{
  "success": true,
  "message": "Contact deleted.",
  "data": {
    "id": 1234,
    "deleted": true
  }
}
StatusWhenMessage
200Deleted
404Contact does not exist or is not owned by the installerContact not found

Check iMessage

POST https://api.bluereacher.com/v1/contacts/check-imessage

Auth: Bearer access token. Scope: contacts.read.

Limits: 10 checks / minute per line

Check whether a contact, phone number or iMessage email address is on iMessage.

Asks Apple, through the workspace's line, whether the handle is registered for iMessage — the same check as Check iMessage on a app.bluereacher.com contact. Give a contact_id (its phone, else its email, is checked) or a phone (with country code) or an email. The answer is recorded, so the app.bluereacher.com and later sends use it.

Needs a line with Advanced Mode on in the workspace (else 400 NO_ADVANCED_MODE_LINE). Apple rate-limits these lookups: each line takes 10 checks a minute (429 RATE_LIMITED beyond that). A handle Apple has not seen recently can take 10–20 s to answer; after 26 s the request is a 504 LINE_TIMEOUT — try again.

silenced and focus_status say whether the recipient has notifications silenced by a Focus, when the line could tell (null otherwise) — see Notify anyway.

Parameters

NameInTypeRequiredDescription
workspace_idbodynumberyesThe workspace whose line does the check. Must belong to the installer.
contact_idbodynumbernoA contact in the workspace. Provide this, phone or email.
phonebodystringnoA phone number with country code. An iMessage email address is accepted here too.
emailbodystringnoAn iMessage email address.

Request

curl -X POST "https://api.bluereacher.com/v1/contacts/check-imessage" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
  "workspace_id": 7,
  "contact_id": 1234
}'

Responses

A 200 reply (OK):

{
  "success": true,
  "data": {
    "handle": "+61412345678",
    "available": true,
    "status": "available",
    "silenced": false,
    "focus_status": null,
    "contact_id": 1234
  }
}
StatusWhenMessage
200OK
400No contact_id, phone or emailProvide contact_id, phone or email.
400Phone without a country codephone must include the country code, e.g. +14155550123
400No line with Advanced Mode on the workspaceNo line with Advanced Mode is connected to this workspace. iMessage checks need a line with Advanced Mode on.
401Missing or invalid tokenInvalid or expired access token.
403Missing scopeMissing scope(s): contacts.read. This integration was granted: …
404Workspace or contact not foundContact not found in this workspace
429More than 10 checks in a minute on this lineToo many checks in the last minute. Try again shortly.
503The line is not connectedThe line isn't connected right now
504The line did not answer in timeThe line didn't answer in time. Try again.

Response fields

check: Apple's answer for the handle. Fields:

FieldTypeDescription
handlestringThe phone or email checked. Example: +61412345678
availablebooleantrue when the handle is on iMessage. Example: true
statusstring, nullableApple's raw answer, when the line reports one. Example: available
silencedboolean, nullabletrue when the recipient has notifications silenced by a Focus; null when unknown.
focus_statusstring, nullableThe recipient's Focus state as Messages reports it; null when unknown.
contact_idnumber, nullableThe contact checked, when contact_id was given.

Add tags

POST https://api.bluereacher.com/v1/contacts/{id}/tags

Auth: Bearer access token. Scope: contacts.write.

Add one or more tags to a contact.

Tags already on the contact are kept; adding one it has is a no-op. Up to 50 tags per call, 100 characters each. Adding a tag can start workflows that trigger on it, as in the dashboard.

AI agent tags. A contact can carry one AI agent tag. Adding a different one answers 409 agent_tag_conflict; send agent_tag_resolution "replace" to swap it or "skip" to keep the old one.

Parameters

NameInTypeRequiredDescription
idpathnumberyesThe contact id.
tagsbodyarray<string>yesTag names.
agent_tag_resolutionbodyenumnoOnly when the request adds an AI agent tag and the contact has a different one.

Request

curl -X POST "https://api.bluereacher.com/v1/contacts/1234/tags" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
  "tags": [
    "vip",
    "demo-booked"
  ]
}'

Responses

A 200 reply (OK — the contact's tags now):

{
  "success": true,
  "message": "Tags added",
  "data": {
    "contact_id": 1234,
    "tags": [
      "lead",
      "vip",
      "demo-booked"
    ]
  }
}
StatusWhenMessage
200OK — the contact's tags now
400No tagstags is required — an array of tag names.
401Missing or invalid tokenInvalid or expired access token.
403Missing scopeMissing scope(s): contacts.write. This integration was granted: …
404Contact does not exist or is not owned by the installer (same response for both)Contact not found or not accessible to this token
409A different AI agent tag is already on the contactThis contact already has a different AI agent tag (a contact can carry one). Send agent_tag_resolution "replace" to swap it, or "skip" to keep it.

Remove tags

DELETE https://api.bluereacher.com/v1/contacts/{id}/tags

Auth: Bearer access token. Scope: contacts.write.

Remove one or more tags from a contact.

Send tags in the JSON body, or as a comma-separated tags query parameter. Tags the contact does not have are ignored.

Parameters

NameInTypeRequiredDescription
idpathnumberyesThe contact id.
tagsbodyarray<string>yesTag names (or ?tags=a,b).

Request

curl -X DELETE "https://api.bluereacher.com/v1/contacts/1234/tags" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
  "tags": [
    "demo-booked"
  ]
}'

Responses

A 200 reply (OK):

{
  "success": true,
  "message": "Tags removed",
  "data": {
    "contact_id": 1234,
    "tags": [
      "lead",
      "vip"
    ]
  }
}
StatusWhenMessage
200OK
401Missing or invalid tokenInvalid or expired access token.
403Missing scopeMissing scope(s): contacts.write. This integration was granted: …
404Contact does not exist or is not owned by the installer (same response for both)Contact not found or not accessible to this token

List notes

GET https://api.bluereacher.com/v1/contacts/{id}/notes

Auth: Bearer access token. Scope: contacts.read.

A contact's notes, oldest first.

Parameters

NameInTypeRequiredDescription
idpathnumberyesThe contact id.

Request

curl -X GET "https://api.bluereacher.com/v1/contacts/1234/notes" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Responses

A 200 reply (OK):

{
  "success": true,
  "data": {
    "contact_id": 1234,
    "notes": [
      {
        "id": "1761555000000",
        "text": "Prefers iMessage after 5pm",
        "created_at": "2026-10-27T08:50:00.000Z"
      }
    ]
  }
}
StatusWhenMessage
200OK
401Missing or invalid tokenInvalid or expired access token.
403Missing scopeMissing scope(s): contacts.read. This integration was granted: …
404Contact does not exist or is not owned by the installer (same response for both)Contact not found or not accessible to this token

Add note

POST https://api.bluereacher.com/v1/contacts/{id}/notes

Auth: Bearer access token. Scope: contacts.write.

Add a note to a contact.

A note is up to 2000 characters. All of a contact's notes together are capped at 5000 characters; a note that would go over is refused with 409 rather than cut.

Parameters

NameInTypeRequiredDescription
idpathnumberyesThe contact id.
textbodystringyesThe note.

Request

curl -X POST "https://api.bluereacher.com/v1/contacts/1234/notes" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
  "text": "Prefers iMessage after 5pm"
}'

Responses

A 201 reply (Created):

{
  "success": true,
  "message": "Note added",
  "data": {
    "id": "1761555000000",
    "text": "Prefers iMessage after 5pm",
    "created_at": "2026-10-27T08:50:00.000Z"
  }
}
StatusWhenMessage
201Created
400No texttext is required.
401Missing or invalid tokenInvalid or expired access token.
403Missing scopeMissing scope(s): contacts.write. This integration was granted: …
404Contact does not exist or is not owned by the installer (same response for both)Contact not found or not accessible to this token
409The contact's notes are fullThis contact's notes are full (5000 characters in all). Delete an older note or shorten this one.

Delete note

DELETE https://api.bluereacher.com/v1/contacts/{id}/notes/{note_id}

Auth: Bearer access token. Scope: contacts.write.

Delete one note.

Parameters

NameInTypeRequiredDescription
idpathnumberyesThe contact id.
note_idpathstringyesThe note id from List notes.

Request

curl -X DELETE "https://api.bluereacher.com/v1/contacts/1234/notes/1761555000000" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Responses

A 200 reply (OK):

{
  "success": true,
  "message": "Note deleted"
}
StatusWhenMessage
200OK
401Missing or invalid tokenInvalid or expired access token.
403Missing scopeMissing scope(s): contacts.write. This integration was granted: …
404Note does not exist or is not owned by the installer (same response for both)Note not found or not accessible to this token

Get DND

GET https://api.bluereacher.com/v1/contacts/{id}/dnd

Auth: Bearer access token. Scope: contacts.read.

A contact's Do-Not-Disturb settings.

Outbound DND stops sends to the contact on those channels — a send answers 409 with reason: "dnd"; inbound DND stops the AI agent and automations from reacting to the contact's messages there. Same settings as the contact panel and the "Set Contact DND" automation action.

Parameters

NameInTypeRequiredDescription
idpathnumberyesThe contact id.

Request

curl -X GET "https://api.bluereacher.com/v1/contacts/1234/dnd" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Responses

A 200 reply (OK):

{
  "success": true,
  "data": {
    "contact_id": 1234,
    "workspace_id": 7,
    "dnd": {
      "outbound": {
        "all": false,
        "channels": []
      },
      "inbound": {
        "all": false,
        "channels": []
      }
    }
  }
}
StatusWhenMessage
200OK
401Missing or invalid tokenInvalid or expired access token.
403Missing scopeMissing scope(s): contacts.read. This integration was granted: …
404Contact does not exist or is not owned by the installer (same response for both)Contact not found or not accessible to this token

Set DND

PATCH https://api.bluereacher.com/v1/contacts/{id}/dnd

Auth: Bearer access token. Scope: contacts.write.

Change a contact's Do-Not-Disturb for one direction.

One call changes one direction. enable_all / disable_all set or clear DND on every channel; enable_specific adds the named channels (and narrows an "all channels" DND to just those); disable_specific removes them. Automations that trigger on Contact Updated run when the settings actually change, as in the dashboard. The response is the contact's full DND afterwards.

Parameters

NameInTypeRequiredDescription
idpathnumberyesThe contact id.
directionbodyenumyesWhich direction to change.
statusbodyenumyesWhat to do.
channelsbodyarray<string>no

Request

curl -X PATCH "https://api.bluereacher.com/v1/contacts/1234/dnd" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
  "direction": "outbound",
  "status": "enable_specific",
  "channels": []
}'

Responses

A 200 reply (OK — the contact's DND now):

{
  "success": true,
  "message": "Contact DND updated",
  "data": {
    "contact_id": 1234,
    "workspace_id": 7,
    "dnd": {
      "outbound": {
        "all": false,
        "channels": []
      },
      "inbound": {
        "all": false,
        "channels": []
      }
    }
  }
}
StatusWhenMessage
200OK — the contact's DND now
400Bad direction, status or channelchannels is required for enable_specific.
401Missing or invalid tokenInvalid or expired access token.
403Missing scopeMissing scope(s): contacts.write. This integration was granted: …
404Contact does not exist or is not owned by the installer (same response for both)Contact not found or not accessible to this token

On this page