Skip to content

Freshdesk to Pylon Migration: The CTO's Technical Guide (2026)

A CTO-level guide to migrating from Freshdesk to Pylon — covering API rate limits, object mapping, attachment handling, and zero-downtime cutover approaches.

Raaj Raaj · · 18 min read
Freshdesk to Pylon Migration: The CTO's Technical Guide (2026)
TALK TO AN ENGINEER

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

Migrating from Freshdesk to Pylon is not a settings import. You are moving from a traditional, email-first ticketing system to an AI-native, Slack-first B2B support platform. The data models are fundamentally different, the API rate limits are asymmetric, and there is no native import path between them.

This guide covers the exact object mapping, rate-limit math, extraction ceilings, attachment handling, and migration approaches you need before writing a single line of code. If you need a source-side deep dive first, see How to Export Data from Freshdesk: Methods, API Limits & Mapping.

Why B2B Teams Move from Freshdesk to Pylon

The shift is architectural, not cosmetic. Freshdesk is a mature, highly configurable helpdesk built around email-centric ticket queues with a flat contact-and-company structure. Pylon is purpose-built for B2B support where the primary conversation happens in shared Slack channels and Microsoft Teams — not email portals. (developers.freshdesk.com)

Teams migrate for three reasons:

  • Channel alignment. B2B customers live in Slack Connect and Teams. Pylon integrates natively with these channels, plus Discord, WhatsApp, and in-app chat, so customers never leave their workspace. Freshdesk treats chat as a bolt-on to an email-first architecture.
  • Account-centric support model. Pylon ties every Issue to an Account, giving agents full customer context — health scores, CRM data, renewal risk — directly in the support view. Freshdesk can achieve this with custom apps and marketplace add-ons, but the experience requires significant configuration.
  • AI-native workflows. Pylon's AI handles triage, routing, knowledge gap detection, and draft replies out of the box. Freshdesk's Freddy AI capabilities are available as paid add-ons (Copilot, AI Agent sessions), with sessions that expire monthly.

If you are comparing Pylon to other migration targets, our Zendesk to Pylon Migration: The CTO's Technical Guide covers the Zendesk-specific data model differences.

Core Architecture Differences

Dimension Freshdesk Pylon
Primary object Ticket Issue
Contact model Contacts + Agents (separate APIs) Contacts + Users (unified)
Company model Companies Accounts (with subaccounts, partner accounts)
Conversation model Conversations (replies, notes) Messages
Custom fields On tickets, contacts, companies On issues, contacts, accounts
Statuses Open, Pending, Resolved, Closed (+ custom) new, waiting_on_you, waiting_on_customer, on_hold, closed (+ custom)
Priority Low, Medium, High, Urgent (integers 1–4) low, medium, high, urgent (strings)
Attachments content_url in ticket/conversation JSON (temporary S3 URLs) attachment_urls array on issues
Auth model Basic Auth (API key) Bearer token
Rate limits 200–700 req/min account-wide (by plan) 10–60 req/min (by endpoint)
Pagination Page-based (100/page, 300-page ceiling) Cursor-based

This asymmetry is the source of most migration failures. You can extract data from Freshdesk roughly 3–10x faster than you can write it to Pylon, so any pipeline needs a buffer or write-side throttle.

Migration Approaches: CSV vs. API vs. Managed Service

There are five ways to move your data. Choosing the wrong one leads to broken threads, orphaned attachments, or weeks of wasted engineering time.

1. Native CSV Export → Manual Import

How it works: Export tickets, contacts, and companies from Freshdesk's admin UI as CSV files. Restructure the data, then use Pylon's API to bulk-import. Freshdesk also offers a full Account Export (Admin → Account → Export) that generates an XML dump including archived tickets. (support.freshdesk.com)

When to use it: Fewer than 1,000 tickets, minimal custom fields, no attachments to preserve.

Limitations: Freshdesk's CSV export does not include full conversation histories, attachments, or archived tickets. You get a flat snapshot — ticket metadata without thread context. Pylon has no CSV import UI, so you still need the API to load data.

Complexity: Low to extract. Medium to load.

2. API-Based Custom ETL Pipeline

