Blue Reacher
Contacts, opt-out and the AI assistant17 / 50

Contacts, opt-out and the AI assistant

Search, upsert and update contacts, read and set opt-out state, and control the AI assistant per contact.

List and search contacts

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

Requires read. Test keys work here too: the simulator answers with the live shapes, marked "sandbox": true, and is bound to no workspace, so a sandbox can never read real data.

Query paramMeaning
phoneExact E.164 match
emailSubstring match
tagContacts carrying this tag
searchFree text across name and phone
created_afterISO timestamp
page, per_pagePage/offset pagination, per_page max 100
{
  "contacts": [
    {
      "id": "c9b41d68-3a2f-4e07-b5d1-6f8e2a9c4d17",
      "phone_number": "+16465550119",
      "first_name": "Dana",
      "last_name": "Reyes",
      "email": "dana@northline.co",
      "company": "Northline",
      "tags": ["speed-to-lead"],
      "custom_fields": { "crm_id": "0067Y00000..." },
      "is_imessage": true,
      "opted_out": false,
      "last_contacted_at": "2026-08-30T14:02:11Z",
      "last_message_received_at": "2026-08-30T14:41:53Z",
      "created_at": "2026-08-21T09:12:44Z",
      "updated_at": "2026-08-30T14:41:53Z"
    }
  ],
  "page": 1,
  "per_page": 25,
  "total": 1,
  "has_more": false
}

Create (upsert by phone)

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

Requires write. Creates the contact, or updates the existing one with the same phone_number. 201 on create, 200 on update; the response carries created: true|false. Fields: phone_number (required, E.164), first_name, last_name, email, company, tags, notes, custom_fields.

Update

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

Partial update; custom_fields shallow-merges with the existing map. opted_out: true suppresses all future platform sends to the contact.

Opt-out state

GET  https://api.bluereacher.com/v1/opt-out?phone=+16465550119
POST https://api.bluereacher.com/v1/opt-out

GET returns opted_out, opted_out_at and known_contact for an exact E.164 match. POST with opted_out: true runs the same enforcement path as an inbound STOP reply: the contact is suppressed everywhere and the contact.opted_out webhook fires. Idempotent.

Re-subscribing is deliberately harder: opted_out: false requires confirm_resubscribe: true, never fires a webhook, and should only be used when the contact explicitly asked to hear from you again. Unknown phones return 404 contact_not_found rather than creating a contact.

STOP, UNSTOP and START in inbound messages are honored automatically; you never need to parse them yourself. A recognized re-subscribe phrase from a genuinely opted-out contact emits contact.resubscribed.

AI assistant control

GET  https://api.bluereacher.com/v1/bot?phone=+16465550119
POST https://api.bluereacher.com/v1/bot

Controls whether the platform's AI assistant replies to one contact. GET returns the stored setting plus an effective block computed from the reply engine's own gate chain, so you can distinguish "switched on and replying" from "switched on but something upstream is off".

POST status values:

ValueEffect
inactiveMute the assistant for this contact
snoozePause for snooze_minutes (default 60, max 90 days). The right call when a human takes the conversation over
activeReturn the contact to the assistant's own schedule, clearing any snooze
active_alwaysReply 24/7 to this contact, overriding configured business hours. Requires confirm_always_on: true, because it can reach a real person at 3am

The state is always persisted, but read effective in the response rather than assuming: a workspace-level or account-level gate can mean the assistant still will not reply, and warnings will say so.

On this page