Skip to content
Last updated

The Live Chat system enables agent-based customer conversations with ticket tracking, team assignment, and message history across WhatsApp, Web, and Facebook channels.

Authentication Required

All API requests require your Developer Key in the Authorization header. No Bearer prefix — pass the key directly. See Authentication for setup and security best practices.


Architecture

The Live Chat system is built around three core concepts:

ConceptDescription
Chat ParticipantsActive conversations between a customer and your platform
TicketsTrack and manage conversations with status workflows
Agents & TeamsSupport staff organized with team assignment and supervisor oversight

Conversation flow

Customer Message ──> Unassigned Queue ──> Agent Picks Up ──> Active Chat
                                                                  │
                                                    ┌─────────────┼─────────────┐
                                                    ▼             ▼             ▼
                                                 Resolved    Transferred     Closed
                                                  (Ticket)   (to team)    (Rating widget)

Chatbot conversation flow

Follow this three-step flow to receive an incoming WhatsApp message and retrieve the full conversation history.

Incoming Message ──> Webhook fires ──> Look up ChatParticipant ──> Get messages
    (customer)       (your server)      (by sender number)        (by participant ID)

Step 1: Receive the incoming message webhook

When a customer sends a message, your configured incomingMessageURL receives a POST with the message payload. See Webhooks — Incoming message payload for full details.

{
  "profileName": "John Smith",
  "sender": "+27987654321",
  "senderUserId": "ZA.1021033720668862",
  "username": "john_smith",
  "receiver": "+27123456789",
  "text": "Hi, I need help with my order",
  "messageType": "INTERACTION",
  "messageContentType": "TEXT",
  "gstId": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
  "participantId": "participant-uuid",
  "sentTime": "2026-01-15T10:30:00.000+00:00",
  "status": "RECEIVED"
}
Alpha usernames (BSUID)

WhatsApp is rolling out alpha usernames. Each customer now has a durable, business-scoped user id (BSUID, e.g. ZA.1021033720668862) that is stable for your business even if the customer changes their phone number — and that stays present on inbound events even when the phone number is withheld. Customers may also set an optional username (display only).

Incoming, chatbot, and status webhooks carry the customer BSUID as senderUserId / recipientUserId, plus the optional username. The phone number (sender / senderMsisdn) remains the primary identifier today — the BSUID is an additional, more durable key you can store now and rely on as phone numbers become optional. The BSUID is always present on these payloads; username is omitted only when the customer hasn't set one.

Use the sender field without a + to look up the chat participant in Step 2. When the phone number is withheld, match on userId (the customer BSUID) instead — it is present on the chat participant even when the number is not.

`participantId` is not the live-chat participant id

The participantId field on the incoming-message webhook payload identifies a participant in the conversation engine. It is not the same as the live-chat chatParticipantId used to fetch messages or send agent replies. Always resolve the live-chat participant by sender (Step 2) before calling any /pl4chat-service/api/v2/messages or /pl4chat-service/api/v2/chats endpoints.

Step 2: Get the chat participant by sender number

List your chats and filter by the sender's phone number to find the latest conversation. The v2 list endpoint selects which conversations to return with a scope filter — the agent and client are resolved from your API key, so you only choose the tab:

GET /pl4chat-service/api/v2/chats?scope=my

Choose your scope

scopeReturns
myConversations assigned to you (the authenticated agent)
teamConversations assigned to your team members
unassignedConversations waiting in queue
closedClosed conversations
missed-agentMissed conversations
missed-after-hoursAfter-hours missed conversations
my-missedYour missed conversations
openAll open client conversations
allAll conversations (open and closed)
ParameterTypeDescription
scopestringWhich list to return (see above). Required
pageintegerPage number (0-based). Default: 0
sizeintegerPage size. Default: 10
searchstringFilter by phone number, name, or customer id

Use the search parameter with the sender's phone number or BSUID (senderUserId) to narrow results directly, or filter client-side after fetching. The response is a page of ChatParticipantResponse objects. Match on phoneNumber or userId — a customer with a withheld phone number is identified only by userId (BSUID).

curl -X GET \
  "https://api.payless4messaging.com/pl4chat-service/api/v2/chats?scope=unassigned&page=0&size=50&search=27987654321" \
  -H "Authorization: $ECOMM_API_KEY"

Step 3: Get the conversation messages

Use the participant ID from step 2 to retrieve the full message history:

curl -X GET \
  "https://api.payless4messaging.com/pl4chat-service/api/v2/messages?participantId=participant-uuid" \
  -H "Authorization: $ECOMM_API_KEY"

Alternative: Get messages by tracking number

If you have the GSTN (Global System Tracking Number) or CTN (Customer Tracking Number) from the chat participant object, you can retrieve messages directly without needing the participant ID:

GET /pl4chat-service/api/v2/messages/tracking/{trackingNumber}
curl -X GET \
  "https://api.payless4messaging.com/pl4chat-service/api/v2/messages/tracking/a1b2c3d4-e5f6-7890-a1b2-c3d4e5f67890" \
  -H "Authorization: $ECOMM_API_KEY"

Mark a conversation as read

After retrieving messages, mark the conversation as read — this clears the unread badge and sends a read receipt to the customer in one call:

