Sending Preferences
Full request reference for the LiSTNR Preferences Webhook.
Endpoint
POST /update
| Environment | URL |
|---|---|
| Dev | <dev-url>/update |
| Production | <prod-url>/update |
Authentication
Every request requires two headers:
Authorization
Include the LiSTNR JWT obtained from the Token Provider as a Bearer credential.
Authorization: Bearer <access_token>
The token must have been issued with the write:preferences scope and the salesforce-preference-centre audience. A missing, expired, or invalid token returns 401 Unauthorized. A valid token without the required scope returns 403 Forbidden.
See Getting Started for how to obtain a token.
x-listnr-source
Identify the calling system with this header. The value must be exactly salesforce-preference-centre.
x-listnr-source: salesforce-preference-centre
A missing or incorrect value returns 400 Bad Request with code INVALID_SOURCE_HEADER.
Request body
Send a JSON array of one or more preference update items. The array must not be empty.
[
{
"emailSha": "<sha256-of-email>",
"brand": "listnr",
"preference": "NEWSLETTER",
"status": "SUBSCRIBED",
"timestamp": "2024-01-01T00:00:00.000Z",
"source": "PREFERENCE_CENTRE",
"reason": null
}
]
Field reference
| Field | Type | Required | Description |
|---|---|---|---|
emailSha | string | yes | SHA-256 hash of the user's email address (lowercase hex). Used to identify the user in Firestore. |
brand | string | yes | The brand the preference applies to (e.g. listnr). |
preference | enum | yes | The preference channel. See Preference channels. |
status | enum | yes | The new subscription status. See Preference statuses. |
timestamp | string | yes | ISO 8601 timestamp of when the preference change occurred. |
source | string | yes | Must be PREFERENCE_CENTRE. |
reason | object | null | no | Optional unsubscribe reason. See Reason object. |
Preference channels
| Value | Description |
|---|---|
NEWSLETTER | Email newsletter subscription |
PARTNER | Partner marketing communications |
COMPETITION | Competition-related communications |
BRAND | Brand marketing communications |
Preference statuses
| Value | Description |
|---|---|
SUBSCRIBED | User has opted in |
UNSUBSCRIBED | User has opted out |
Reason object
Present only when status is UNSUBSCRIBED. May be null.
| Field | Type | Required | Description |
|---|---|---|---|
code | string | yes | Normalised unsubscribe reason code. |
codeRaw | string | no | Raw code as received from the source system. |
descriptionRaw | string | no | Human-readable description from the source system. |
Response
200 OK
Preferences were accepted and written to Firestore.
{
"processedCount": 1
}
Error responses
| Status | Code | Cause |
|---|---|---|
400 | INVALID_SOURCE_HEADER | x-listnr-source header is missing or does not equal salesforce-preference-centre |
400 | BODY_NOT_ARRAY | Request body is not a JSON array |
400 | BODY_EMPTY_ARRAY | Request body is an empty array |
400 | MISSING_EMAIL_SHA | An item is missing the emailSha field |
400 | MISSING_BRAND | An item is missing the brand field |
400 | INVALID_PREFERENCE | An item has an unrecognised preference value |
400 | INVALID_STATUS | An item has an unrecognised status value |
400 | MISSING_TIMESTAMP | An item is missing the timestamp field |
400 | INVALID_SOURCE | An item's source field is not PREFERENCE_CENTRE |
400 | MISSING_REASON_CODE | A reason object is present but missing the code field |
401 | — | Missing, expired, or invalid Bearer token |
403 | — | Token is valid but does not carry the write:preferences scope |