Thena to LiveChat Migration: The Complete Technical Guide
Technical guide to migrating from Thena to LiveChat/HelpDesk: API endpoints, data mapping, Slack identity resolution, and cutover strategy.
Planning a migration?
Get a free 30-min call with our engineers. We'll review your setup and map out a custom migration plan — no obligation.
Schedule a free call- 1,500+ migrations completed
- Zero downtime guaranteed
- Transparent, fixed pricing
- Project success responsibility
- Post-migration support included
Thena to LiveChat Migration: The Complete Technical Guide
TL;DR: Thena is a Slack-native, AI-first B2B ticketing platform. LiveChat is a real-time website chat platform backed by HelpDesk for async ticketing. No native import path exists between them — the data models are structurally different, and Thena's Slack-centric request format must be transformed into HelpDesk's event-driven ticket model (a flat, chronologically ordered array of typed events). Your historical data must be imported into HelpDesk (not LiveChat) via POST /v1/importedTickets. The main engineering challenges are Slack user identity resolution, Slack mrkdwn-to-HTML conversion, and working within Thena's 60 req/min standard-tier API rate limit.
Published: January 2025. Last reviewed: June 2025 against Thena Platform API v2, HelpDesk API v1 (POST /v1/importedTickets), and Text Platform Agent Chat API v3.6.
Migrating from Thena to LiveChat means leaving a Slack-first, AI-driven B2B support platform and moving to a website-visitor-facing live chat system with a separate ticketing backend. The platforms serve fundamentally different use cases, and the migration is entirely API-driven — there is no built-in connector, no CSV import on HelpDesk that preserves conversation threading, and no third-party tool that supports Thena as a source.
This guide covers the exact API endpoints, data-model mapping, rate-limit math, error responses, attachment handling, and cutover logic you need. If you've already read our LiveChat vs Thena comparison, this picks up where the "migration path" section ended.
What This Migration Actually Involves
Thena organizes support around Requests — conversations captured from Slack, email, MS Teams, web chat, and Discord. Each Request holds threaded messages, AI-generated metadata (title, summary, tags, sentiment, urgency), custom fields, SLA data, account context, and escalation details. Thena's data model is deeply tied to Slack: messages include thread structures, emoji reactions, Slack user IDs, and channel context. Thena also exposes first-class accounts and customer contacts, giving it a true B2B account-centric model.
LiveChat (by Text, Inc.) is a real-time chat platform for website visitors. Its legacy built-in ticketing was sunset in January 2025 and replaced by HelpDesk (helpdesk.com), a separate product that handles all async ticketing. This means your Thena data has two possible targets:
- HelpDesk (
POST /v1/importedTickets) — the primary target for all ticket and request history. This is where the bulk of your Thena data goes. - LiveChat (Agent Chat API) — only relevant for future live chat sessions, not historical data import.
For nearly every Thena-to-LiveChat migration, HelpDesk's Imported Tickets API is your actual target.
API version note: Text's Agent Chat API v3.6 removed Create Customer and List Customers, which were present in the legacy v3.5 docs. Do not build bulk customer pre-seeding against the old API surface. Build against the current stable behavior. (platform.text.com)
The practical split:
- Thena tickets, comments, tags, assignees, priorities, status history, attachments → land in HelpDesk
- Future website chat flows → land in LiveChat
- Thena accounts and contacts → keep in your CRM, mirror selectively into HelpDesk custom fields
- Thena workflows, Slack routing, AI agent configs, internal thread behavior → redesign from scratch. Do not expect a 1:1 port.
Thena Data Model: What You're Extracting
Thena's API exposes Requests via GET https://bolt.thena.ai/rest/v2/requests. Each Request object contains:
| Thena Field | Type | Notes |
|---|---|---|
id |
string | Unique request identifier |
status |
enum | OPEN, ASSIGNED, CONVERTED_TO_TICKET, custom sub-statuses |
sub_status |
string | Custom workflow states |
ai_metadata.title |
string | AI-generated title |
ai_metadata.summary |
string | AI-generated summary |
ai_metadata.tags [] |
array | AI-generated tags |
ai_metadata.urgency |
string | Low, Medium, High, etc. |
ai_metadata.sentiment |
string | Neutral, Positive, Negative |
custom_fields_v2 [] |
array | User-defined custom fields |
feedback [] |
array | CSAT feedback entries |
escalation_type |
string | e.g., automatic |
external_links [] |
array | Links to external tools (Jira, Linear, etc.) |
Conversations are fetched separately via GET /rest/v2/requests/{requestId}/conversations. This returns the full message thread — including Slack message content, sender info, timestamps, and attachments.
Thena also provides a search API (GET https://platform.thena.ai/v1/search/tickets) that supports filter_by, sort_by, page, per_page, and include_fields parameters. This is useful for date-window delta exports and targeted extraction. (docs.thena.ai)
Rate limit constraint: Thena's standard-tier API allows 60 requests per minute per user, org, and IP. Extracting 5,000 requests with their conversations requires at minimum ~167 minutes of API time (5,000 list items + 5,000 conversation fetches = 10,000 calls ÷ 60/min). Plan for a multi-hour extraction window, or negotiate Enterprise-tier custom limits before starting.
HelpDesk Data Model: What You're Loading Into
HelpDesk's POST /v1/importedTickets endpoint is purpose-built for migrations. It accepts a complete ticket — subject, requester, tags, priority, custom fields, team assignment, and a chronologically ordered array of typed events — in a single API call. (api.helpdesk.com)
HelpDesk authentication: Credentials use HTTP Basic Auth. The format is license_id:personal_access_token, base64-encoded. Generate a Personal Access Token (PAT) from the Developer Console. Your license ID is the numeric identifier visible in the HelpDesk URL after login. The resulting header is: Authorization: Basic base64("your_license_id:your_PAT").
Key constraints on the import endpoint:
- First event must be type
message— its date becomes the ticket's creation date - Events must be chronologically ordered and all dates must be in the past
- Agent-authored messages require
agentID,agentName, andisPrivateparameters — messages missing these fields are treated as requester-authored. This is where bad migrations silently corrupt authorship. - The last
statusevent determines the final ticket state - Attachments require a 3-step transaction flow: create transaction → upload files → reference
transactionIDin the ticket payload - Transaction IDs expire after 24 hours; if an attachment upload partially fails mid-transaction, the entire transaction must be abandoned and restarted from step 1 — partially uploaded files cannot be recovered or completed after expiry
- All uploaded attachments must be referenced in the ticket payload or the transaction fails
HelpDesk ticket statuses: open, pending, onhold, solved, closed.
HelpDesk priorities: -10 (low), 0 (medium), 10 (high), 20 (urgent).
HelpDesk custom fields are limited to four types: singleLine (120 chars), multiLine (1,000 chars), date, and url.
HelpDesk API Error Responses
Understanding what POST /v1/importedTickets returns on failure is essential for debugging. The endpoint returns standard HTTP status codes with a JSON error body:
| Scenario | HTTP Status | Error Body (example) |
|---|---|---|
| Events array out of chronological order | 422 Unprocessable Entity |
{"error": "Events must be in chronological order"} |
First event is not type message |
422 Unprocessable Entity |
{"error": "First event must be of type message"} |
agentID references a non-existent agent |
422 Unprocessable Entity |
{"error": "Agent not found"} |
agentID present but agentName missing |
422 Unprocessable Entity |
{"error": "agentName is required when agentID is provided"} |
| Transaction ID expired or invalid | 400 Bad Request |
{"error": "Transaction not found or expired"} |
| Attachment referenced but not uploaded to transaction | 400 Bad Request |
{"error": "Attachment not found in transaction"} |
| Missing or malformed auth header | 401 Unauthorized |
{"error": "Unauthorized"} |
| Rate limit exceeded | 429 Too Many Requests |
{"error": "Too many requests"} with Retry-After header |
If agentID is omitted from a message that should be agent-authored, HelpDesk does not return an error — it silently treats the message as requester-authored. This is the most common silent corruption in Thena migrations. Validate authorship in your post-load checks, not just record counts.
Field Mapping: Thena Request → HelpDesk Imported Ticket
Not everything maps cleanly. Here is the core transformation logic:
| Thena Source | HelpDesk Target | Transformation |
|---|---|---|
ai_metadata.title or first message |
subject |
Use AI title if present; fall back to first 120 chars of first message |
| Request creator email | requester.email |
Slack user ID → email lookup required if source is Slack |
| Request creator name | requester.name |
May need Slack API call to resolve display name |
status / sub_status |
events [].type: "status" |
See status mapping below |
ai_metadata.urgency |
priority |
Low → -10, Medium → 0, High → 10 |
ai_metadata.tags [] |
tagIDs [] |
Pre-create tags in HelpDesk via POST /v1/tags, then reference UUIDs |
custom_fields_v2 [] |
customFields |
Pre-create via POST /v1/customFields; note char limits |
| Conversations | events [] (type: message) |
Flatten Slack threads into chronological events; convert mrkdwn to HTML |
feedback [] (CSAT) |
N/A | No import path — HelpDesk has its own post-ticket rating system |
external_links [] |
N/A | Append to first message body or store in a url custom field |
ai_metadata.summary |
N/A | Prepend to ticket body or store in a multiLine custom field |
Status Mapping
Thena's statuses don't map 1:1 to HelpDesk. Thena uses free-form sub-statuses alongside core states:
def map_status(thena_status: str, thena_sub_status: str | None) -> str:
status_map = {
"OPEN": "open",
"ASSIGNED": "open",
"IN_PROGRESS": "pending",
"WAITING_ON_CUSTOMER": "pending",
"WAITING_ON_INTERNAL": "onhold",
"CONVERTED_TO_TICKET": "solved",
"CLOSED": "closed",
"RESOLVED": "solved",
}
# Check sub_status first for more granular mapping
if thena_sub_status and thena_sub_status.upper() in status_map:
return status_map[thena_sub_status.upper()]
return status_map.get(thena_status.upper(), "open")Preserve Thena's original status as a tag. Create a HelpDesk tag like thena-status:waiting-on-customer so agents can filter by the original workflow state after migration. This costs nothing and saves debugging time.
Step-by-Step Migration Process
Step 1: Extract Thena Data
Generate an API key from Thena Dashboard → Organization Settings → Security and Access. All requests use the x-api-key header.
# Fetch all requests (paginated)
curl -X GET "https://bolt.thena.ai/rest/v2/requests?limit=100&page=1&sort_order=asc" \
-H "x-api-key: YOUR_THENA_API_KEY"For each request, fetch conversations:
curl -X GET "https://bolt.thena.ai/rest/v2/requests/{requestId}/conversations" \
-H "x-api-key: YOUR_THENA_API_KEY"Also extract supporting entities:
- Users:
GET https://platform.thena.ai/v1/users— for agent/requester identity mapping - Accounts:
GET https://bolt.thena.ai/rest/v2/accounts— for company/org context - Custom fields:
GET https://bolt.thena.ai/rest/v2/custom-fields— for field schema
Store raw JSON locally or in a staging database before any transformation. Run a second pass for tickets updated after the first snapshot to catch changes during extraction.
Step 2: Resolve Slack User Identities
This is the most common failure point. HelpDesk requires a valid email address to create a customer profile. Thena, however, often stores users by their Slack ID — especially guest users in Slack Connect channels where email visibility is restricted by the external organization.
- Extract Thena users and identify any missing the
emailfield. - Query the Slack API using a bot token with the
users:read.emailscope. Callusers.infoorusers.profile.getto resolve Slack IDs to email addresses. - Budget for Slack rate limits — Tier 3/4 endpoints allow ~50–100 requests per minute.
- Handle unresolvable users. If a Slack workspace restricts email sharing or the user is deactivated, generate a fallback email like
unknown-{slack_user_id}@migration.internaland tag these tickets for manual review. Document this mapping so agents understand the placeholder emails in historical tickets.
Step 3: Convert Slack mrkdwn to HTML
Thena conversations originating from Slack use Slack's proprietary mrkdwn format. HelpDesk expects plain text or HTML in message events. This conversion must be handled before building ticket payloads.
Recommended approach: Use the slack-mrkdwn npm package (Node.js) or implement the conversion directly. Python users can use slack-to-html as a starting point, but verify output against real Slack payloads — neither library handles all edge cases.
Core conversion patterns with tested regex:
import re
def slack_mrkdwn_to_html(text: str, user_map: dict) -> str:
"""
Convert Slack mrkdwn to HTML for HelpDesk import.
user_map: dict mapping Slack user IDs to display names, e.g. {"U12345": "Jane Smith"}
"""
# Resolve user mentions: <@U12345> → Jane Smith (or fallback to Slack ID)
def resolve_mention(match):
uid = match.group(1)
return f"@{user_map.get(uid, uid)}"
text = re.sub(r'<@([A-Z0-9]+)>', resolve_mention, text)
# Named links: <https://example.com|Click Here> → <a href="...">Click Here</a>
text = re.sub(
r'<(https?://[^|>]+)\|([^>]+)>',
r'<a href="\1">\2</a>',
text
)
# Bare URLs: <https://example.com> → <a href="...">https://example.com</a>
text = re.sub(
r'<(https?://[^>]+)>',
r'<a href="\1">\1</a>',
text
)
# Bold: *text* → <b>text</b> (must not match mid-word)
text = re.sub(r'(?<!\w)\*([^*\n]+)\*(?!\w)', r'<b>\1</b>', text)
# Italic: _text_ → <i>text</i>
text = re.sub(r'(?<!\w)_([^_\n]+)_(?!\w)', r'<i>\1</i>', text)
# Strikethrough: ~text~ → <s>text</s>
text = re.sub(r'(?<!\w)~([^~\n]+)~(?!\w)', r'<s>\1</s>', text)
# Inline code: `code` → <code>code</code>
text = re.sub(r'`([^`\n]+)`', r'<code>\1</code>', text)
# Code blocks: ```code``` → <pre><code>code</code></pre>
text = re.sub(r'```([^`]+)```', r'<pre><code>\1</code></pre>', text)
# Newlines → <br>
text = text.replace('\n', '<br>')
return textKnown edge cases to test:
- Emoji: Slack encodes custom emoji as
:emoji-name:— these pass through as-is and render as text in HelpDesk. Unicode emoji (actual codepoints) pass through correctly. - Channel references:
<#C12345|general>→ convert to#generalusingre.sub(r'<#[A-Z0-9]+\|([^>]+)>', r'#\1', text). - Bold inside code blocks: Slack does not render formatting inside backtick spans — ensure your code block regex runs before bold/italic conversions, or use a two-pass approach.
- Multi-byte Unicode / surrogate pairs: Slack payloads are UTF-8. HelpDesk accepts UTF-8. No re-encoding is needed, but validate that your JSON serializer does not escape non-ASCII characters as
\uXXXXsequences, as this produces garbled output in the HelpDesk UI.
Step 4: Provision HelpDesk Scaffolding
Before loading any tickets, set up the target:
- Create teams via
POST /v1/teams— map from Thena's groups/boards - Create agents via
POST /v1/agents— match by email address. Note: HelpDesk does not allow changing an agent's email after creation; if it changes, you must create a new agent account. Finalize your assignee map before the backfill. - Create tags via
POST /v1/tags— each tag requires ateamID - Create custom fields via
POST /v1/customFields— note theapiKeyyou assign; you'll reference it in ticket payloads
Step 5: Transform and Load Tickets
For each Thena request, build a HelpDesk imported ticket payload. This is the most engineering-heavy phase.
Flatten threads: Thena captures Slack threads as nested conversations. HelpDesk expects a flat chronological event array. Merge parent + reply messages into a single ordered sequence. Consider prefixing replies with [Thread reply] to preserve context.
Example transformed payload:
{
"subject": "Cannot access dashboard after SSO migration",
"teamIDs": ["team-uuid"],
"requester": {
"email": "customer@acme.com",
"name": "Jane Smith"
},
"tagIDs": ["tag-uuid-1", "tag-uuid-2"],
"assignment": {
"team": { "ID": "team-uuid" },
"agent": { "ID": "agent-uuid" }
},
"priority": 10,
"customFields": {
"thena-request-id": "req_abc123",
"original-account": "Acme Corp"
},
"events": [
{
"date": "2025-03-15T10:30:00Z",
"type": "message",
"message": {
"text": "I can't log into the dashboard since the SSO migration yesterday.",
"html": "<p>I can't log into the dashboard since the SSO migration yesterday.</p>"
}
},
{
"date": "2025-03-15T11:15:00Z",
"type": "message",
"message": {
"text": "We're looking into this now. Can you try clearing your browser cache?",
"html": "<p>We're looking into this now. Can you try clearing your browser cache?</p>"
},
"agentID": "agent-uuid",
"agentName": "Alex Support",
"isPrivate": false
},
{
"date": "2025-03-15T14:00:00Z",
"type": "status",
"status": "solved"
}
]
}Post to HelpDesk, constructing auth as base64("license_id:PAT"):
curl -X POST "https://api.helpdesk.com/v1/importedTickets" \
-H "Authorization: Basic $(echo -n 'YOUR_LICENSE_ID:YOUR_PAT' | base64)" \
-H "Content-Type: application/json" \
-H "User-Agent: thena-migration/1.0" \
-d @ticket_payload.jsonAlways include the User-Agent header. HelpDesk's docs note that requests missing it may be blocked by intermediary services.
Step 6: Handle Attachments
Attachments are the silent killers of migration timelines. Thena references files hosted in Slack, and those URLs are authenticated — HelpDesk cannot download them directly.
HelpDesk requires a three-step transaction flow for attachments:
# 1. Create import transaction
curl -X POST "https://api.helpdesk.com/v1/importedTickets/transactions" \
-H "Authorization: Basic $(echo -n 'YOUR_LICENSE_ID:YOUR_PAT' | base64)"
# Response: { "transactionID": "uuid" }
# 2. Upload attachment files
curl -X POST "https://api.helpdesk.com/v1/importedTickets/attachments" \
-H "Authorization: Basic $(echo -n 'YOUR_LICENSE_ID:YOUR_PAT' | base64)" \
-F "transactionID=uuid" \
-F "attachments=@screenshot.png"
# Response: [{ "attachmentID": "att-uuid" }]
# 3. Include transactionID in the importedTickets POSTThe full pipeline:
- Read the
file_urlfrom the Thena message payload. - Download the file using an authenticated Slack token. Use a User Token (not a Bot Token) if files were uploaded by human users — Bot Tokens cannot access files uploaded by humans in some workspace configurations.
- Upload to HelpDesk via the transaction flow above.
- Reference the attachment IDs in the ticket payload's event
filesarray.
Partial failure behavior: If any individual file upload fails mid-transaction (network error, file too large, unsupported MIME type), the transaction is not automatically invalidated — but the missing attachment ID will cause the final POST /v1/importedTickets call to return 400 Bad Request with {"error": "Attachment not found in transaction"}. You must then abandon the transaction and restart from step 1. Transaction IDs expire after 24 hours regardless of upload state.
If you skip attachment handling entirely, every historical screenshot and log file shared in Slack will return a 404 when agents view imported tickets.
Rate Limits and Throughput Planning
| Platform | Rate Limit | Practical Throughput |
|---|---|---|
| Thena (Standard) | 60 req/min per user/org/IP | ~50 req/min with backoff |
| Thena (Enterprise) | Custom | Negotiate before migration |
| HelpDesk | 1,000 req/10 min per license | ~90 req/min sustained |
| Slack (user lookup) | Tier 3: ~50 req/min | ~40 req/min with backoff |
For a dataset of 3,000 Thena requests with conversations and attachments:
- Extraction: 3,000 (list pages) + 3,000 (conversations) + ~1,000 (Slack lookups) = ~7,000 calls → ~140 minutes at Thena's standard rate
- Loading: 3,000 ticket imports + ~1,500 attachment transactions = ~4,500 calls → ~50 minutes at HelpDesk's rate
- Total estimated runtime: ~3–4 hours for a clean run
Implement exponential backoff on 429 responses. Both Thena and HelpDesk return rate-limit headers (Retry-After on HelpDesk, X-RateLimit-Reset on Thena) — read and honor them rather than using fixed sleep intervals.
Idempotency is your responsibility. HelpDesk's import API does not natively prevent duplicate ticket creation. Store the Thena request ID as a HelpDesk custom field and maintain a local mapping (SQLite works fine) of thena_request_id → helpdesk_ticket_id. If your script crashes mid-migration, this map lets you resume without creating duplicates.
Migration Complexity Decision Matrix
Use this matrix to estimate scope before committing to an approach:
| Factor | Low Complexity | Medium Complexity | High Complexity |
|---|---|---|---|
| Request volume | < 500 | 500–5,000 | > 5,000 |
| Slack threading depth | Flat (≤ 2 levels) | Moderate (3–5 levels) | Deep (> 5 levels) |
| Attachment volume | None or minimal | < 500 files | > 500 files or large files |
| Slack identity resolution | All users have email | < 10% missing emails | > 10% missing or restricted |
| Custom field complexity | ≤ 5 fields, simple types | 6–15 fields, mixed types | > 15 fields or long-text values |
| Data freshness requirement | Point-in-time snapshot OK | Short delta window (< 1 day) | Live sync required during cutover |
| Validation strictness | Count-level checks | Field-level sampling | Full record-by-record audit |
Low complexity: One engineer, 2–4 days scripting plus 1 day validation. Medium complexity: One to two engineers, 1–2 weeks including edge-case handling and delta sync. High complexity: Dedicated team, 3–6 weeks — primarily driven by Slack identity resolution at scale, attachment pipeline, and validation coverage.
Edge Cases and Failure Modes
AI metadata loss. Thena's AI-generated fields (summary, sentiment, urgency source, category) have no structural equivalent in HelpDesk. Decide upfront: discard them, store them in custom fields (limited to singleLine at 120 chars and multiLine at 1,000 chars), or append them as a formatted header block in the ticket body.
CSAT and feedback data. Thena's feedback [] array doesn't map to HelpDesk's rating system. HelpDesk has its own rating object (good/neutral/bad), but it's tied to post-ticket rating requests — there's no way to import historical ratings. Export this data separately for analytics continuity.
SLA policies. Thena's SLA configurations don't transfer. HelpDesk doesn't have a native SLA engine in its API — recreate time-based rules using HelpDesk's Rules automation post-migration.
Custom field truncation. HelpDesk's singleLine custom fields cap at 120 characters and multiLine at 1,000 characters. If your Thena custom fields hold longer values, they will be silently truncated — HelpDesk does not return a warning or error. Audit field lengths before loading; values longer than the cap should be stored in ticket body text instead.
Platform events for delta sync. Thena's platform events are useful for a short cutover window. They provide eventId for idempotency and support retries with exponential backoff. However, Thena documents a 256KB payload limit — large comment payloads are truncated to "Payload too large. Use API instead." Use events for change detection, then re-fetch the full ticket or comment through the API. (docs.thena.ai)
HelpDesk post-import validation via webhooks. HelpDesk's webhook system can be used to confirm that imported tickets are being created correctly in near-real-time. Configure a webhook on the ticket_created event (POST /v1/webhooks) pointing to a local listener during your test runs. Compare the webhook payload's ticketID, subject, requester.email, and priority against your source data to catch transformation errors before running the full backfill.
Silent authorship corruption. As noted above: omitting agentID from agent-authored events does not produce an error. The message imports successfully but is attributed to the requester. This produces incorrect conversation histories that cannot be fixed after import without deleting and re-importing the ticket. Add an authorship validation step to your pre-import checks.
What Won't Survive the Move
Be explicit with stakeholders about what doesn't transfer:
- Slack channel associations — Thena's channel-to-request mapping has no HelpDesk equivalent
- AI agent configurations — Thena's AI studio, MCP integrations, and workflow automations are platform-specific
- Account-level B2B context — Thena's account model (account → contacts → requests) doesn't map to HelpDesk's flat requester model. Keep this data in your CRM.
- Historical CSAT scores — no import path exists
- Workflow automations — rebuild from scratch using HelpDesk Rules
- Escalation chains — manual recreation required
- Real-time Slack sync — LiveChat's Slack integration is notification-only, not bidirectional
- AI-generated summaries and sentiment scores — no structured equivalent in HelpDesk; store in custom fields with character-limit caveats or discard
Cutover Strategy and Validation
A low-risk runbook:
- Freeze config drift. Export Thena field definitions, statuses, priorities, tags, and workflow references before anyone "cleans up" the source.
- Create the target skeleton. Stand up HelpDesk teams, tags, custom fields, agents, and LiveChat widget settings before loading history.
- Backfill historical tickets into HelpDesk. Store the original Thena request ID in a custom field for reconciliation.
- Run a delta sync. Re-export tickets updated after the first snapshot and upsert them before cutover.
- Cut over entry points. Switch the website widget to LiveChat. If Slack Connect is your current front door, set channels to read-only or deploy an auto-responder directing customers to the new support channel.
- Leave Thena read-only for a short window. Keep it available for audit until sample checks pass.
Validation Checklist
Do not stop at record counts. Check:
- Ticket counts match by status, team, and week
- First message dates and last update dates are correct
- Agent-authored messages display correct agent names (not requester-attributed)
- Attachments download without errors from HelpDesk ticket view
- Public vs. private message visibility is preserved (
isPrivateflag) - Custom field values are not truncated (singleLine: 120 chars, multiLine: 1,000 chars)
- Thena request IDs stored in custom fields are unique — no duplicates
- mrkdwn conversion output is valid HTML — no raw
<@U12345>tokens or unconverted*bold*patterns visible in HelpDesk - Unicode characters and emoji render correctly in HelpDesk ticket view
- Spot-check 20+ Slack-heavy tickets. These are where data-model mismatches surface.
- Webhook-confirmed ticket counts match your local
thena_request_id → helpdesk_ticket_idmap
LiveChat plan consideration: LiveChat's Starter plan currently offers only 60-day chat history. If long-term historical access matters, you need Team plan or above for unlimited chat history. (livechat.com)
The Two-Migration Frame
The mistake is treating Thena → LiveChat as a single import job. It's two migrations with one cutover: historical records into HelpDesk, future conversations into LiveChat. These require separate scripts, separate API credentials, and separate validation passes.
For source-side export details, see our guide on how to export data from Thena. For a deeper look at the HelpDesk import API, the Zendesk to LiveChat migration guide covers that side in more detail.
Frequently Asked Questions
- Can I import Thena data directly into LiveChat?
- No. LiveChat handles real-time chat sessions, not historical ticket imports. LiveChat's legacy ticketing was sunset in January 2025. Historical Thena data must be imported into HelpDesk via the POST /v1/importedTickets endpoint.
- How do I handle Slack users without email addresses during the migration?
- HelpDesk requires an email address for every requester. Query the Slack API (users.info with users:read.email scope) to resolve Slack IDs to emails. For users whose workspaces restrict email visibility or who are deactivated, generate a fallback email like unknown-{slack_user_id}@migration.internal and tag those tickets for manual review.
- Can I preserve original timestamps from Thena in HelpDesk?
- Yes. HelpDesk's imported tickets API lets you set historical dates on events — the first message's date becomes the ticket creation date. Events must be chronologically ordered and all dates must be in the past. LiveChat chat events, by contrast, use server-generated timestamps that cannot be overridden.
- Can I preserve Thena's AI-generated metadata in HelpDesk?
- Not natively. HelpDesk has no fields for AI summaries, sentiment, or urgency sources. Store them in HelpDesk custom fields (singleLine: 120 chars, multiLine: 1,000 chars), append them to the ticket body, or discard them.
- How long does a Thena to LiveChat migration take?
- For 3,000 requests with conversations: roughly 3-4 hours of API runtime. Thena's 60 req/min rate limit is the bottleneck. Add development time for scripting, Slack user resolution, and validation — typically 3-7 days of total engineering effort.

