Custom Digital Channel — Integration Guide

4 min read

ℹ️
This guide describes how to push customer messages into Salted CX over the Custom Digital Channel — a channel you drive from your own platform (e.g. a web chat widget). You first create a conversation, then push customer triggers (events that already happened on your side) to it.

Overview

The Custom Digital Channel lets your platform deliver customer turns to Salted CX. Direction is defined from your point of view:

  • Trigger (inbound, you → us) — a message the customer already sent in your widget. You push it to us.
  • Action (outbound, us → you) — asking your platform to render a reply. This is a future capability and is not part of this guide.

Each trigger runs through the same conversation lifecycle as a native digital turn (translation, routing to an agent or bot).

Authentication

All requests use your per-account bearer token (the same token used for the YourLogic integration):

Authorization: Bearer <your-account-token>
Content-Type: application/json

Requests without a valid token for the account in the path are rejected.

Flow

sequenceDiagram
	autonumber
	participant You as Your platform
	participant CreateApi as Create-conversation endpoint
	participant API as Triggers endpoint
	You->>CreateApi: create conversation
	CreateApi-->>You: conversationPid
	You->>API: push triggers on conversationPid
	API-->>You: per-trigger result

Create the conversation once (you receive a conversationPid), then push one or more triggers to that conversation.

Create the conversation

Create the conversation first; the response returns a conversationId that you use as conversationPid when pushing triggers. The contact is created or matched automatically from the customer block — you do not make a separate contact call.

POST /api/v1/live/custom-channel/accounts/{accountId}/conversations

The conversation is created as an inbound chat conversation. Request body:

{
  "brandPid": "<brand-uuid>",
  "customer": {
    "displayName": "Jane Doe",
    "contact": { "contact": "[email protected]", "contactType": "Anonymous" }
  },
  "languageCustomer": "en",
  "url": "https://widget.example.com/chat",
  "custom": null
}

Request fields:

FieldTypeRequiredDescription
brandPiduuidyesYour brand id
customerobjectyesCustomer details (see below)
languageCustomerstringnoCustomer language, e.g. en
urlstringnoLast page the customer visited
customobjectnoCustom properties (any JSON), or null

customer fields:

FieldTypeRequiredDescription
displayNamestringyesCustomer display name
contact.contactstringyesA stable identifier for the customer (email, phone, or your own id)
contact.contactTypestringyese.g. Anonymous, Email, Phone

Response:

{ "conversationId": "11111111-2222-3333-4444-555555555555" }

Push triggers

POST /api/v1/live/custom-channel/accounts/{accountId}/conversations/{conversationPid}/triggers

The body is an ordered array of triggers. v1 supports participantType = CUSTOMER and two trigger types: MESSAGE and ANSWER.

Common fields

FieldTypeRequiredDescription
typestringyesMESSAGE or ANSWER
participantTypestringyesCUSTOMER (only value in v1)
externalIdstringyesYour unique id for this trigger; used as the idempotency key

MESSAGE — a customer text message

FieldTypeRequiredDescription
contentstringyesThe message text
attachmentsarraynoList of attachments (see below)

Attachment object:

FieldTypeRequiredDescription
namestringyesFile name
bodystringyesBase64-encoded file content
mimeTypestringnoe.g. image/jpeg

ANSWER — a customer answering a question

FieldTypeRequiredDescription
answerIdstringyesThe id of the answer the customer chose
responseToIduuidyesThe id of the question turn being answered

Examples

Text message:

{
  "triggers": [
    {
      "type": "MESSAGE",
      "participantType": "CUSTOMER",
      "externalId": "a1b2c3-0001",
      "content": "Hello, I need help with my order"
    }
  ]
}

Message with an attachment:

{
  "triggers": [
    {
      "type": "MESSAGE",
      "participantType": "CUSTOMER",
      "externalId": "a1b2c3-0002",
      "content": "Here is the photo",
      "attachments": [
        { "name": "receipt.jpg", "body": "<base64-bytes>", "mimeType": "image/jpeg" }
      ]
    }
  ]
}

Answer to a question:

{
  "triggers": [
    {
      "type": "ANSWER",
      "participantType": "CUSTOMER",
      "externalId": "a1b2c3-0003",
      "answerId": "yes",
      "responseToId": "11111111-2222-3333-4444-555555555555"
    }
  ]
}

Response

The response reports a status per trigger, in the same order:

{
  "conversationPid": "11111111-2222-3333-4444-555555555555",
  "results": [
    { "index": 0, "type": "MESSAGE", "status": "CREATED", "message": "Created" }
  ]
}

Per-trigger status:

StatusMeaning
CREATEDThe trigger was applied and a turn was created
DUPLICATEA trigger with this externalId was already applied; nothing changed (idempotent)
FAILEDThe trigger could not be applied; processing of the batch stops here
SKIPPEDNot attempted because an earlier trigger in the batch failed

HTTP status codes:

CodeWhen
200 OKAll triggers applied (CREATED or DUPLICATE)
207 Multi-StatusAt least one trigger FAILED; inspect the per-trigger results
400 Bad RequestA trigger is malformed (missing required field, unknown type/participantType). No trigger in the batch is applied.
404 Not FoundThe conversation does not exist

Idempotency

Each trigger carries an externalId that you choose. Re-sending a trigger with the same externalId does not create a second turn — it returns DUPLICATE. Use stable ids so safe retries never duplicate messages.

Batch semantics

  • Triggers are applied strictly in order.
  • On the first failure, processing stops; remaining triggers are returned as SKIPPED and the HTTP status is 207.
  • Send a single trigger per request if you prefer to handle each independently.
⚠️
v1 scope: one custom channel per account; participantType = CUSTOMER only; trigger types MESSAGE (with attachments) and ANSWER. Typing indicators and outbound delivery are not yet available.
Was this page helpful?