Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.tybritelabs.com/llms.txt

Use this file to discover all available pages before exploring further.

The MessagingService class (accessed via client.messaging) handles real-time customer ↔ store communication. It manages threaded conversations, message delivery, read state, and full thread lifecycle management.

Security Model

Messaging threads carry sensitive customer PII — order inquiries, complaints, contact details, and uploaded attachments. To prevent one customer from reading or mutating another customer’s conversation, every customer-facing messaging endpoint requires a signed customer session token (xAuthToken) issued by client.auth. The gateway enforces ownership through one of three layered gates:
GateApplied ToCheck
gateByCustomerIdList / create operationsThe customer_id supplied in the query or request body must match the customer_id claim on the bearer token.
gateByThreadIdThread-scoped reads & writesThe worker resolves thread.customer_id from the database, then asserts it equals the token’s customer_id. Applied to getThread, updateThread, getThreadMessages, sendMessage, and markThreadRead.
gateByMessageIdPer-message edit & deleteThe worker resolves the target message and asserts sender_type = 'customer' and sender_id = auth.customerId. A customer can only edit or delete messages they personally authored.
Obtain a customer session via client.auth.login(...) or client.auth.verifyOtp(...) and pass customerSession.access_token as xAuthToken on every call below.
Each Thread object returned by listThreads and getThread includes an unread_count_customer field. Sum these client-side to compute a customer’s total unread count — no separate endpoint is needed.

Thread Discovery & Filtering

listThreads

Retrieve message threads with advanced server-side filtering. Pinned threads are automatically returned at the top of the result set.
const { threads, pagination } = await client.messaging.listThreads({
  xAuthToken: customerSession.access_token, // Must match customerId claim
  customerId: 'cust_123',
  status: 'active',           // active | resolved | closed | escalated | pending
  priority: 'high',           // low | normal | high | urgent
  archived: false,            // Filter by archive state
  unread: true,               // Only show threads with unread messages
  limit: 20,
  fields: 'id,subject,status,is_pinned,unread_count_store'
});
Gated by gateByCustomerId — the customerId query parameter must match the customer_id claim on xAuthToken.

Computing total unread

Each thread returned by listThreads includes unread_count_customer. Sum these client-side to display a “new messages” badge:
const { threads } = await client.messaging.listThreads({
  customerId: customer.id,
  xAuthToken: customerSession.access_token
});

const totalUnread = threads.reduce((sum, t) => sum + (t.unread_count_customer || 0), 0);
To fetch only threads with unread messages, pass ?unread=true as a filter.

getThread

Retrieve high-level metadata for a single thread.
const thread = await client.messaging.getThread({
  xAuthToken: customerSession.access_token, // Must own this thread
  id: 'thread-uuid-123',
  fields: 'subject,priority,status,is_muted,is_archived'
});
Gated by gateByThreadId — the worker resolves thread.customer_id and asserts it equals the token’s customer_id claim.

updateThread 🔒

Update thread state including status, priority, or lifecycle flags.
Requires a Secret Key (for merchant lifecycle changes) or a customer xAuthToken belonging to the thread owner (for customer-driven actions like muting or archiving their own conversation). Customer requests are additionally gated by gateByThreadId.
await client.messaging.updateThread({
  xAuthToken: customerSession.access_token, // Required when called with a publishable key
  id: 'thread-uuid-123',
  requestBody: {
    status: 'resolved',
    priority: 'normal',
    archived: true,
    pinned: false,
    muted: true
  }
});

markThreadRead 🔒

Marks all customer messages in the thread as read and resets the store unread count to 0.
await client.messaging.markThreadRead({
  xAuthToken: customerSession.access_token, // Must own this thread
  id: 'thread-uuid-123'
});
Gated by gateByThreadId. The id must be a valid UUID — malformed values return 400.

Message Operations

getThreadMessages

Fetch paginated history for a thread. Deleted messages are automatically excluded.
ParamTypeDescription
limitnumberMax messages per page (default 50).
cursorstringBase64-encoded created_at for next page.
orderstringasc (oldest first) or desc (newest first).
const { messages, pagination } = await client.messaging.getThreadMessages({
  xAuthToken: customerSession.access_token, // Must own this thread
  id: 'thread-uuid-123',
  limit: 50,
  order: 'desc' // Get newest first
});
Gated by gateByThreadId — only the thread’s owning customer (or a Secret Key holder) can read its messages.

sendMessage 🔒

Reply to an existing conversation.
await client.messaging.sendMessage({
  xAuthToken: customerSession.access_token, // Must own this thread
  id: 'thread-uuid-123',
  requestBody: {
    message: "We've received your request and are looking into it."
  }
});
Gated by gateByThreadId. Returns 201 with the newly persisted message body on success.

editMessage 🔒

Update the content of an existing message. Sets is_edited: true.
await client.messaging.editMessage({
  xAuthToken: customerSession.access_token, // Must be the original sender
  id: 'msg-uuid-456',
  requestBody: {
    message_content: "Correction: The delivery will arrive by 5 PM today."
  }
});
Gated by gateByMessageId — the worker asserts message.sender_type = 'customer' and message.sender_id = auth.customerId. Customers cannot edit store or system messages.

deleteMessage 🔒

Soft-deletes a message. The message is hidden from list responses but retained for audit trails.
await client.messaging.deleteMessage({
  xAuthToken: customerSession.access_token, // Must be the original sender
  id: 'msg-uuid-456'
});
Gated by gateByMessageId — same ownership check as editMessage. Soft delete only; the row is retained for audit.

createConversation 🔒

Initiate a new support ticket with an initial message.
const { thread, message } = await client.messaging.createConversation({
  xAuthToken: customerSession.access_token, // Required when body.customer_id is supplied
  requestBody: {
    customer_id: 'cust_123', // Must match token claim
    customer_name: 'Jane Doe',
    customer_email: 'jane@example.com',
    subject: "Missing Item - Order #8821",
    message: "My package arrived but the headphones were missing.",
    priority: 'high',
    thread_type: 'order_inquiry',
    order_id: 'order-uuid-abc' // Optional context
  }
});
Gated by gateByCustomerId whenever body.customer_id is supplied — the value must match the customer_id claim on xAuthToken. Returns 201 with both the new thread and the initial message.

Data Schemas

Thread Structure

FieldTypeDescription
iduuidUnique thread identifier.
subjectstringThread title/topic.
statusenumactive, resolved, closed, escalated, pending.
priorityenumlow, normal, high, urgent.
is_archivedbooleanHidden from main list.
is_mutedbooleanNotifications disabled.
is_pinnedbooleanAlways at top of list.
unread_count_storenumberMessages awaiting store reply.

Message Structure

FieldTypeDescription
iduuidUnique message identifier.
message_contentstringThe text body.
sender_typeenumcustomer, store, system.
is_editedbooleanWhether content was changed.
is_deletedbooleanWhether message is soft-deleted.

Performance Tip: When building a chat UI, use getThreadMessages with order: 'desc' to load the most recent activity first, then use the next_cursor to load history as the user scrolls up.

Response Codes

CodeMeaning
200Success on reads, updateThread patches, and markThreadRead.
201Success on createConversation and sendMessage — a new resource was persisted.
400Invalid request body, or a malformed UUID supplied to markThreadRead (or any thread/message ID path param).
401Missing or invalid xAuthToken, or missing/invalid API key.
403Customer token does not own the target thread or message (gate failure).
404Thread or message not found (or filtered out by store scoping).
429Rate limit exceeded.
500Internal server error — safe to retry idempotent reads.