How it works: Write a script (Python, Node.js) that extracts data via Freshdesk's v2 REST API, transforms it to match Pylon's schema, and loads it via Pylon's REST API. For enterprise programs or regulated environments, land the data into a staging database first for better observability, dead-letter handling, audit logs, and rerun safety. (developers.freshdesk.com)

When to use it: You have engineering bandwidth, need full control over transformation logic, and want repeatable delta syncs.

Pros:

  • Full control over field mapping and transformation
  • Can handle custom fields, attachments, and conversation threading
  • Repeatable for delta syncs
  • Staging-database approach gives the strongest audit trail and rollback posture

Cons:

  • Freshdesk's List All Tickets API is capped at 30,000 tickets (300 pages × 100 records). Larger accounts require date-range segmentation or the Account Export feature.
  • Pylon's issue creation endpoint is rate-limited to 10 requests per minute. A 10,000-ticket migration with multiple API calls per ticket takes significant write time.
  • Attachments require separate HTTP GET requests to Freshdesk's temporary S3 URLs, then re-upload before referencing in Pylon.

Complexity: High.

3. Third-Party Automated Migration Tools

How it works: Tools like Help Desk Migration or Import2 offer pre-built connectors for Freshdesk. Import2's workflow runs sample-to-full: connect source and destination, run a sample migration, inspect results, edit mappings, then execute. Their docs note that system configuration (users, reports, templates, automations, workflows) is not migrated, and validation errors on a parent record can block linked records. (help.import2.com)

When to use it: Only if a connector for Pylon exists and your data structure is straightforward. As of mid-2026, dedicated Freshdesk-to-Pylon connectors are extremely limited.

Limitations: Standard migration tools often fail on knowledge base articles, complex custom fields, multi-level account hierarchies, inline images, conversation threading, and CSAT data. They typically do not offer delta syncs, forcing a hard weekend cutover.

For a comparison of automated tools vs. managed services, see ClonePartner vs Help Desk Migration: 2026 Price & Feature Comparison.

Complexity: Medium (when connectors exist).

4. Middleware Platforms (Zapier, Make)

How it works: Use prebuilt connectors to create or update Pylon objects from events. Zapier exposes Pylon actions such as Create Account and Create Account Activity. Make currently lists Pylon as a community connector that talks to official API endpoints. (zapier.com)

When to use it: Ongoing sync after the bulk backfill is complete. Not for replaying years of ticket history.

Limitations: Connector throttling, task costs, and community-adapter stability make these unviable for historical bulk loads. Migrating 100,000+ tickets through Zapier is financially and technically unworkable.

Complexity: Low for simple syncs. Unviable for bulk migration.

5. Managed Migration Service

How it works: A specialized team handles the full ETL pipeline — extraction, transformation, loading, validation, and delta sync — on your behalf.

When to use it: More than 10,000 tickets, complex custom fields, attachments that must be preserved, or zero tolerance for downtime.

Pros:

  • No engineering distraction from product work
  • Handles rate-limit orchestration, attachment re-hosting, and relationship integrity
  • Supports parallel operation and delta sync for zero-downtime cutover

Complexity: Low (for your team). Scalability: High.

Approach Comparison

Criteria CSV Export Custom ETL Auto Tool Middleware Managed Service
Engineering effort Low High Low-Medium Low None
Conversation history Partial
Attachments ✅ (complex) Partial
Custom fields Partial Partial Partial
Scale (50k+ tickets) Risky Depends
Delta sync DIY Partial
Zero downtime DIY

Scenario recommendations:

  • Small business, <1,000 tickets, low engineering bandwidth: Use a self-service tool if official Freshdesk-to-Pylon support exists. Otherwise, go straight to a managed service.
  • Enterprise, attachments, deep history, or account hierarchy: API-based ETL or managed service. CSV and iPaaS are false economies here.
  • Bulk migration + ongoing sync: Run the bulk move via API or managed service, then keep deltas alive with a small worker or iPaaS flow.
  • Zero-downtime requirement: Stage historical imports, validate, then cut channels over after delta sync reaches zero.

Pre-Migration Planning & Data Audit

Before touching any API, audit your Freshdesk instance. Freshdesk archives closed inactive tickets after 120 days, and the standard UI ticket export excludes archived history and full conversations. Decide up front what is in scope. (support.freshdesk.com)

