Podium to Helpshift Migration: A Technical Guide
Technical guide to migrating from Podium to Helpshift. Covers API-based ETL, data model mapping, Custom Issue Fields, thread splitting, rate limits, and validation.
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
Podium to Helpshift Migration: A Technical Guide
Tested against Podium API v4 and Helpshift REST API v1.
TL;DR: Podium → Helpshift Migration
Podium is a messaging, reviews, and payments platform for local businesses. Helpshift is a mobile-first, in-app customer service platform built for apps and games. They share almost no structural overlap. Podium Conversations become Helpshift Issues. Podium Contacts map to Helpshift End User Profiles. Podium Locations map to Helpshift Apps or Tags. Reviews, Payments, and Campaigns have no native Helpshift equivalent — archive or discard them. There is no native migration path. A custom API-based ETL pipeline is the only reliable approach for full-fidelity migration. Budget 80–160 engineer-hours for a mid-size dataset (10K–50K conversations) and expect 2–4 weeks elapsed time.
What Is a Podium to Helpshift Migration?
A Podium to Helpshift migration is the process of extracting contacts, conversations, message history, tags, and metadata from Podium's customer interaction platform and loading them into Helpshift as Issues, End User Profiles, and Custom Issue Fields (CIFs) — while preserving conversation context and contact relationships.
This is a data-model transformation, not a platform swap. Podium is an all-in-one customer interaction platform centered on SMS/text messaging, webchat, Google and Facebook review management, text-based payments, and marketing campaigns for local businesses. Helpshift is a mobile-first customer service platform designed for in-app messaging, AI-driven automation, and issue resolution — primarily used by mobile apps, games, and digital-first companies.
The architectures diverge at the foundation. Podium operates on a location-based, multi-channel messaging model where conversations are tied to physical business locations. A customer texts a business, and that thread can remain open indefinitely. Helpshift operates on an app-based, issue-centric model where support interactions ("Issues") belong to specific applications and move through a defined lifecycle (New → In Progress → Resolved → Rejected). No native "click-to-migrate" tool exists between them.
For related platform migrations, see:
- Podium to HappyFox Migration
- Podium to Crisp Migration
- Podium to Freshservice Migration
- Help Desk Data Migration Checklist
Why Teams Move from Podium to Helpshift
The shift is architectural. Teams migrate for these reasons:
- Mobile-first support. Podium is designed for local-business SMS and webchat. When the product is a mobile app or game, Helpshift's native in-app SDK is the right foundation. Helpshift provides SDKs for Android, iOS, Unity, React Native, Unreal Engine, Cocos2dx, and Xamarin.
- In-app messaging over SMS. Podium's messaging is channel-dependent (SMS, email, webchat). Helpshift's messaging is embedded directly inside the app, reducing channel fragmentation and keeping users in-product.
- AI and bot automation. Helpshift's bot engine supports intent-based automation, FAQ suggestions, and Custom Issue Field-driven routing. Podium's automation is limited to review invites, auto-responders, and marketing campaigns.
- Issue-based pricing. Helpshift charges per issue created, not per seat or per location. For high-volume support teams with significant bot deflection (>40% deflection rates are common with well-tuned Helpshift bots), this can be substantially cheaper than Podium's per-location pricing.
- Structured issue management. Helpshift offers Smart Views, SLAs, Automations, Custom Issue Fields, and agent queues. Podium's inbox is conversational but lacks structured ticketing workflows.
- Scale beyond local business. Podium is optimized for businesses with physical locations (dental offices, auto dealers, retail). Teams building global digital products outgrow Podium's location-centric model and need a platform that scales by app and user volume, not by storefront count.
Core Data Model Differences
These platforms share no common schema. Understanding the structural gap is the first step.
| Podium Concept | Helpshift Equivalent | Notes |
|---|---|---|
| Contact | End User Profile (via User Hub) | Name, email, phone map directly. Attributes → Custom Data or CIF. |
| Conversation | Issue | One or more Podium conversations per Helpshift Issue, depending on thread-splitting strategy. |
| Message | Message (within Issue) | Direction (inbound/outbound) preserved. Attachments require separate upload. |
| Location | App or Tag | One Podium Location can map to one Helpshift App, or use Tags for routing. |
| Tag | Tag | Direct mapping. Tags in Helpshift filter Issues into Smart Views. |
| Attribute (Contact) | Custom Issue Field (CIF) or Custom Data | Depends on whether data is per-contact or per-issue. |
| Review | ❌ No equivalent | Archive externally. Helpshift has no review management. |
| Payment | ❌ No equivalent | Archive externally. Helpshift has no payment processing. |
| Campaign | ❌ No equivalent | Archive externally. Helpshift has no marketing automation. |
| Note | No native equivalent | Serialize into issue messages prefixed with " [Internal Note]" or archive externally. |
| Webchat Widget | Web Chat SDK | Requires separate SDK integration — not a data migration item. |
Reviews, Payments, and Campaigns are dead ends. Helpshift has no concept of review management, payment processing, or marketing campaigns. Export these from Podium and archive them in your data warehouse before migration. They cannot be imported into Helpshift.
Migration Approaches
There are four viable paths. Each has different trade-offs around fidelity, effort, and scale.
1. CSV Export + Manual Reconstruction
How it works: Export contacts from Podium via the reporting UI as CSV. Rebuild Helpshift configuration (FAQs, text templates) separately. Accept that historical conversation threading will not be recreated this way. Podium's native contact CSV export includes Name, Phone, Email, Contact Status, Address, Tags, and Date Added. Helpshift's documented CSV imports are for FAQs and text templates, not historical Issue ingestion. (podium.com)
When to use it: Very small datasets (under 1,000 contacts) where conversation history fidelity is not required.
Pros:
- Lowest technical barrier
- No OAuth app setup required for the export side
Cons:
- Podium CSV exports do not include full conversation threading or message bodies
- Helpshift has no self-service CSV import for Issues — you must use the API or send files to Helpshift support
- Attachments, message direction, and timestamps are lost or flattened
- No relationship preservation between contacts and conversations
Scalability: Small datasets only. Breaks down above 1,000 records. Complexity: Low. Risk: False confidence — the CSV looks complete when it is not.
2. API-Based Custom ETL Pipeline
How it works: Build a custom script that extracts data from Podium's REST API v4 (Contacts, Conversations, Messages) and loads it into Helpshift's REST API v1 (Create Issue, Add Message, User Hub Bulk APIs). Store raw extracts in a staging database, transform data to match Helpshift's schema, then load with retry logic and rate limit management.
When to use it: Any migration where conversation history, attachments, and custom fields must be preserved.
Pros:
- Full control over data transformation logic
- Preserves message threading, timestamps, attachments, and direction
- Supports custom field mapping (Podium Attributes → Helpshift CIF)
- Scriptable, repeatable, testable
- Supports staged cutover and delta sync
Cons:
- Requires Podium Developer Account approval (typically 2–5 business days to process)
- Podium API rate limits vary by endpoint — message-related endpoints are capped at 10 requests/minute, while most read endpoints are limited to 300 requests/minute (docs.podium.com)
- Helpshift's GET /issues has a pagination ceiling of 50,000 issues per query window (page × page-size ≤ 50,000)
- Significant engineering effort (80–160 hours for a mid-size dataset)
Scalability: Handles 10K–500K+ records with proper batching and cursor-based pagination. Complexity: High.
Throughput estimates at documented rate limits:
- Podium contact extraction at 300 req/min with 100 contacts/page: ~50K contacts in ~17 minutes
- Podium message extraction at 10 req/min: ~600 messages/hour (the bottleneck — a dataset with 100K messages takes ~167 hours of API time without parallelization)
- Helpshift issue creation (serial, no documented hard limit): plan for ~60–120 issues/minute depending on payload size and Helpshift's throttling response
3. Middleware / iPaaS (Zapier, Make)
How it works: Use Zapier or Make to connect Podium triggers (new message, new contact) to Helpshift actions via custom webhook/API steps. Podium has a Zapier app; Helpshift requires generic HTTP modules. (zapier.com)
When to use it: Ongoing sync of new records after the initial migration. Not suitable for historical data migration.
Pros:
- No code required for basic setups
- Good for post-migration live sync of new contacts
Cons:
- Cannot migrate historical data in bulk
- No native Helpshift integration on Zapier or Make
- Rate limits and per-task pricing make bulk operations impractical
- No attachment handling or conversation threading preservation
Scalability: Individual records only. Not for bulk migration. Complexity: Low for live sync. Useless for historical migration.
4. Managed Migration Service
How it works: Engage a migration service provider who builds and operates the custom ETL pipeline, handles edge cases, runs validation, and manages the cutover.
When to use it: When engineering bandwidth is limited, the dataset is large, or accuracy requirements are non-negotiable.
Pros:
- No internal engineering time consumed
- Handles edge cases (duplicates, malformed data, attachment uploads, rate limit management)
- Includes validation and rollback planning
- Fastest turnaround
Cons:
- External cost (typically $5K–$25K+ depending on dataset size and complexity)
- Requires data access credentials to be shared with the provider
- Quality varies by vendor — confirm support for Podium conversations, notes, tags, locations, and attachments before signing
Scalability: Any dataset size. Complexity: Low for the customer.
Migration Approach Comparison
| Approach | Historical Data | Conversation Threading | Attachments | Scale | Engineering Effort | Main Failure Mode |
|---|---|---|---|---|---|---|
| CSV Export | Partial (contacts only) | ❌ | ❌ | Small | Low | False sense of completeness |
| Custom API ETL | ✅ Full | ✅ | ✅ | Any | High (80–160 hrs) | Poor mapping or retry design |
| Middleware (Zapier/Make) | ❌ | ❌ | ❌ | Individual records | Low | Timeout and audit gaps |
| Managed Service | ✅ Full | ✅ | ✅ | Any | None (customer) | Vendor overpromises |
Recommendations by scenario:
- Small business, < 1K contacts, no history needed: CSV export + manual reconstruction.
- Mid-size, 1K–50K conversations, history matters: Custom API ETL or managed service.
- Enterprise, 50K+ conversations, zero-downtime required: Managed migration service.
- Ongoing sync after migration: Middleware for new records, with API ETL for the initial backfill.
Pre-Migration Planning
Data Audit
Before writing any code, audit what exists in Podium and what needs to move:
- Contacts: Total count, fields populated (name, phone, email, attributes, tags), percentage with valid email addresses
- Conversations: Total count, average messages per conversation, date range, percentage with attachments
- Messages: Total volume, attachment count by MIME type, message types (SMS, email, webchat)
- Locations: Number of Podium Locations, mapping to Helpshift Apps
- Reviews: Count and disposition (archive or discard — no Helpshift target)
- Payments: Count and status (archive — no Helpshift target)
- Campaigns: Active vs. completed (archive — no Helpshift target)
- Custom Attributes: List all contact attributes, map to Helpshift CIF types (single-line text, multi-line text, number, date, dropdown, checkbox)
- Tags: Deduplicate and standardize naming before migration
Define Migration Scope
Not everything should move:
- Move: Active contacts, conversations from the last 12–24 months, open/unresolved conversations, FAQ content.
- Archive externally: Reviews, payments, campaigns, conversations older than 24 months.
- Discard: Test contacts, spam conversations, duplicate records.
Migration Strategy
| Strategy | Description | Best For |
|---|---|---|
| Big Bang | Migrate everything in a single cutover window | Small datasets (< 5K records), weekend migration windows |
| Phased | Migrate by Location or date range in batches | Mid-size datasets, multiple business units |
| Incremental | Migrate historical data first, then sync delta before cutover | Large datasets, zero-downtime requirements |
For most Podium → Helpshift migrations, phased by Location is the safest approach. Each Podium Location maps to a Helpshift App, creating a natural partition boundary.
If you choose incremental, note that Podium webhooks queue events for approximately ten days and time out after five seconds — build your delta collector accordingly. (docs.podium.com)
Timeline Breakdown (Mid-Size Migration, 10K–50K Conversations)
| Phase | Duration | Activities |
|---|---|---|
| Week 1 | Days 1–5 | Data audit, scope definition, Podium Developer Account approval, Helpshift API access request, CIF and App pre-configuration |
| Week 2 | Days 6–10 | Build extract scripts, run full extraction, download attachments to S3/GCS, build staging database |
| Week 3 | Days 11–15 | Transform layer development, test load of 100–500 records to Helpshift sandbox, agent UAT on test batch, fix mapping issues |
| Week 4 | Days 16–20 | Full load, delta sync, record count validation, field-level sampling, cutover, post-migration monitoring |
Add 1–2 weeks for datasets exceeding 50K conversations or requiring multi-app routing configuration.
Data Model & Field-Level Mapping
Podium Contact → Helpshift End User Profile
| Podium Field | Helpshift Field | Type | Notes |
|---|---|---|---|
uid |
identifier |
String | Use as external identifier for deduplication |
name |
name |
String | Direct mapping; trim leading/trailing whitespace |
phone |
phone |
String | Normalize to E.164 format with country code (e.g., +14155551234) |
email |
email |
String | Lowercase, dedupe |
createdAt |
created_at |
DateTime | Preserve original timestamp |
tags [] |
Tags (on Issues) | Array | Tags are per-Issue in Helpshift, not per-user |
attributes{} |
Custom Data or CIF | Key-Value | Map each attribute to a CIF type |
locations [] |
App assignment | Reference | One Location = one App (or use Tags) |
Podium Conversation → Helpshift Issue
| Podium Field | Helpshift Field | Type | Notes |
|---|---|---|---|
conversation.uid |
Custom Issue Field | String | Store Podium UID in a CIF for cross-reference |
conversation.channel.type |
Custom Issue Field | Dropdown | Map to "phone", "email", "webchat" — values must be pre-configured in Dashboard |
conversation.startedAt |
created_at |
DateTime | Set via API on creation |
conversation.assignedUser |
assignee_name |
String | Map Podium user → Helpshift agent |
| Messages | Messages within Issue | Array | Preserve order, direction, timestamps |
Podium Message → Helpshift Message
| Podium Field | Helpshift Field | Notes |
|---|---|---|
message.body |
body |
Direct mapping. 100,000 character limit in Helpshift. |
message.createdAt |
Timestamp | Preserve in message body or metadata. API may not allow timestamp override — prepend to body if needed (e.g., [2023-04-12 14:00 UTC]). |
message.sender |
author |
Map to "agent" or "user" based on sender type. Note: Podium contact and sender fields on the message object are deprecated — resolve identity from contact and conversation records instead. (docs.podium.com) |
| Attachments | Attachment upload | Requires separate API call per attachment. Download during extraction — Podium attachment URLs expire after seven days. (docs.podium.com) |
Thread-Splitting Strategy
Podium conversations can run continuously for months or years. A single SMS thread between a customer and a business location may contain interactions about multiple unrelated topics. You have two design choices:
- 1:1 mapping: One Podium Conversation = one Helpshift Issue. Simpler, but can result in massive Issues that are hard for agents to navigate.
- Time-based chunking: Split a single Podium conversation into multiple Helpshift Issues based on inactivity thresholds (e.g., a 7-day gap creates a new Issue). More complex, but produces cleaner, more actionable Issues in Helpshift.
Choose based on your data. If your average conversation has fewer than 20 messages, 1:1 mapping works. If you have multi-year SMS threads with hundreds of messages, time-based chunking will produce a better agent experience. A common heuristic: if > 25% of conversations exceed 50 messages, implement chunking.
Custom Issue Field types in Helpshift: Single line text (255 chars max), Multi-line text (100,000 chars max), Number, Date, Dropdown, and Checkbox. Plan your Podium attribute mapping around these six types. If a Podium attribute doesn't fit cleanly, use Multi-line text as a catch-all. Helpshift supports up to 20 global custom user fields and 30 app-level custom user fields. CIF dropdown values must be pre-configured in the Helpshift Dashboard — the API will reject payloads containing undefined dropdown values. (support.helpshift.com)
Migration Architecture
Data Flow: Extract → Transform → Load
Podium API v4 Transform Layer Helpshift API v1
───────────── ─────────────── ────────────────
GET /contacts ──► Clean, deduplicate, ──► POST /user-hub/profiles
GET /conversations ──► map fields, restructure ──► POST /{domain}/issues
GET /messages ──► flatten/normalize ──► POST /{domain}/issues/{id}/messages
attachments ──► (multipart upload)
│
Staging DB (PostgreSQL/SQLite)
S3/GCS for attachments
Reconciliation table (Podium UID ↔ Helpshift Issue ID)
Podium API (Source)
- Base URL:
https://api.podium.com/v4/ - Auth: OAuth 2.0 (requires Developer Account approval via developer.podium.com; typical approval time: 2–5 business days) (docs.podium.com)
- Key endpoints:
GET /contacts,GET /conversations,GET /locations, Webhooks for messages - Rate limits: Most read endpoints are limited to 300 requests/minute. Message-related endpoints are capped at 10 requests/minute. Expect HTTP 429 responses on sustained bulk extraction. (docs.podium.com)
- Pagination: Cursor-based. Contact retrieval uses
afterparameter. Supportsupdated_atfilter for delta extraction. - Gotchas: Podium's contact identifiers are polymorphic — the
idparameter can be a conversation UID, email, or phone number depending on context. Standardize on theuidfield during extraction. Podium can auto-merge identical contacts, so detect merged identities before loading to avoid duplicate or split identities in Helpshift. (docs.podium.com) - Attachments: URLs expire after seven days. Download all attachments during the extract phase. (docs.podium.com)
Helpshift API (Target)
- Base URL:
https://api.helpshift.com/v1/{domain}/ - Auth: API Key (from Dashboard → Settings → API). Uses HTTP Basic Auth with API key as username and empty password. (postman.com)
- Key endpoints:
POST /issues(Create Issue),POST /issues/{id}/messages(Add Message), User Hub Bulk APIs - Rate limits: No hard limit documented on Create Issue API, but Helpshift requires an RPM estimate from your Account Manager. Rate limit settings are managed under Settings > APIs. Plan for throttling on high-volume imports.
- Pagination (reads): Default 100 issues/page, max 1,000/page. Hard ceiling of 50,000 issues per query window (page × page-size). Use
created_sinceas a time-based cursor to paginate beyond 50K. - User Hub Bulk APIs: Limit of 10,000 payloads per request for bulk user profile operations.
- Bulk Edit: Supports up to 5,000 issue IDs per request for post-load field updates. (postman.com)
- Archiving: Helpshift automatically archives resolved or rejected issues older than one year. Archived issues are not available through the API or Advanced Search. Do not treat post-go-live API reads as your long-term archive strategy. (support.helpshift.com)
Helpshift API access is gated. The Integrations feature must be explicitly enabled by Helpshift for your account. Contact your Helpshift Account Manager before starting development. Typical enablement time: 1–3 business days, but can take up to a week during peak periods. This can add days to your timeline — request access in Week 1.
Step-by-Step Migration Process
Step 1: Extract Data from Podium
Pull contacts, conversations, and messages via Podium API v4. Handle cursor-based pagination and rate limits.
import requests
import time
import json
import os
PODIUM_BASE = "https://api.podium.com/v4"
HEADERS = {
"Authorization": "Bearer {access_token}",
"Content-Type": "application/json"
}
def extract_contacts(after_cursor=None):
"""Extract all contacts with cursor-based pagination."""
params = {"limit": 100}
if after_cursor:
params["after"] = after_cursor
resp = requests.get(f"{PODIUM_BASE}/contacts", headers=HEADERS, params=params)
if resp.status_code == 429:
retry_after = int(resp.headers.get("Retry-After", 60))
time.sleep(retry_after)
return extract_contacts(after_cursor)
resp.raise_for_status()
data = resp.json()
return data.get("data", []), data.get("metadata", {}).get("cursor", {}).get("after")
def extract_all_contacts():
"""Paginate through all contacts."""
all_contacts = []
cursor = None
while True:
contacts, cursor = extract_contacts(cursor)
all_contacts.extend(contacts)
if not cursor or not contacts:
break
return all_contacts
def download_attachment(url, dest_dir="./attachments"):
"""Download attachment before URL expires (7-day TTL)."""
os.makedirs(dest_dir, exist_ok=True)
filename = url.split("/")[-1].split("?")[0]
filepath = os.path.join(dest_dir, filename)
resp = requests.get(url, stream=True)
if resp.status_code == 200:
with open(filepath, "wb") as f:
for chunk in resp.iter_content(8192):
f.write(chunk)
return filepath
return NoneFor each contact, retrieve their conversation history. Download all attachments to secure storage (e.g., AWS S3, GCS) during extraction — Podium's attachment URLs expire after seven days.
Step 2: Transform Data
Clean, deduplicate, and restructure Podium data into Helpshift's schema. If using time-based thread chunking, apply the splitting logic here.
from datetime import datetime, timedelta
import re
def normalize_phone_e164(phone, default_country="+1"):
"""Normalize phone number to E.164 format."""
if not phone:
return ""
digits = re.sub(r"[^\d+]", "", phone)
if not digits.startswith("+"):
digits = default_country + digits
return digits
def sanitize_text(text):
"""Remove null bytes, invalid UTF-8, and malformed characters."""
if not text:
return ""
# Remove null bytes
text = text.replace("\x00", "")
# Encode and decode to strip invalid UTF-8
text = text.encode("utf-8", errors="ignore").decode("utf-8")
return text
def transform_contact_to_profile(podium_contact):
"""Map Podium Contact to Helpshift User Profile."""
return {
"identifier": podium_contact.get("uid"),
"name": sanitize_text(podium_contact.get("name", "")).strip(),
"email": (podium_contact.get("email") or "").lower().strip(),
"custom_data": {
"podium_uid": podium_contact.get("uid"),
"phone": normalize_phone_e164(podium_contact.get("phone", "")),
"source": "podium_migration"
}
}
def chunk_conversations(messages, max_gap_days=7):
"""Split a long-running conversation into discrete issues by inactivity gap."""
messages.sort(key=lambda x: x['createdAt'])
issues = []
current_issue = []
for i, msg in enumerate(messages):
if i == 0:
current_issue.append(msg)
continue
prev_time = datetime.fromisoformat(messages[i-1]['createdAt'])
curr_time = datetime.fromisoformat(msg['createdAt'])
if (curr_time - prev_time).days > max_gap_days:
issues.append(current_issue)
current_issue = [msg]
else:
current_issue.append(msg)
if current_issue:
issues.append(current_issue)
return issues
def transform_conversation_to_issue(conversation, messages, app_id):
"""Map Podium Conversation to Helpshift Issue."""
first_message = messages[0] if messages else {}
body = sanitize_text(first_message.get("body", "[No message body]"))
return {
"title": f"Migrated: {conversation.get('channel', {}).get('type', 'unknown')} conversation",
"message-body": body,
"author": conversation.get("contact", {}).get("email", ""),
"app-id": app_id,
"tags": ["podium-migration", conversation.get("channel", {}).get("type", "unknown")],
"custom_issue_fields": {
"podium_conversation_uid": {
"type": "singleline",
"value": conversation.get("uid", "")
},
"original_channel": {
"type": "dropdown",
"value": conversation.get("channel", {}).get("type", "sms")
}
}
}Key transformation rules:
- Normalize phone numbers to E.164 format (e.g.,
(415) 555-1234→+14155551234) - Lowercase all email addresses and trim whitespace
- Strip null bytes (
\x00), malformed emojis, and invalid UTF-8 bytes to prevent Helpshift API 400 errors - Resolve Podium's merged contact identities before loading to avoid duplicate users in Helpshift
- Map Podium Locations to Helpshift Apps or Tags based on your routing strategy
- Truncate single-line CIF values to 255 characters; use multi-line text for longer values
Step 3: Load into Helpshift
Create user profiles via Bulk API, then create Issues with messages.
HELPSHIFT_DOMAIN = "your-domain"
HELPSHIFT_API_KEY = "your-api-key"
HS_BASE = f"https://api.helpshift.com/v1/{HELPSHIFT_DOMAIN}"
def bulk_create_user_profiles(profiles_batch):
"""Bulk import user profiles via User Hub API. Max 10,000 per request."""
resp = requests.post(
f"{HS_BASE}/user-hub/bulk/create_core_profiles",
auth=(HELPSHIFT_API_KEY, ""),
json={"payloads": profiles_batch}
)
return resp.json()
def create_issue(issue_payload):
"""Create a single Issue in Helpshift."""
resp = requests.post(
f"{HS_BASE}/issues",
auth=(HELPSHIFT_API_KEY, ""),
data=issue_payload
)
if resp.status_code == 201:
return resp.json().get("id")
elif resp.status_code == 400:
# Common causes: undefined CIF dropdown value, invalid character in body
log_error("create_issue_400", issue_payload, resp.status_code, resp.text)
return None
elif resp.status_code == 429:
time.sleep(int(resp.headers.get("Retry-After", 30)))
return create_issue(issue_payload)
else:
log_error("create_issue", issue_payload, resp.status_code, resp.text)
return None
def add_message_to_issue(issue_id, message_body, author, attachment_path=None):
"""Add a message (with optional attachment) to an existing Issue."""
data = {"message-body": sanitize_text(message_body), "author": author}
files = None
if attachment_path and os.path.exists(attachment_path):
files = {"attachment": open(attachment_path, "rb")}
resp = requests.post(
f"{HS_BASE}/issues/{issue_id}/messages",
auth=(HELPSHIFT_API_KEY, ""),
data=data,
files=files
)
if files:
files["attachment"].close()
return resp.status_code == 201
def log_error(operation, payload, status_code, response_text):
"""Log failed operations for manual remediation."""
with open("migration_errors.jsonl", "a") as f:
f.write(json.dumps({
"operation": operation,
"status_code": status_code,
"response": response_text,
"payload_id": payload.get("custom_issue_fields", {}).get(
"podium_conversation_uid", {}).get("value", "unknown"),
"timestamp": datetime.utcnow().isoformat()
}) + "\n")Issues must be created one at a time via the API — there is no bulk Issue import endpoint. After creation, use the bulk edit endpoint (up to 5,000 issue IDs per request) for status, assignee, and tag updates. (postman.com)
Common Helpshift API error responses:
400 Bad Requestwith"Invalid value for custom issue field"— CIF dropdown value not pre-configured in Dashboard400 Bad Requestwith"Invalid character"— null bytes or invalid UTF-8 in message body401 Unauthorized— API key invalid or Integrations feature not enabled for your account429 Too Many Requests— rate limit exceeded; checkRetry-Afterheader
Step 4: Rebuild Relationships and Enrich
After issues and profiles are created:
- Link each Issue to its End User Profile using the
authoremail or identifier. - Apply Tags from Podium conversations to corresponding Helpshift Issues.
- Map Podium Location → Helpshift App assignments (if using multi-app setup).
- Store the Podium UID ↔ Helpshift Issue ID mapping in a reconciliation table for audit.
- Use bulk edit to set assignees, statuses, and operational flags.
Step 5: Run Delta Sync and Validate
Keep Podium live while you ingest deltas from updated_at queries and webhooks, then cut over once record counts, field samples, and agent UAT pass.
Podium webhook payload structure for delta collection:
{
"event": "message.created",
"data": {
"conversationUid": "conv_abc123",
"message": {
"uid": "msg_xyz789",
"body": "Thanks for the update",
"createdAt": "2024-01-15T09:30:00Z",
"direction": "inbound"
}
},
"timestamp": "2024-01-15T09:30:01Z"
}Note: Podium webhooks time out after 5 seconds — your endpoint must acknowledge quickly and process asynchronously. Undelivered events are queued for approximately 10 days. (docs.podium.com)
Edge Cases & Challenges
Duplicate Records
Podium contacts can have duplicate entries across Locations, and Podium can auto-merge identical contacts. Deduplicate by phone number + email before loading into Helpshift. Helpshift's User Hub does not enforce uniqueness — duplicates will be created silently.
Historical Timestamps
Helpshift's Create Issue API sets created_at to the API call timestamp. If the API does not allow overriding created_at on messages, prepend the original timestamp to the message body:
[Original: 2023-04-12 14:00 UTC] Customer: I need help with my order.
Validate the exact write path with Helpshift support before building your loader.
Multi-Location Conversations
A single Podium contact may have conversations across multiple Locations. In Helpshift, each Location maps to an App. Decide whether to consolidate all conversations under one App or preserve the multi-app structure. Consolidation simplifies agent workflows; multi-app preserves organizational boundaries but requires agents to switch between Apps.
Attachment Migration
Podium attachment URLs expire after seven days — download all files during extraction. Helpshift accepts common MIME types (images, PDFs, text files). Upload each attachment via the multipart form endpoint on POST /issues/{id}/messages. There is no bulk attachment import. Unsupported file types should be converted to plain-text links pointing to your secure storage archive (e.g., [Attachment: video.mp4 — https://s3.amazonaws.com/your-bucket/video.mp4]).
Message Ordering
Helpshift Issues display messages chronologically. Load messages in timestamp order. If you create the Issue with the first message body, then append subsequent messages sequentially, threading is preserved.
Podium's Polymorphic Identifiers
Podium's contact retrieval endpoints accept UUIDs, email addresses, or phone numbers as the id parameter. Standardize on the uid field during extraction to avoid 404 errors from ambiguous lookups.
Custom Issue Field Limits
Helpshift enforces strict types for CIFs — single-line text maxes at 255 characters, dropdown values must be pre-defined in the Dashboard before pushing data via the API. The API will reject payloads containing unrecognized CIF keys or undefined dropdown values with a 400 Bad Request. Do not attempt to map every arbitrary Podium tag into a unique CIF — consolidate tags before migration.
API Failures and Retries
Both APIs will return transient errors. Implement exponential backoff with jitter and a maximum of 5 retries. Log every failed request with the full payload for manual remediation.
import time
import random
def retry_with_backoff(fn, max_retries=5):
for attempt in range(max_retries):
try:
result = fn()
if result:
return result
except Exception as e:
base_wait = 2 ** attempt
jitter = random.uniform(0, base_wait * 0.5)
wait = base_wait + jitter
log_error(f"Retry {attempt + 1}/{max_retries}, waiting {wait:.1f}s", str(e))
time.sleep(wait)
return NoneSearchability After Migration
Helpshift automatically archives resolved or rejected issues older than one year. Archived issues are not available through the API or Advanced Search. If long-term searchability matters, plan for an external archive (data warehouse, Elasticsearch) alongside your Helpshift instance. (support.helpshift.com)
Limitations & Constraints
| Constraint | Detail |
|---|---|
| No native migration path | There is no Podium-to-Helpshift connector, plugin, or import wizard. |
| No review management in Helpshift | All Podium review data must be archived externally. |
| No payment processing in Helpshift | All Podium payment data must be archived externally. |
| Helpshift API access is gated | Integrations must be enabled by Helpshift. Contact your Account Manager (1–3 business days typical). |
| 50K pagination ceiling | Helpshift GET /issues caps at page × page-size ≤ 50,000. Use created_since time-based cursors to work around this. |
| No bulk Issue import | Issues must be created one at a time via the API. No CSV bulk import for Issues. |
| Attachment re-upload required | Attachments must be downloaded from Podium (URLs expire in 7 days) and re-uploaded individually to Helpshift. |
| Tags are per-Issue, not per-Contact | Podium contact-level tags must be migrated as Issue-level tags or Custom Data on the User Profile. |
| CIF dropdown values must be pre-configured | You cannot create dropdown options via the API — set them up in the Dashboard first. API returns 400 for undefined values. |
| Agent mapping | If an agent has left your company, you cannot assign Issues to them without consuming a paid seat. Assign legacy tickets to a generic "Migrated Archive" system user. |
| CIF quantity limits | Helpshift limits the number of Custom Issue Fields you can create. Consolidate tags and attributes before mapping. |
| 1-year auto-archive | Helpshift archives resolved/rejected issues after one year. Archived issues are not available through the API or Advanced Search. |
| 10 req/min on Podium messages | Message extraction is the primary bottleneck. 100K messages ≈ 167 hours of API time without parallelization. |
Validation & Testing
Never execute a full migration without a UAT phase.
Record Count Comparison
| Object | Podium Count | Helpshift Count | Match? |
|---|---|---|---|
| Contacts / End User Profiles | X | X | ✅ / ❌ |
| Conversations / Issues | X | X | ✅ / ❌ |
| Messages (total) | X | X | ✅ / ❌ |
| Attachments | X | X | ✅ / ❌ |
Note: If using thread-chunking, the Helpshift Issue count will exceed the Podium Conversation count. Track the expected expansion ratio (e.g., 10K conversations → 14K issues at 7-day chunking).
Field-Level Validation
Sample 5–10% of migrated records and verify:
- Contact name, email, phone match source
- Conversation message count matches
- Message body content is intact (no truncation, no encoding artifacts)
- Custom Issue Fields contain the correct mapped values
- Tags are applied correctly
- Attachments are accessible and not corrupted
Weight your sample toward long threads (>50 messages) and attachment-heavy conversations — that is where edge cases cluster.
UAT Process
- Migrate a test batch (100–500 records) to a Helpshift sandbox or test App.
- Have support agents review 20+ conversations for accuracy, covering SMS, email, and webchat channels.
- Verify Smart Views, Automations, and routing rules work with migrated data.
- Test that CIF dropdown values render correctly in the agent console.
- Sign off before running the full migration.
Rollback Planning
Helpshift does not have a "bulk delete" API for Issues. If the migration fails:
- Tag all migrated Issues with a
podium-migrationtag for identification. - Use the Bulk Edit API to archive or close migrated Issues (up to 5,000 per request).
- Re-run the migration after fixing the root cause.
- Maintain the reconciliation table (Podium UID ↔ Helpshift Issue ID) to avoid duplicates on re-run.
For a structured QA approach, see Post-Migration QA Checklist.
Post-Migration Tasks
Rebuild Automations
Podium Automations (review invites, campaigns, auto-responders) do not transfer. Rebuild equivalent workflows in Helpshift using:
- Automations: Trigger-based rules for issue routing, tagging, and assignment.
- Smart Views: Filtered queues based on Custom Issue Fields, tags, or issue state.
- Bots: Configure Helpshift's bot builder for common query deflection.
SDK Integration
Helpshift's value is in-app. Deploy the Helpshift SDK in your mobile app or website:
- iOS and Android: SDK X (latest generation). Minimum deployment target: iOS 13+, Android API 21+.
- Web Chat: JavaScript SDK embedded via
<script>tag. - Game engines: Unity plugin (supports Unity 2018.4+), Unreal Engine plugin, Cocos2dx plugin.
- Cross-platform: React Native and Xamarin bindings.
Plan 1–2 sprints (2–4 weeks) for SDK integration and testing. This is a development task separate from the data migration.
User Hub Configuration
If you adopted User Hub for identity management, plan a second workstream for live identity and user-field updates. User Hub uses a server-generated JWT model for authentication and requires SDK or API updates for ongoing user profile synchronization — it is not a one-time import. (support.helpshift.com)
Agent Training
Train your team on Helpshift's Agent Console — it operates differently from Podium's location-based inbox. Cover:
- Smart Views and SLA-driven ticketing queues
- CIF-based routing and bot handoff workflows
- Where migrated Podium data lives in Helpshift (document the field mapping for agents)
- How to identify migrated vs. new Issues (the
podium-migrationtag)
Monitor for Inconsistencies
Run daily spot checks for the first two weeks post-migration:
- Are new issues routing correctly?
- Are migrated conversations accessible and searchable?
- Are Custom Issue Fields populating as expected?
- Are resolved migrated issues approaching the 1-year auto-archive window?
Best Practices
- Back up everything first. Export all Podium data (contacts, conversations, reviews, payments) to your data warehouse before starting. Treat Podium as read-only during migration.
- Pre-configure Helpshift. Create all Custom Issue Fields, dropdown values, Apps, Agent Groups, and Automations in Helpshift before importing data. The API cannot create CIF dropdown options.
- Run test migrations. Always migrate a test batch (100–500 records) to a sandbox App first. Validate before scaling.
- Use idempotent operations. Store Podium UIDs in a Custom Issue Field on every created Issue. This lets you re-run the migration without creating duplicates — check for existing UIDs before creating.
- Run a delta migration. Extract and load historical data up to a specific date. On cutover day, run a delta script that only moves data created after the last extract timestamp. This enables zero-downtime migration.
- Validate incrementally. Don't wait until the end to check counts. Validate after each batch of 1,000–5,000 records.
- Sanitize data. Strip null bytes, malformed emojis, and invalid UTF-8 bytes during transformation to prevent Helpshift API 400 errors.
- Map system IDs. Always store the
Podium_Conversation_IDinside a Helpshift CIF. This makes troubleshooting and future audits significantly easier. - Separate archive from live data. Not all historical data needs to be in the agent's primary queue. Use tags or Smart Views to distinguish migrated archive from active issues.
- Download attachments immediately. Do not defer attachment downloads. Podium's 7-day URL expiry is the single most common cause of data loss in deferred migration strategies.
When to Use a Managed Migration Service
DIY migration makes sense when you have dedicated engineering bandwidth and a small, clean dataset. It stops making sense when:
- Dataset exceeds 50K conversations. The pagination and rate-limit management alone consumes weeks of engineering time. At Podium's 10 req/min message rate limit, extracting 500K messages takes ~830 hours of API time.
- Attachments are critical. Downloading, storing, and re-uploading thousands of files with retry logic is tedious and error-prone.
- You need zero downtime. Coordinating an incremental migration with a delta sync requires infrastructure your team may not have.
- Engineering time has a higher-value alternative. Every hour spent on migration scripting is an hour not spent on product.
- Your Podium tenant has many locations. Multi-location routing and identity resolution adds complexity that scales poorly with DIY scripts.
Two source-specific gotchas make DIY riskier than it looks: Podium can auto-merge identical contacts (creating split identities in the destination), and Podium attachment URLs expire after seven days (breaking any delayed download strategy).
The hidden costs of DIY include: mapping workshops (4–8 hours), retry logic development (8–16 hours), data QA (8–16 hours), agent UAT coordination (4–8 hours), cutover communications, rollback planning, and re-creating routing and automation in Helpshift (8–24 hours).
ClonePartner has completed 1,500+ migrations across help desk platforms, including complex multi-location and multi-app scenarios structurally similar to Podium → Helpshift. We handle the ETL pipeline, edge cases, validation, and cutover — implementing intelligent thread-chunking, managing all API rate limits, and ensuring your agents log into Helpshift with complete, readable customer histories on day one. See how we run migrations.
Sample Data Mapping Reference
| Podium Field | Helpshift Object | Helpshift Field | Transform Notes |
|---|---|---|---|
contact.uid |
User Profile | identifier |
Preserve as immutable key for deduplication |
contact.name |
User Profile | name |
Trim whitespace, sanitize UTF-8 |
contact.phone |
User Profile | phone |
Normalize to E.164 (e.g., +14155551234) |
contact.email |
User Profile | email |
Lowercase, dedupe, trim |
conversation.uid |
Issue (CIF) | podium_conversation_uid |
Store in a single-line CIF (255 char max) |
conversation.channel.type |
Issue (CIF) | original_channel |
Dropdown CIF — pre-configure values: sms, phone, email, webchat |
location.name |
Issue (CIF or Tag) | store_location |
Dropdown CIF or Tag depending on routing needs |
message.body |
Issue Message | body |
Direct mapping; sanitize; 100K char limit |
message.createdAt |
Issue Message | created_at |
Prepend to body if API restricts timestamp override |
message.sender |
Issue Message | author |
Map to Agent ID or Customer ID; use conversation/contact records (deprecated sender field) |
tags [].label |
Issue | tags |
Normalize naming conventions; lowercase, hyphenate |
note.body |
Issue Message or Archive | — | Prefix as " [Internal Note]" or archive externally |
Frequently Asked Questions
- Can I migrate Podium data to Helpshift using CSV?
- Only partially. Podium's native CSV export covers contacts but not full conversation threading or message bodies. Helpshift has no self-service CSV import for Issues — you must use the REST API or send files to Helpshift support. For any migration requiring conversation history, a custom API-based ETL pipeline is required.
- What Podium data cannot be migrated to Helpshift?
- Reviews, payments, and marketing campaigns have no equivalent in Helpshift. These must be exported from Podium and archived externally (data warehouse, cloud storage) before migration. Helpshift is a support platform, not a reputation or payment management tool.
- Does Helpshift have a bulk import API for issues?
- No. Helpshift Issues must be created one at a time via the POST /issues API. There is no bulk issue import endpoint. The User Hub Bulk APIs allow importing up to 10,000 user profiles per request, and the Bulk Edit endpoint supports up to 5,000 issue IDs per request for post-load updates.
- How long does a Podium to Helpshift migration take?
- For a mid-size dataset (10K–50K conversations), expect 2–4 weeks elapsed time and 80–160 engineer-hours for a custom API-based migration. A managed migration service can compress this significantly. Small datasets under 1,000 records can be migrated in under a week.
- How should I handle Podium's continuous SMS threads in Helpshift?
- You have two options. A 1:1 mapping (one Podium Conversation = one Helpshift Issue) works for short conversations. For multi-year SMS threads with hundreds of messages, use time-based chunking — split conversations into separate Issues based on inactivity thresholds (e.g., a 7-day gap creates a new Issue) to produce cleaner, more actionable tickets.


