PlatformXeDocs
Get API Key

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.

SDKInstallNamespace
TypeScriptnpm install @caldera/platformxe-sdkclient.threads
Pythonpip install platformxeclient.threads
Gogo get github.com/calderax/platformxe-goclient.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:

#MethodDescription
1createChannelCreate a new conversation channel
2listChannelsList all channels
3updateChannelUpdate channel configuration
4getEscalationConfigGet channel escalation configuration
5setEscalationConfigSet channel escalation configuration
6createThreadCreate a thread with participants
7listThreadsList threads with filters
8getThreadGet thread detail
9updateThreadUpdate thread subject or metadata
10closeThreadClose a thread
11reopenThreadReopen a closed thread
12sendMessageSend a participant message
13listMessagesList messages (visibility-filtered)
14sendSystemMessageSend a system message
15editMessageEdit message content
16deleteMessageSoft-delete a message
17addParticipantAdd a participant to a thread
18removeParticipantRemove a participant
19updateParticipantUpdate participant display name, avatar, or mute state
20markReadMark a thread as read
21getReadStatesGet read states for all participants
22inboxGet inbox for a participant
23unreadCountGet total unread count
24flagMessageFlag a message for review
25listFlagsList flags for a thread
26listFlagsAcrossThreadsList flags across all threads
27reviewFlagApprove or reject a flag
28escalateThreadManually escalate a thread
29entityEventForward entity status change

Scopes required

Method groupScope
Channel CRUDthreads:admin
Escalation configthreads:admin
Thread CRUD, messages, participantsthreads:write
Read states, inbox, unread countthreads:read
Flags and escalationthreads:write
Entity eventsthreads:write