Data inventory checklist:

  • Total ticket count (check if >30,000 — you will hit the pagination ceiling)
  • Total contacts and companies
  • Custom ticket fields (names, types, picklist values)
  • Custom contact/company fields
  • Ticket tags and categories
  • Conversation count per ticket (affects API call volume)
  • Attachment volume (count and total size in GB)
  • Knowledge base articles and folder structure
  • Automations, SLAs, and business hours (must be rebuilt manually)
  • Canned responses / saved replies

What to leave behind:

  • Spam and deleted tickets
  • Duplicate contacts (merge before migration)
  • Test tickets from implementation
  • Time-tracking entries (Pylon has no equivalent)
  • Historical SLA metrics (not transferable as native SLA objects)
  • Leads and Opportunities from Freshsales or your CRM — these are a separate migration; sync only the context Pylon needs through its CRM layer

Migration strategy:

  • Big bang: Migrate everything in one pass over a weekend. Works for fewer than 10,000 tickets.
  • Phased by channel: Migrate email tickets first, then move Slack/Teams channels to Pylon. Lets you validate before going all-in.
  • Parallel operation with delta sync: Run both systems simultaneously. New tickets go to Pylon; historical data migrates in the background. A final delta pass catches anything created during migration. This is the zero-downtime approach and what we recommend for most B2B teams.
Warning

Disable all Freshdesk automations and notification rules before starting any data export. Bulk API reads can trigger webhooks, which consume your rate limit and can send unintended emails to customers.

Data Model & Object Mapping: Tickets to Issues

This is where migrations break. Freshdesk and Pylon use fundamentally different schemas, and raw field copy is the wrong strategy. Map the semantic next-action state, not just labels.

Object-Level Mapping

Freshdesk Object Pylon Object Notes
Company Account Pylon supports subaccounts and partner accounts. Preserve source company ID as external_id.
Contact Contact Link to Accounts via account_id. Match by email.
Agent User Pylon uses roles (Admin, Member, etc.). Manual rebuild.
Ticket Issue Core mapping — see field table below.
Conversation (reply/note) Message Each reply becomes a Message on the Issue. Preserve internal vs. public visibility strictly.
Ticket attachment Attachment URL Must be re-hosted; Freshdesk S3 URLs are temporary.
Knowledge Base article Knowledge Base article Separate API; requires collection structure. Migrate as a separate workstream.
Tags Tags Direct mapping; create tags in Pylon first. Normalize casing before load.
Custom fields Custom fields Must pre-create in Pylon with matching slugs.
Groups Teams Manual rebuild.
Canned responses Macros Manual rebuild.
SLAs SLAs Manual rebuild.
Automations Triggers Manual rebuild.
Parent/child companies Subaccounts Use when roll-up reporting matters.
Agencies / consultants Partner accounts Avoid duplicating cross-customer contacts.

Field-Level Mapping: Tickets → Issues

Freshdesk Field Pylon Field Transformation
id external_id Store for cross-reference and idempotent reruns
subject title Direct
description / description_text body_html Freshdesk provides HTML; Pylon accepts HTML. Parse for inline images.
status (2=Open, 3=Pending, 4=Resolved, 5=Closed) state (new, waiting_on_you, waiting_on_customer, on_hold, closed) Integer → string mapping (see below)
priority (1=Low, 2=Med, 3=High, 4=Urgent) priority (low, medium, high, urgent) Integer → string
requester_id contact_id Lookup by email from pre-migrated contacts
responder_id assignee_id Lookup by email from pre-created users
company_id account_id Lookup from pre-migrated accounts
tags tags Array → array
created_at created_at RFC3339 format
custom_fields.cf_* custom_fields [{slug, value}] Map cf_ prefix fields to Pylon slugs
attachments [].attachment_url attachment_urls Download from Freshdesk S3, re-host, pass URLs
Info

Pylon's issue creation API accepts a created_at timestamp (RFC3339), which lets you preserve original ticket creation dates. If omitted, the current time is used — destroying your historical timeline.

Status Mapping

Freshdesk uses integer status codes. Pylon uses string states:

Freshdesk Status Code Pylon State
Open 2 new
Pending 3 waiting_on_customer
Resolved 4 closed
Closed 5 closed
Custom statuses 6+ Map to Pylon custom statuses (create before import)

