Opt-out

Opt-out endpoints manage per-contact, per-platform, per-user messaging preferences. A contact can be opted out of one platform for one user but still reachable on other platforms or by other users.

All endpoints require authentication via the X-API-Key header. See Authentication.


Opt-out model

Opt-outs are stored on the contact document as a nested map:

contact.optOuts = {
  "email": { "userId1": true, "userId2": false },
  "stacked-sms": { "userId1": false },
  "personal-sms": { "userId1": true }
}

Platforms: email, stacked-sms, personal-sms, twitter, web-chat.

A value of true means the contact has opted out of receiving messages on that platform from that user.


Get opt-out status

GET /opt-out/:id

Returns the opt-out map for a contact across all platforms and users.

Path parameters

ParameterTypeDescription
idstringContact ID.

Example request

curl "https://<host>/api/opt-out/675a..." \
  -H "X-API-Key: your-api-key"

Response

{
  "success": true,
  "data": {
    "email": {
      "675a...user1": true
    },
    "stacked-sms": {
      "675a...user1": false,
      "675a...user2": true
    }
  }
}

Set opt-out status

POST /opt-out

Sets the opt-out status for a specific contact, platform, and user combination.

Request body

FieldTypeRequiredNotes
contactIdstringYesContact ID.
userIdstringYesUser ID.
platformstringYesemail, stacked-sms, personal-sms, twitter, or web-chat.
valuebooleanYestrue to opt out, false to opt in.

Example request

curl -X POST https://<host>/api/opt-out \
  -H "X-API-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "contactId": "675a...",
    "userId": "675a...",
    "platform": "stacked-sms",
    "value": true
  }'

Response

Returns the updated opt-out map for the contact:

{
  "success": true,
  "data": {
    "stacked-sms": {
      "675a...": true
    }
  }
}

Errors

StatusMessageCause
400Validation errorMissing required fields or invalid platform.

Response envelope

All endpoints use the standard envelope:

{
  "error": false,
  "success": true,
  "message": "...",
  "code": 200,
  "data": "..."
}

Error responses:

{
  "error": true,
  "success": false,
  "message": "...",
  "code": 400,
  "data": null
}

data is null for a general failure, such as a database error or an upstream timeout. When the request is rejected because of a specific field, data carries the field(s) at fault instead:

{
  "error": true,
  "success": false,
  "message": "phone: Phone parse failed: The string supplied did not seem to be a phone number (input: <masked>)",
  "code": 400,
  "data": {
    "issues": [
      {
        "path": "phone",
        "message": "Phone parse failed: The string supplied did not seem to be a phone number (input: <masked>)"
      }
    ]
  }
}

Each issue carries a path (the dotted path into the request body) and a message. A label is added when the path is not self-describing, which today means custom fields only, for example "path": "fields.68b0a1f39c2e4d0012ab77e5", "label": "Class Year". issues is an array, but treat it as holding at most one entry: validation stops at the first failure.

On this page