PlatformXeDocs
Get API Key

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)
StateDescription
OPENActive conversation. Messages can be sent and received
CLOSEDConversation ended. Can be reopened. Messages are read-only unless reopened
ARCHIVEDPermanently closed. Cannot be reopened. Retained for audit purposes
DeletedThread and all child records permanently removed from the database
AnonymizedPII 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.

FieldTypeDescription
onEntityStatusstring[]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.

FieldTypeDescription
afterInactivityDaysnumberDays 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.

FieldTypeDescription
afterClosedDaysnumberDays 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).

FieldTypeDescription
deleteAfterDaysnumberDays 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
FieldTypeDescription
anonymizeAfterDaysnumberDays 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

FieldTypeRequiredDescription
channelSlugstringYesChannel slug to evaluate
entityIdstringYesEntity ID of the thread
eventstringYesEvent type (e.g., STATUS_CHANGED)
newStatusstringNoNew 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."
  }
}
ValueDescription
"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:

  1. Inactivity closes -- finds OPEN threads with no activity beyond the threshold and closes them.
  2. Auto-archives -- finds CLOSED threads past the archive threshold and transitions them to ARCHIVED.
  3. 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

EventTriggerPayload
thread.closedThread auto-closed by lifecycle rulesThread ID, reason, channel
thread.archivedThread auto-archivedThread ID, channel
thread.retention.deletedThreads permanently deletedChannel ID, thread IDs, count
thread.retention.anonymizedThreads anonymizedChannel ID, thread IDs, count