Pylon's issue workflow supports five core status categories. Custom statuses are supported but must be created before import. Closed issues can reopen on new activity — keep that in mind when mapping Resolved vs. Closed.

Freshdesk allows unlimited custom statuses (codes 6+). Pylon supports custom statuses within its status categories. That is usually enough for support operations, but it is not a 1:1 substitute for every bespoke Freshdesk taxonomy.

Warning

Custom objects and schema constraints: Pylon has a streamlined schema. If you rely heavily on Freshdesk Custom Objects or integrations that simulate custom objects (e.g., asset tracking), those patterns don't transfer directly. Flatten this data into standard Issue attributes or Account-level fields. Push CRM data back to the CRM rather than forcing it into the support platform.

Warning

Multi-company contacts: Freshdesk can associate contacts with multiple companies. Pylon's contact creation centers on one account reference at a time. Decide early whether to collapse those relationships, duplicate contacts selectively, or model the intermediary as a partner account. (support.freshdesk.com)

Custom Field Type Mapping

Freshdesk contact and company fields expose types like custom_text, custom_paragraph, custom_checkbox, custom_number, custom_dropdown, custom_phone_number, custom_url, and custom_date. Pylon custom fields support Text, Number, Decimal, Select, Multi-select, Boolean, Date, User, URL, Datetime, and Formula. Build from the overlap, and normalize picklist values before load so Select fields do not fail on unmapped values. (developers.freshdesk.com)

Freshdesk API Constraints & Attachment Handling

This is where DIY scripts fail. If your custom script breaks here, see Helpdesk Migration Failed? The Engineer's Rescue Guide.

Rate Limits by Plan

Freshdesk enforces account-wide rate limits plus endpoint-specific sublimits. The account-wide limit is shared with every other integration, app, and webhook running on that Freshdesk instance. Even failed requests (400, 404) count against the limit.

Freshdesk Plan Account-Wide Rate Limit Ticket List Sublimit
Trial 50/min
Growth 200/min ~20 list calls/min
Pro 400/min ~40 list calls/min
Enterprise 700/min ~70 list calls/min

Monitor usage via response headers: X-Ratelimit-Total, X-Ratelimit-Remaining, X-Ratelimit-Used-CurrentRequest. A 429 Too Many Requests response includes a Retry-After header — queue your calls and obey it. (developers.freshdesk.com)

The 30,000-Ticket Ceiling

Freshdesk's List All Tickets endpoint (/api/v2/tickets) is capped at 300 pages × 100 records = 30,000 tickets maximum. The endpoint also returns only the last 30 days by default. If your account has more tickets, you must:

  1. Segment by date range using the updated_since parameter to pull batches under the ceiling.
  2. Use Freshdesk's Account Export (Admin → Account → Export), which generates a full XML dump of all data including archived tickets.
  3. Use the Search API (/api/v2/search/tickets) for targeted extraction only — it is capped at 10 pages (300 results per query), uses URL-encoded query syntax with case-sensitive field names, and is unsuitable for bulk export.

Attachment Extraction

Freshdesk attachments are not embedded in the ticket JSON. The API response includes an attachments array where each file has a content_url pointing to a temporary S3 URL. To migrate attachments:

  1. Fetch the ticket with include=conversations to get conversation attachments. Note: this returns only up to 10 conversations per ticket and consumes extra API cost. For tickets with more replies, use the dedicated /api/v2/tickets/{id}/conversations endpoint with pagination.
  2. Download each file from the content_url via authenticated GET request.
  3. Re-host the file (S3 bucket, GCS, or any publicly accessible URL).
  4. Pass the hosted URL into Pylon's attachment_urls array when creating the issue.

Freshdesk's S3 URLs are temporary. If you extract ticket metadata today but download attachments next week, the URLs may have expired. Treat every attachment as a separate download-and-reupload problem, and do it during extraction, not later.

Danger

Inline images will break. Freshdesk inline images in HTML ticket descriptions use Freshdesk-hosted URLs (*.freshdesk.com/...). After you cancel Freshdesk, those URLs die. Every inline image in every ticket description must be parsed, downloaded, re-hosted, and URL-rewritten before loading into Pylon.

Pylon-Side Rate Limits