POST /pl4chat-service/api/v2/messages/read?participantId=cp-a1b2c3d4

Chat participants

Each chat participant carries:

FieldTypeDescription
idstringChat participant id
phoneNumberstringCustomer phone number. May be absent when the number is withheld
userIdstringCustomer BSUID (e.g. ZA.1021033720668862), durable across phone-number changes. Present even when phoneNumber is not
usernamestringCustomer's optional WhatsApp username (display only)
namestringDisplay name

Terminate or reopen a chat

Close or reopen a conversation with its id — the acting agent is resolved from your API key, so there's no request body to assemble:

POST /pl4chat-service/api/v2/chats/{id}/terminate   # close (sends the rating widget if configured)
POST /pl4chat-service/api/v2/chats/{id}/open        # reopen and assign to you

Both return the updated ChatParticipantResponse.

The assigned-agent slot is freed for you

Terminating a chat moves its current assignedTo to lastAssignedAgent and frees the slot in the agent's chat-limit count automatically. (The deprecated PUT /pl4chat-service/ChatParticipant/terminateChatParticipantChat required you to echo the full object back to make that happen — v2 does it server-side.)


Agent messaging

Why this endpoint, not the notifications one?

Only messages sent through the live-chat send endpoint show up in the live-chat UI. Outbound sends through the notifications endpoint (/whatsapp-api-service/v2/channels/whatsapp) reach the customer but bypass the chat service entirely — agents won't see them. See How the system fits together for the architecture.

Send a reply

One endpoint sends on every channel. Set channel (WHATSAPP, WEB, or FACEBOOK) and text — the agent is resolved from your API key:

POST /pl4chat-service/api/v2/messages
{
  "participantId": "participant-uuid",
  "channel": "WHATSAPP",
  "tempId": "unique-temp-uuid",
  "text": "Here is the information you requested."
}

tempId is optional — supply a client-generated string only if you want it echoed back to reconcile an optimistic UI message; otherwise omit it. The response is the stored MessageResponse (with your tempId echoed back when you sent one). To quote/reply to an earlier message, also set quotedExternalMessageId.

Send media

Upload the file, then send the returned mediaUrl — the same flow works for any channel:

POST /pl4chat-service/api/v2/messages/media   # multipart/form-data, field "file" -> { mediaUrl, mediaType }
POST /pl4chat-service/api/v2/messages         # { participantId, channel, mediaUrl, text? }

The content type defaults to MEDIA when a mediaUrl is present, so you don't need to set it.

Typing indicator

POST /pl4chat-service/api/v2/messages/typing?participantId=participant-uuid

Shows a typing bubble to the customer while the agent is composing a reply.

Mark a conversation as read

POST /pl4chat-service/api/v2/messages/read?participantId=participant-uuid

Tickets

Search tickets

GET /pl4chat-service/ticket/search

Required parameters:

ParameterTypeDescription
pageintegerPage number (0-based)
sizeintegerPage size
startDateTimestringStart of date range
endDateTimestringEnd of date range
clientRefstringClient reference

Optional filters:

FilterTypeDescription
whatsAppNumberstringCustomer WhatsApp number
ratingenumpoor, average, or excellent
ticketNumberstringSpecific ticket number (e.g., TCK-001)
agentIdstringFilter by assigned agent
selectedStatusenumopen, closed, awaiting agent, awaiting customer, resolved

Update ticket status

PUT /pl4chat-service/ticket/{ticketId}/status?newStatus=RESOLVED

Available statuses:

StatusDescription
OPENTicket is active and being worked on
AWAITING_AGENTWaiting for an agent to respond
AWAITING_CUSTOMERWaiting for the customer to respond
RESOLVEDIssue has been resolved but ticket remains accessible
CLOSEDTicket is closed and archived

Get ticket by number

GET /pl4chat-service/ticket/by-ticket-number?ticketNumber=TCK-001

Contacts

Manage customer contact records linked to your account.

MethodEndpointDescription
GET/payless4messaging-service/WhatsApp/contactsGet all contacts (paginated)
POST/payless4messaging-service/WhatsApp/contactsCreate a contact
PUT/payless4messaging-service/WhatsApp/contacts/{id}Update a contact
DELETE/payless4messaging-service/WhatsApp/contacts/{id}Delete a contact
Limited update fields

Currently, only the fullName field can be updated on an existing contact. Other fields (phone number, business name, etc.) are read-only after creation.

PUT /payless4messaging-service/WhatsApp/contacts/{id}

{
  "fullName": "Jane Smith"
}

Supported channels

ChannelValueDescription
WhatsAppWHATSAPPWhatsApp conversations via Cloud or Lite
WebWEBWeb chat widget embedded in your website
FacebookFACEBOOKFacebook Messenger conversations

Message content types

TypeDescription
TEXTPlain text message
IMAGEImage attachment (JPG, PNG, GIF)
DOCUMENTDocument attachment (PDF, DOCX, XLSX)
VIDEOVideo attachment (MP4)
AUDIOAudio message
VOICEVoice note
FILEGeneric file attachment
LOCATIONLocation with latitude/longitude
BUTTONButton interaction response
CAROUSELCarousel card
RATINGCustomer rating response