Skip to main content
POST

Opt a contact out

Method: POST | Endpoint: /v1/contacts/{contact_id}/opt-out Description: Record that this person doesn’t want your messages, the same as when they reply STOP. Use it to bring opt-outs from your CRM or another channel into iBubbl.
An opt-out can’t be undone. There is no opt-in endpoint, and the dashboard can’t reverse it either. From then on every send to this number answers 422 contact_opted_out, from the API, the dashboard and automations alike. It belongs to the phone number: deleting the contact and creating it again doesn’t clear it. Only call this for a person who asked not to be messaged.
Authentication: API key in the Authorization header: Authorization: Bearer ib_pk_<64 hex>. Create keys in the dashboard under Settings → API access.

Request Body

None. The path parameter contact_id is the contact’s ID (a UUID).

What happens

  • opted_out becomes true and opted_out_at is set.
  • The first opt-out for this person fires a contact.opted_out webhook with source: "api".
  • It’s safe to call twice. If the person has already opted out, in any way and under any form of their number (a STOP reply, a rep, GoHighLevel Do Not Disturb, or an earlier call), you get 200 with the contact as it is, and no second webhook fires.
  • Messages already accepted can still go out. New sends are refused from now on, but a message accepted earlier and still waiting (held for sending hours, or queued) is not withdrawn. Cancel it in the dashboard if it must not be sent. See Suppression & Opt-Outs.
To stop messaging someone only for now, block them instead: a block can be undone.

Responses

200 OK The contact, with opted_out: true. On a repeat call, opted_out_at is the time of the first opt-out.
401 Unauthorized
Other message values: Authorization Bearer token required, API key required (use Authorization: Bearer ib_pk_…), Invalid API key format, Customer account not found. 403 Forbidden
Your iBubbl account is suspended or cancelled (message is then Account is cancelled). Every API-key endpoint returns this. 404 Not Found
Also returned for a malformed ID, a deleted contact, and a contact that belongs to another account. Nothing was recorded.

Authorizations

Authorization
string
header
required

Bearer API key. Format: Authorization: Bearer ib_pk_<64 hex> (70 characters). Generate keys from Dashboard → Settings → API Access.

Path Parameters

contact_id
string
required

Response

The contact, now opted out.

id
string
required

Unique contact identifier (UUID).

phone
string
required

Contact's phone number as first seen. Usually E.164; a contact first created by an inbound SMS can carry the sender's bare national form (e.g. 4155551234). Upserting any form of the same number returns this contact.

opted_out
boolean
required

True if this person has opted out: a STOP reply, a rep in the dashboard, a Do Not Disturb in your connected GoHighLevel account, or POST /v1/contacts/{id}/opt-out. When true, every send to this contact returns 422 contact_opted_out. An opt-out can't be undone, and it belongs to the number: a contact deleted and created again is still opted out.

created_at
string
required

ISO 8601 UTC timestamp the contact was created.

first_name
string | null
last_name
string | null
email
string | null
city
string | null
state
string | null
timezone
string | null

IANA timezone used for this contact's sending hours, or null if not set yet. When it is null and the number is a US or Canadian one, iBubbl infers the zone from the area code and saves it here when the contact's first message is processed; otherwise your account's timezone is used. Once set, an upsert never replaces it, so pass timezone on the first upsert, before you send, or change it with PATCH.

tags
string[]

The contact's tag names, sorted case-insensitively.

opted_out_at
string | null

ISO 8601 UTC timestamp of the opt-out, or null.

blocked
boolean
default:false

True if you blocked this contact (dashboard or POST /v1/contacts/{id}/block). Sends to them return 422 contact_blocked until you unblock them. Unlike an opt-out, a block is yours to undo, and it fires no webhook.

blocked_at
string | null

ISO 8601 UTC timestamp of the block, or null.