Pylon enforces per-endpoint rate limits that are significantly lower than Freshdesk's extraction limits. Your pipeline needs a write-side throttle. (docs.usepylon.com)

Pylon Endpoint Rate Limit
Account/Contact create & update 60 req/min
Issue creation 10 req/min
Issue search 20 req/min
Attachment upload 10 req/min

At 10 issues per minute, a 10,000-ticket migration takes approximately 1,000 minutes (~16.7 hours) of write time for issue creation alone — before adding messages, attachments, and custom field updates. Plan accordingly.

Only Admin users can create Pylon API tokens. And one safety feature matters during migration: issue creation supports destination_metadata with an "internal" destination, so imported history does not trigger notifications to customers.

Step-by-Step API Migration Process

The migration follows a strict dependency order. Violating it breaks relationships.

Phase 1: Extract from Freshdesk

Extraction order:
1. Companies     → GET /api/v2/companies?per_page=100
2. Contacts      → GET /api/v2/contacts?per_page=100
3. Agents        → GET /api/v2/agents?per_page=100
4. Tickets       → GET /api/v2/tickets?per_page=100&updated_since=...&include=description
5. Conversations → GET /api/v2/tickets/{id}/conversations
6. Attachments   → GET each content_url
7. KB Articles   → GET /api/v2/solutions/categories → folders → articles

Store everything locally (JSON files or staging database) before attempting any writes. This decouples extraction from loading and lets you retry the load phase without re-extracting.

curl -u "$FD_API_KEY:X" \
  "https://yourdomain.freshdesk.com/api/v2/tickets?updated_since=2026-01-01T00:00:00Z&include=description&page=1"

Phase 2: Transform

  • Map Freshdesk company IDs → Pylon account names/domains
  • Map Freshdesk contact emails → Pylon contact objects
  • Map Freshdesk agent emails → Pylon user IDs
  • Convert status integers to Pylon state strings
  • Convert priority integers to Pylon priority strings
  • Map cf_* custom fields to Pylon custom field slugs
  • Parse HTML descriptions for inline images; download, re-host, and rewrite URLs
  • Upload attachments to your hosting; generate public URLs
  • Build ID lookup tables (Freshdesk ID → staged ID) for accounts, contacts, and users

Phase 3: Load into Pylon

Load order (strict):
1. Create Accounts      → POST /accounts
2. Create Contacts      → POST /contacts (with account_id)
3. Create Issues        → POST /issues (with account_id, contact_id, assignee_id)
4. Add Messages         → POST /issues/{id}/messages
5. Create KB Collections → POST /knowledge-bases/{id}/collections
6. Create KB Articles    → POST /knowledge-bases/{id}/articles
Warning

When creating issues via API, set destination_metadata.destination to "internal" to prevent Pylon from sending email or Slack notifications to the customer for every historical ticket you import.

Example: Creating an Issue in Pylon

import requests
import time
 
PYLON_BASE = "https://api.usepylon.com"
PYLON_TOKEN = "your_bearer_token"
 
def create_pylon_issue(ticket, account_map, contact_map, user_map):
    payload = {
        "title": ticket["subject"],
        "body_html": ticket["description"],
        "account_id": account_map.get(ticket["company_id"]),
        "contact_id": contact_map.get(ticket["requester_id"]),
        "assignee_id": user_map.get(ticket["responder_id"]),
        "priority": {1: "low", 2: "medium", 3: "high", 4: "urgent"}.get(
            ticket["priority"], "medium"
        ),
        "state": {2: "new", 3: "waiting_on_customer", 4: "closed", 5: "closed"}.get(
            ticket["status"], "new"
        ),
        "created_at": ticket["created_at"],
        "tags": ticket.get("tags", []),
        "attachment_urls": ticket.get("rehosted_attachment_urls", []),
        "destination_metadata": {"destination": "internal"},
        "custom_fields": [
            {"slug": slug, "value": val}
            for slug, val in transform_custom_fields(ticket).items()
        ],
    }
 
    resp = requests.post(
        f"{PYLON_BASE}/issues",
        json=payload,
        headers={"Authorization": f"Bearer {PYLON_TOKEN}"},
    )
 
    if resp.status_code == 429:
        retry_after = int(resp.headers.get("Retry-After", 60))
        time.sleep(retry_after)
        return create_pylon_issue(ticket, account_map, contact_map, user_map)
 
    resp.raise_for_status()
    return resp.json()["data"]["id"]

