Contextual Messaging
SDK methods for channels, threads, messages, participants, read state, inbox, flags, and escalation.
The client.threads namespace provides typed methods for the Contextual Messaging API. Available in TypeScript, Python, and Go SDKs.
| SDK | Install | Namespace |
|---|---|---|
| TypeScript | npm install @caldera/platformxe-sdk | client.threads |
| Python | pip install platformxe | client.threads |
| Go | go get github.com/calderax/platformxe-go | client.Threads |
Channels
Create a channel
const channel = await client.threads.createChannel({
slug: 'booking',
displayName: 'Booking Conversations',
entityType: 'BOOKING',
participantRoles: ['GUEST', 'HOST', 'PLATFORM'],
defaultVisibility: ['ALL'],
lifecycleRules: {
autoClose: { onEntityStatus: ['CHECKED_OUT', 'CANCELLED'] },
autoArchive: { afterClosedDays: 90 },
},
escalationConfig: {
flagReasons: [
{ code: 'SAFETY', label: 'Safety concern', severity: 'HIGH' },
{ code: 'DISPUTE', label: 'Dispute', severity: 'MEDIUM' },
],
},
});
channel = client.threads.create_channel(
slug="booking",
display_name="Booking Conversations",
entity_type="BOOKING",
participant_roles=["GUEST", "HOST", "PLATFORM"],
default_visibility=["ALL"],
lifecycle_rules={
"autoClose": {"onEntityStatus": ["CHECKED_OUT", "CANCELLED"]},
"autoArchive": {"afterClosedDays": 90},
},
)
channel, err := client.Threads.CreateChannel(platformxe.CreateThreadChannelInput{
Slug: "booking",
DisplayName: "Booking Conversations",
EntityType: "BOOKING",
ParticipantRoles: []string{"GUEST", "HOST", "PLATFORM"},
DefaultVisibility: []string{"ALL"},
LifecycleRules: map[string]interface{}{
"autoClose": map[string]interface{}{"onEntityStatus": []string{"CHECKED_OUT", "CANCELLED"}},
},
})
List channels
const { channels } = await client.threads.listChannels();
result = client.threads.list_channels()
result, err := client.Threads.ListChannels()
Update a channel
await client.threads.updateChannel('ch_abc', {
displayName: 'Updated Channel Name',
isActive: true,
});
client.threads.update_channel("ch_abc", display_name="Updated Channel Name")
client.Threads.UpdateChannel("ch_abc", platformxe.UpdateThreadChannelInput{
DisplayName: strPtr("Updated Channel Name"),
})
Get escalation config
const config = await client.threads.getEscalationConfig('ch_abc');
config = client.threads.get_escalation_config("ch_abc")
config, err := client.Threads.GetEscalationConfig("ch_abc")
Set escalation config
await client.threads.setEscalationConfig('ch_abc', {
flagReasons: [
{ code: 'SAFETY', label: 'Safety concern', severity: 'HIGH' },
{ code: 'CLEANLINESS', label: 'Cleanliness issue', severity: 'MEDIUM' },
{ code: 'REFUND', label: 'Refund request', severity: 'LOW' },
],
rules: [{
id: 'rule-safety',
name: 'Safety auto-escalation',
trigger: 'PARTICIPANT_FLAG',
conditions: { in: [{ var: 'flag.reason' }, ['SAFETY']] },
actions: [{ type: 'CREATE_ISSUE', config: { title: 'SAFETY: {{thread.subject}}', priority: 'URGENT' } }],
priority: 1,
isActive: true,
}],
});
client.threads.set_escalation_config("ch_abc", config={
"flagReasons": [
{"code": "SAFETY", "label": "Safety concern", "severity": "HIGH"},
],
"rules": [{
"id": "rule-safety",
"name": "Safety auto-escalation",
"trigger": "PARTICIPANT_FLAG",
"conditions": {"in": [{"var": "flag.reason"}, ["SAFETY"]]},
"actions": [{"type": "CREATE_ISSUE", "config": {"title": "SAFETY: {{thread.subject}}", "priority": "URGENT"}}],
"priority": 1,
"isActive": True,
}],
})
client.Threads.SetEscalationConfig("ch_abc", map[string]interface{}{
"flagReasons": []map[string]interface{}{
{"code": "SAFETY", "label": "Safety concern", "severity": "HIGH"},
},
"rules": []map[string]interface{}{
{
"id": "rule-safety", "name": "Safety auto-escalation",
"trigger": "PARTICIPANT_FLAG",
"actions": []map[string]interface{}{
{"type": "CREATE_ISSUE", "config": map[string]interface{}{"title": "SAFETY: {{thread.subject}}", "priority": "URGENT"}},
},
},
},
})
Threads
Create a thread
const thread = await client.threads.createThread({
channelSlug: 'booking',
entityId: 'BK-2026-00451',
subject: 'Booking BK-2026-00451',
participants: [
{ role: 'GUEST', externalId: 'usr-abc', displayName: 'Ade Bakare' },
{ role: 'HOST', externalId: 'ptn-xyz', displayName: 'Bimpe Adeyemi' },
{ role: 'PLATFORM', externalId: 'system', displayName: 'Support' },
],
});
thread = client.threads.create_thread(
channel_slug="booking",
entity_id="BK-2026-00451",
subject="Booking BK-2026-00451",
participants=[
{"role": "GUEST", "externalId": "usr-abc", "displayName": "Ade Bakare"},
{"role": "HOST", "externalId": "ptn-xyz", "displayName": "Bimpe Adeyemi"},
{"role": "PLATFORM", "externalId": "system", "displayName": "Support"},
],
)
thread, err := client.Threads.CreateThread(platformxe.CreateThreadInput{
ChannelSlug: "booking",
EntityID: "BK-2026-00451",
Subject: "Booking BK-2026-00451",
Participants: []platformxe.ThreadParticipant{
{Role: "GUEST", ExternalID: "usr-abc", DisplayName: "Ade Bakare"},
{Role: "HOST", ExternalID: "ptn-xyz", DisplayName: "Bimpe Adeyemi"},
{Role: "PLATFORM", ExternalID: "system", DisplayName: "Support"},
},
})
List threads
const { threads } = await client.threads.listThreads({
channelSlug: 'booking',
status: 'OPEN',
});
result = client.threads.list_threads(channel_slug="booking", status="OPEN")
result, err := client.Threads.ListThreads(map[string]string{
"channelSlug": "booking", "status": "OPEN",
})
Get a thread
const detail = await client.threads.getThread('th-001');
detail = client.threads.get_thread("th-001")
detail, err := client.Threads.GetThread("th-001")
Update a thread
Update a thread's subject or metadata.
const updated = await client.threads.updateThread('th-001', {
subject: 'Updated subject line',
metadata: { priority: 'high' },
});
updated = client.threads.update_thread("th-001", subject="Updated subject line")
updated, err := client.Threads.UpdateThread("th-001", platformxe.UpdateThreadInput{
Subject: strPtr("Updated subject line"),
})
Close a thread
await client.threads.closeThread('th-001', { reason: 'CHECKED_OUT' });
client.threads.close_thread("th-001", reason="CHECKED_OUT")
result, err := client.Threads.CloseThread("th-001", "CHECKED_OUT")
Reopen a thread
await client.threads.reopenThread('th-001');
client.threads.reopen_thread("th-001")
result, err := client.Threads.ReopenThread("th-001")
Messages
Send a message
const msg = await client.threads.sendMessage('th-001', {
senderExternalId: 'usr-abc',
senderRole: 'GUEST',
content: 'What time can I check in?',
visibility: ['ALL'],
});
msg = client.threads.send_message(
"th-001",
sender_external_id="usr-abc",
sender_role="GUEST",
content="What time can I check in?",
visibility=["ALL"],
)
msg, err := client.Threads.SendMessage("th-001", platformxe.SendMessageInput{
SenderExternalID: "usr-abc",
SenderRole: "GUEST",
Content: "What time can I check in?",
Visibility: []string{"ALL"},
})
List messages
Messages are visibility-filtered by the requesting participant's role.
const { messages } = await client.threads.listMessages('th-001', {
role: 'GUEST',
page: 1,
limit: 50,
});
result = client.threads.list_messages("th-001", role="GUEST", page=1)
result, err := client.Threads.ListMessages("th-001", map[string]string{
"role": "GUEST", "page": "1", "limit": "50",
})
Send a system message
System messages are sent on behalf of the platform and require the threads:admin scope.
await client.threads.sendSystemMessage('th-001', {
content: 'Guest has checked in.',
});
client.threads.send_system_message("th-001", content="Guest has checked in.")
msg, err := client.Threads.SendSystemMessage("th-001", "Guest has checked in.", []string{"ALL"})
Edit a message
await client.threads.editMessage('msg-001', { content: 'Updated text' });
client.threads.edit_message("msg-001", content="Updated text")
msg, err := client.Threads.EditMessage("msg-001", "Updated text")
Delete a message
Soft-deletes a message. The message record is preserved for audit purposes but the content is no longer visible.
await client.threads.deleteMessage('msg-001');
client.threads.delete_message("msg-001")
result, err := client.Threads.DeleteMessage("msg-001")
Participants
Add a participant
await client.threads.addParticipant('th-001', {
role: 'AGENT',
externalId: 'agt-001',
displayName: 'Travel Agent',
});
client.threads.add_participant(
"th-001",
role="AGENT",
external_id="agt-001",
display_name="Travel Agent",
)
participant, err := client.Threads.AddParticipant("th-001", platformxe.AddParticipantInput{
Role: "AGENT", ExternalID: "agt-001", DisplayName: "Travel Agent",
})
Remove a participant
await client.threads.removeParticipant('th-001', 'tp-agent');
client.threads.remove_participant("th-001", "tp-agent")
result, err := client.Threads.RemoveParticipant("th-001", "tp-agent")
Update a participant
Update a participant's display name, avatar, or mute state.
await client.threads.updateParticipant('th-001', 'tp-agent', {
isMuted: true,
displayName: 'Senior Travel Agent',
});
client.threads.update_participant(
"th-001", "tp-agent",
is_muted=True,
display_name="Senior Travel Agent",
)
participant, err := client.Threads.UpdateParticipant("th-001", "tp-agent", platformxe.UpdateParticipantInput{
IsMuted: boolPtr(true),
})
Read state
Mark as read
await client.threads.markRead('th-001', {
participantExternalId: 'usr-abc',
participantRole: 'GUEST',
});
client.threads.mark_read("th-001", participant_external_id="usr-abc", participant_role="GUEST")
result, err := client.Threads.MarkRead("th-001", "usr-abc", "GUEST")
Get read states
Returns the read state for all participants in a thread.
const { readStates } = await client.threads.getReadStates('th-001');
result = client.threads.get_read_states("th-001")
result, err := client.Threads.GetReadStates("th-001")
Inbox
Get inbox
Retrieve all threads for a participant with unread counts and last message previews.
const { items } = await client.threads.inbox({
externalId: 'usr-abc',
role: 'GUEST',
status: 'OPEN',
});
result = client.threads.inbox(external_id="usr-abc", role="GUEST", status="OPEN")
result, err := client.Threads.Inbox("usr-abc", "GUEST", map[string]string{"status": "OPEN"})
Unread count
const { count } = await client.threads.unreadCount({
externalId: 'usr-abc',
role: 'GUEST',
});
result = client.threads.unread_count(external_id="usr-abc", role="GUEST")
result, err := client.Threads.UnreadCount("usr-abc", "GUEST")
Flags and escalation
Flag a message
Flag a message for review. If escalation rules are configured on the channel, matching rules execute automatically.
const flag = await client.threads.flagMessage('th-001', 'msg-005', {
reason: 'SAFETY',
note: 'Guest reported feeling unsafe',
flaggedByExternalId: 'usr-abc',
flaggedByRole: 'GUEST',
});
flag = client.threads.flag_message(
"th-001", "msg-005",
reason="SAFETY",
note="Guest reported feeling unsafe",
flagged_by_external_id="usr-abc",
flagged_by_role="GUEST",
)
flag, err := client.Threads.FlagMessage("th-001", "msg-005", platformxe.FlagMessageInput{
Reason: "SAFETY",
Note: "Guest reported feeling unsafe",
FlaggedByExternalID: "usr-abc",
FlaggedByRole: "GUEST",
})
List flags for a thread
const { flags } = await client.threads.listFlags('th-001', {
status: 'PENDING',
});
result = client.threads.list_flags("th-001", status="PENDING")
result, err := client.Threads.ListFlags("th-001", map[string]string{"status": "PENDING"})
List flags across all threads
Query flags across all threads with optional filters for status, severity, and date range.
const { flags } = await client.threads.listFlagsAcrossThreads({
status: 'PENDING',
severity: 'HIGH',
});
result = client.threads.list_flags_across_threads(status="PENDING", severity="HIGH")
result, err := client.Threads.ListFlagsAcrossThreads(map[string]string{
"status": "PENDING", "severity": "HIGH",
})
Review a flag
Approve or reject a flagged message. Approved flags may trigger further escalation actions.
const reviewed = await client.threads.reviewFlag('flag-001', {
action: 'APPROVE',
reviewedByExternalId: 'admin-001',
reviewedByRole: 'PLATFORM',
note: 'Confirmed safety concern — escalating to management',
});
reviewed = client.threads.review_flag(
"flag-001",
action="APPROVE",
reviewed_by_external_id="admin-001",
reviewed_by_role="PLATFORM",
)
reviewed, err := client.Threads.ReviewFlag("flag-001", platformxe.ReviewFlagInput{
Action: "APPROVE",
})
Escalate a thread
Manually escalate a thread. This bypasses the automatic rule-based escalation and creates an immediate escalation record.
await client.threads.escalateThread('th-001', {
reason: 'Guest safety concern requires immediate attention',
escalatedByExternalId: 'admin-001',
escalatedByRole: 'PLATFORM',
});
client.threads.escalate_thread(
"th-001",
reason="Guest safety concern requires immediate attention",
escalated_by_external_id="admin-001",
escalated_by_role="PLATFORM",
)
result, err := client.Threads.EscalateThread("th-001", "Guest safety concern", "admin-001", "PLATFORM")
Entity events
Forward entity status changes for lifecycle evaluation. When a status matches a channel's lifecycle rules, threads are automatically closed or archived.
await client.threads.entityEvent({
channelSlug: 'booking',
entityId: 'BK-2026-00451',
event: 'STATUS_CHANGED',
newStatus: 'CHECKED_OUT',
});
client.threads.entity_event(
channel_slug="booking",
entity_id="BK-2026-00451",
event="STATUS_CHANGED",
new_status="CHECKED_OUT",
)
result, err := client.Threads.EntityEvent(platformxe.EntityEventInput{
ChannelSlug: "booking",
EntityID: "BK-2026-00451",
Event: "STATUS_CHANGED",
NewStatus: "CHECKED_OUT",
})
Method reference
All 29 methods in the threads namespace:
| # | Method | Description |
|---|---|---|
| 1 | createChannel | Create a new conversation channel |
| 2 | listChannels | List all channels |
| 3 | updateChannel | Update channel configuration |
| 4 | getEscalationConfig | Get channel escalation configuration |
| 5 | setEscalationConfig | Set channel escalation configuration |
| 6 | createThread | Create a thread with participants |
| 7 | listThreads | List threads with filters |
| 8 | getThread | Get thread detail |
| 9 | updateThread | Update thread subject or metadata |
| 10 | closeThread | Close a thread |
| 11 | reopenThread | Reopen a closed thread |
| 12 | sendMessage | Send a participant message |
| 13 | listMessages | List messages (visibility-filtered) |
| 14 | sendSystemMessage | Send a system message |
| 15 | editMessage | Edit message content |
| 16 | deleteMessage | Soft-delete a message |
| 17 | addParticipant | Add a participant to a thread |
| 18 | removeParticipant | Remove a participant |
| 19 | updateParticipant | Update participant display name, avatar, or mute state |
| 20 | markRead | Mark a thread as read |
| 21 | getReadStates | Get read states for all participants |
| 22 | inbox | Get inbox for a participant |
| 23 | unreadCount | Get total unread count |
| 24 | flagMessage | Flag a message for review |
| 25 | listFlags | List flags for a thread |
| 26 | listFlagsAcrossThreads | List flags across all threads |
| 27 | reviewFlag | Approve or reject a flag |
| 28 | escalateThread | Manually escalate a thread |
| 29 | entityEvent | Forward entity status change |
Scopes required
| Method group | Scope |
|---|---|
| Channel CRUD | threads:admin |
| Escalation config | threads:admin |
| Thread CRUD, messages, participants | threads:write |
| Read states, inbox, unread count | threads:read |
| Flags and escalation | threads:write |
| Entity events | threads:write |