Thread Lifecycle
Automatic thread closing, archiving, retention, and anonymization based on channel rules.
Threads follow a lifecycle: OPEN, CLOSED, ARCHIVED, and eventually deleted or anonymized. The lifecycle is driven by rules you configure on each channel. PlatformXe evaluates these rules automatically -- you do not need to build lifecycle logic into your application.
Lifecycle states
OPEN ──> CLOSED ──> ARCHIVED ──> Deleted / Anonymized
^ |
└───────────┘ (reopen)
| State | Description |
|---|---|
OPEN | Active conversation. Messages can be sent and received |
CLOSED | Conversation ended. Can be reopened. Messages are read-only unless reopened |
ARCHIVED | Permanently closed. Cannot be reopened. Retained for audit purposes |
| Deleted | Thread and all child records permanently removed from the database |
| Anonymized | PII scrubbed from messages and participants; thread structure preserved |
Lifecycle rules
Lifecycle rules are configured on a channel and apply to all threads in that channel.
{
"lifecycleRules": {
"autoClose": {
"onEntityStatus": ["CHECKED_OUT", "CANCELLED"],
"afterInactivityDays": 14
},
"autoArchive": {
"afterClosedDays": 30
},
"retention": {
"deleteAfterDays": 365,
"anonymizeAfterDays": 90
}
}
}
Set lifecycle rules when creating or updating a channel:
PUT /api/v1/threads/channels/:channelId
{
"lifecycleRules": {
"autoClose": {
"onEntityStatus": ["CHECKED_OUT", "CANCELLED"],
"afterInactivityDays": 14
},
"autoArchive": {
"afterClosedDays": 30
},
"retention": {
"deleteAfterDays": 365,
"anonymizeAfterDays": 90
}
}
}
Auto-close on entity status
When an entity status change matches a value in onEntityStatus, the associated thread is automatically closed.
| Field | Type | Description |
|---|---|---|
onEntityStatus | string[] | Entity statuses that trigger auto-close (e.g., CHECKED_OUT, CANCELLED, COMPLETED) |
This is triggered by the entity event API. When your application notifies PlatformXe of a status change, the lifecycle service evaluates the channel's rules.
Auto-close on inactivity
Threads with no new messages for longer than afterInactivityDays are automatically closed.
| Field | Type | Description |
|---|---|---|
afterInactivityDays | number | Days of inactivity before auto-close. Uses lastMessageAt or createdAt if no messages exist |
Inactivity checks run during lifecycle processing (see below).
Auto-archive
Closed threads are automatically archived after the configured period.
| Field | Type | Description |
|---|---|---|
afterClosedDays | number | Days after closing before the thread is archived |
Retention: hard delete
Threads in ARCHIVED or CLOSED state older than the configured threshold are permanently deleted along with all child records (messages, participants, read states, flags, escalations, audit entries).
| Field | Type | Description |
|---|---|---|
deleteAfterDays | number | Days after last update before hard deletion |
Hard deletion is irreversible. All thread data including messages, participants, flags, and escalation records are permanently removed. Ensure your retention period meets any regulatory requirements before configuring this setting.
Retention: anonymization
Threads in ARCHIVED or CLOSED state older than the configured threshold have PII scrubbed:
- Message content is replaced with
[redacted] - Message metadata is cleared
- Participant display names are set to
Anonymous - Participant avatar URLs are cleared
- Participant external IDs are replaced with anonymized values
| Field | Type | Description |
|---|---|---|
anonymizeAfterDays | number | Days after last update before PII is scrubbed |
Anonymization preserves the thread structure for audit purposes while removing personally identifiable information.
Entity event API
Your application notifies PlatformXe of entity status changes via the entity event endpoint. The lifecycle service evaluates the channel's auto-close rules against the new status.
POST /api/v1/threads/entity-event
Request body
| Field | Type | Required | Description |
|---|---|---|---|
channelSlug | string | Yes | Channel slug to evaluate |
entityId | string | Yes | Entity ID of the thread |
event | string | Yes | Event type (e.g., STATUS_CHANGED) |
newStatus | string | No | New status value to evaluate against lifecycle rules |
Response
{
"success": true,
"data": {
"action": "closed",
"threadId": "th-001",
"systemMessage": "This conversation has been closed because the booking status changed to CHECKED_OUT."
}
}
| Value | Description |
|---|---|
"closed" | Thread was auto-closed based on the entity status |
"none" | No lifecycle action was taken (status did not match any rule) |
Lifecycle processing endpoint
Inactivity-based auto-closes, auto-archives, and retention rules are evaluated by the lifecycle processing endpoint. This endpoint is designed to be called by a scheduled job (cron).
POST /api/v1/threads/lifecycle/process
Scope: threads:admin
This endpoint processes all three lifecycle operations in sequence for the organization:
- Inactivity closes -- finds OPEN threads with no activity beyond the threshold and closes them.
- Auto-archives -- finds CLOSED threads past the archive threshold and transitions them to ARCHIVED.
- Retention -- finds ARCHIVED/CLOSED threads past the delete or anonymize threshold and processes them.
Response
{
"success": true,
"data": {
"closed": 3,
"archived": 7,
"deleted": 1,
"anonymized": 5
}
}
Set up a daily cron job to call this endpoint. Lifecycle processing is idempotent -- calling it multiple times is safe. Each run processes only threads that have crossed their threshold since the last run.
System messages
You can configure system messages that are automatically posted when lifecycle transitions occur.
{
"lifecycleRules": {
"autoClose": {
"onEntityStatus": ["CHECKED_OUT"]
},
"systemMessages": {
"onThreadClosed": "This conversation has been closed because the {entityType} status changed to {closedReason}."
}
}
}
Template variables:
{closedReason}-- the entity status or reason that triggered the close{entityType}-- the channel's entity type
Examples
Configure lifecycle rules on a channel
curl
curl -X PATCH https://api.platformxe.com/api/v1/threads/channels/ch-booking \
-H "Content-Type: application/json" \
-H "x-api-key: pxk_live_your_api_key_here" \
-d '{
"lifecycleRules": {
"autoClose": {
"onEntityStatus": ["CHECKED_OUT", "CANCELLED"],
"afterInactivityDays": 14
},
"autoArchive": {
"afterClosedDays": 30
},
"retention": {
"deleteAfterDays": 365,
"anonymizeAfterDays": 90
}
}
}'
TypeScript SDK
import { PlatformXe } from '@caldera/platformxe-sdk';
const client = new PlatformXe({ apiKey: 'pxk_live_your_api_key_here' });
await client.threads.updateChannel('ch-booking', {
lifecycleRules: {
autoClose: {
onEntityStatus: ['CHECKED_OUT', 'CANCELLED'],
afterInactivityDays: 14,
},
autoArchive: { afterClosedDays: 30 },
retention: {
deleteAfterDays: 365,
anonymizeAfterDays: 90,
},
},
});
Python SDK
from platformxe import PlatformXe
client = PlatformXe(api_key="pxk_live_your_api_key_here")
client.threads.update_channel("ch-booking", {
"lifecycleRules": {
"autoClose": {
"onEntityStatus": ["CHECKED_OUT", "CANCELLED"],
"afterInactivityDays": 14
},
"autoArchive": {"afterClosedDays": 30},
"retention": {
"deleteAfterDays": 365,
"anonymizeAfterDays": 90
}
}
})
Forward an entity event
curl
curl -X POST https://api.platformxe.com/api/v1/threads/entity-event \
-H "Content-Type: application/json" \
-H "x-api-key: pxk_live_your_api_key_here" \
-d '{
"channelSlug": "booking",
"entityId": "BK-2026-00451",
"event": "STATUS_CHANGED",
"newStatus": "CHECKED_OUT"
}'
TypeScript SDK
const result = await client.threads.entityEvent({
channelSlug: 'booking',
entityId: 'BK-2026-00451',
event: 'STATUS_CHANGED',
newStatus: 'CHECKED_OUT',
});
console.log(result.action);
// "closed"
Go SDK
import platformxe "github.com/calderax/platformxe-go"
client := platformxe.NewClient("pxk_live_your_api_key_here")
result, err := client.Threads.EntityEvent(platformxe.EntityEventInput{
ChannelSlug: "booking",
EntityID: "BK-2026-00451",
Event: "STATUS_CHANGED",
NewStatus: "CHECKED_OUT",
})
Run lifecycle processing
curl -X POST https://api.platformxe.com/api/v1/threads/lifecycle/process \
-H "x-api-key: pxk_live_your_api_key_here"
Webhook events
| Event | Trigger | Payload |
|---|---|---|
thread.closed | Thread auto-closed by lifecycle rules | Thread ID, reason, channel |
thread.archived | Thread auto-archived | Thread ID, channel |
thread.retention.deleted | Threads permanently deleted | Channel ID, thread IDs, count |
thread.retention.anonymized | Threads anonymized | Channel ID, thread IDs, count |