Error Handling & Logging

Every API call should log:

  • Freshdesk source ID
  • Pylon target ID (on success)
  • HTTP status code
  • Error body and Pylon request_id (on failure)
  • Timestamp

Build an ID mapping table (Freshdesk ID → Pylon ID) and persist it. You need it for rebuilding relationships, debugging, running validation, and future integrations. Pylon explicitly supports external identifiers on accounts and contacts, which makes deterministic upserts easier on reruns. (docs.usepylon.com)

Make loaders idempotent using external IDs and mapping tables. Send failed records to a dead-letter queue, not back into the hot path.

Edge Cases & What Breaks

Duplicate Contacts

Freshdesk allows multiple contacts with the same email across different companies. Pylon's /import/contacts endpoint supports this — the same email can exist across different accounts — but standard POST /contacts may enforce uniqueness. Deduplicate before loading, or use the import endpoint.

Missing Relationships

If a ticket's requester_id references a contact that was not migrated (deleted user, spam contact), the issue creation will fail or create an orphaned record. Pre-validate all foreign keys before loading.

Inline Images

Freshdesk users often paste images directly into replies. These are hosted on Freshdesk's CDN. If you do not download and re-host these images during migration, they will render as broken links in Pylon once the Freshdesk account is closed.

Time Tracking and CSAT

Freshdesk time entries have no Pylon counterpart — archive them to a data warehouse. Historical CSAT scores can be stored as custom field values but will not feed into Pylon's native CSAT analytics.

Historical SLA Metrics

Pylon calculates SLAs based on its own internal logic. Historical SLA compliance metrics from Freshdesk cannot be imported as native SLA objects. Store them as custom text fields or export to a data warehouse.

Conversation Replay

Before committing to a DIY build, confirm the exact historical message replay behavior you need. Pylon's API supports creating messages on issues, but verify whether reply ordering, internal note attribution, and full thread reconstruction match your requirements.

Validation & Testing

Do not trust the migration until you have validated it.

Record count comparison:

  • Compare total accounts, contacts, and issues between Freshdesk and Pylon
  • Account for intentionally excluded records (spam, duplicates, test data)

Field-level validation (golden sample):

  • Pull 50–100 tickets at random from Freshdesk
  • Compare every field against the corresponding Pylon issue
  • Verify: title, body HTML, status, priority, requester, assignee, account, tags, custom fields, created_at, attachment count

Relationship integrity:

  • Every issue should link to a valid account and contact
  • Every contact should link to a valid account
  • No orphaned issues (requester = null)

Conversation threading:

  • Verify that reply order is preserved
  • Verify internal notes vs. customer-facing messages are correctly attributed

Attachment QA:

  • Open files from 20–50 sampled issues across file types
  • Check for broken inline images in HTML descriptions

Rollback plan:

  • If you have not cut over DNS or email routing, rollback is simple: keep using Freshdesk
  • Maintain the staging database until UAT is signed off — if the Pylon import fails, you can wipe and restart without re-querying Freshdesk
  • Pylon supports bulk delete via API for cleanup

Best Practices

  1. Back up everything. Request a full Account Export from Freshdesk before touching anything.
  2. Run a test migration first. Migrate 100 tickets to a Pylon sandbox environment. Validate every field.
  3. Migrate in dependency order. Accounts → Contacts → Issues → Messages. Never reverse this.
  4. Use destination: internal on all issue creation calls to prevent customer notifications.
  5. Preserve created_at timestamps. Without this, your historical reporting in Pylon is useless.
  6. Build an ID mapping table. Freshdesk ID → Pylon ID for every object. You need it for debugging, validation, and any future integrations.
  7. Disable Freshdesk automations before export to prevent webhooks from consuming your rate limit.
  8. Schedule bulk extraction during off-peak hours to avoid competing with live agent API usage.
  9. Pre-create all custom fields, tags, and teams in Pylon before loading any records. Select fields will reject unmapped values.

Post-Migration Tasks

Data migration is half the job. The other half is rebuilding operational configuration that no migration tool transfers.

Rebuild in Pylon (manual):

  • SLA policies and support hours
  • Triggers and workflow automations (Freshdesk Dispatch'r / Observer rules → Pylon triggers)
  • Macros (Freshdesk canned responses → Pylon macros)
  • CSAT surveys
  • Views and assignment rules
  • Team structure and roles
  • Email routing and forwarding
  • Chat widget configuration
  • Integrations (Salesforce, HubSpot, Linear, Jira)

Monitoring (first 30 days):

  • Watch for orphaned issues (no account or contact)
  • Monitor Pylon's analytics for data gaps
  • Check knowledge base articles for broken links and missing images
  • Verify CSAT surveys are firing on new issues
  • Keep Freshdesk in read-only mode for at least 7 days while monitoring Pylon for inconsistencies

When to Use a Managed Migration Service

Build in-house when:

  • Fewer than 5,000 tickets
  • No attachments or inline images to preserve
  • Simple custom field structure
  • An engineer with a week to dedicate

Use a managed service when:

  • More than 10,000 tickets with attachments
  • Complex custom field and status mapping
  • You need zero downtime (parallel operation + delta sync)
  • Your engineering team cannot afford the distraction
  • Compliance requirements (HIPAA, SOC 2) demand auditable data handling
  • Multi-level account hierarchies, agency structures, or partner accounts

Building an in-house ETL pipeline for a one-time migration is rarely the best use of engineering resources. The Freshdesk API constraints covered in this guide — 429 throttling, the 30,000-ticket ceiling, temporary S3 attachment URLs, inline image rewriting — require dedicated backend expertise for a task your team will never repeat.

ClonePartner handles the rate-limit orchestration, attachment re-hosting, relationship integrity, and delta sync so your engineering team stays focused on product work. We run your Freshdesk and Pylon instances in parallel with continuous delta syncs, enabling a zero-downtime cutover. Most Freshdesk-to-Pylon migrations complete in days, not weeks.

Frequently Asked Questions

Can I migrate Freshdesk tickets to Pylon using CSV export?
Only partially. Freshdesk CSV exports include ticket metadata but not full conversation histories, attachments, or archived tickets. Pylon has no CSV import UI, so you still need the API to load data. For anything beyond a basic snapshot of fewer than 1,000 tickets, API-based migration is required.
What are the Freshdesk API rate limits for data migration?
Freshdesk enforces account-wide rate limits by plan: Growth gets 200 calls/min, Pro gets 400/min, and Enterprise gets 700/min. Individual endpoints have sublimits — ticket listing is roughly 20 calls/min on Growth. The limit is shared with all integrations, and even failed requests count. The List All Tickets endpoint is capped at 300 pages (30,000 tickets max).
What is Pylon's API rate limit for importing data?
Pylon enforces per-endpoint rate limits: 60 req/min for account and contact operations, 10 req/min for issue creation, 20 req/min for issue search, and 10 req/min for attachment uploads. This is significantly lower than Freshdesk's extraction limits, so your pipeline needs a write-side throttle.
How do I migrate Freshdesk ticket attachments to Pylon?
Freshdesk provides temporary S3 URLs for attachments in the API response. Download each file via authenticated GET requests during extraction (URLs expire), re-host them on your own storage (S3, GCS), then pass the new public URLs into Pylon's attachment_urls array when creating issues. Inline images in HTML descriptions also need to be parsed, downloaded, re-hosted, and URL-rewritten.
How do I prevent customer notifications during a Freshdesk to Pylon import?
Create historical Pylon issues with destination_metadata.destination set to 'internal'. This prevents Pylon from sending email or Slack notifications to customers for every imported ticket. Patch workflow data like status and tags after validation.

More from our Blog

ClonePartner vs Help Desk Migration: 2026 Price & Feature Comparison
Why Choose ClonePartner

ClonePartner vs Help Desk Migration: 2026 Price & Feature Comparison

Choosing between ClonePartner and Help Desk Migration for your data migration in 2026? This essential guide provides a head-to-head comparison of features, true costs, and security compliance. We break down the critical differences between a DIY automated tool and a managed, engineer-led service , analyzing key factors like custom data handling, "Delta Migration," and the "hidden costs" of an in-house project so you can choose the right approach for your team.

Raaj Raaj · · 10 min read