Migration Playbook

Zammad Tidio

Zammad to Tidio: The Complete Migration Playbook

A 42-step runbook across six phases — track your progress, and open the right tool at every step.

0 / 42 steps complete 0%
TL;DR

Zammad to Tidio migration requires flattening organizations into contact properties, replaying ticket articles as sequential replies, and handling Tidio's 60–120 rpm rate limits with no bulk import.

Migrating from Zammad to Tidio requires a fundamental data model redesign, not a simple export/import operation. Zammad is built around a traditional helpdesk hierarchy of Tickets, Articles, Users, Organizations, and Groups, while Tidio is a chat-first platform organized around Contacts, Conversations, Tickets, Operators, and Departments — with no native Organization object and no knowledge base import pathway. There is no official migration tool or native import path that covers full ticket history, threaded articles, or organizational relationships. Custom API-based or ETL work is required to flatten organization data into contact properties, sequentially replay ticket articles as replies, and manually reconcile agents, departments, and tags before any data load can begin.

Read this first

Pair-specific gotchas that catch teams out. Each one has cost somebody a weekend.

If your Zammad instance has been acting as a lightweight CRM, do not assume Tidio should

If your Zammad instance has been acting as a lightweight CRM, do not assume Tidio should become the new system of record for accounts or custom objects. Tidio's public model does not expose first-class company or arbitrary custom-object endpoints. (developers.tidio.com)

Organization flattening is irreversible in Tidio

Because Tidio lacks a relational Organization object, updating a company name for one contact will not automatically update it for other contacts in the same company. Handle this via your CRM integration post-migration.

Tidio POST /contacts always creates a new contact and does not overwrite an existing one,

Tidio POST /contacts always creates a new contact and does not overwrite an existing one, even when the same email or distinct_id is sent. The response is 201 Created with a new UUID — no error, no warning. Use lookup + PATCH, or /contacts/batch for controlled updates, and keep distinct_id at 55 characters or less. If distinct_id exceeds 55 characters, the API returns 422 Unprocessable Entity with a validation error on the distinct_id field. (developers.tidio.com)

Tidio's OpenAPI endpoints are available on Plus and Premium plans, with published limits

Tidio's OpenAPI endpoints are available on Plus and Premium plans, with published limits of 60 requests/minute on Plus and 120 requests/minute on Premium. Free and Starter plans do not include OpenAPI access. Budget your migration window around these limits before you promise a weekend cutover. For reference: 10,000 tickets with an average of 5 articles each requires ~60,000 API calls (contacts + tickets + replies + status patches). At 120 rpm, that is approximately 8.3 hours of continuous API calls assuming zero errors and zero retries. (developers.tidio.com)

Zammad has hard limits on the maximum number of returned objects per request (100 for

Zammad has hard limits on the maximum number of returned objects per request (100 for most endpoints). You cannot raise these limits. You must paginate through all pages using the page and per_page parameters. An empty array [] in the response indicates you have reached the last page.

Tidio's reply endpoint supports both public and internal message types

Map Zammad articles with internal: true to internal and customer-facing articles to public. Getting this wrong exposes internal agent discussions to the customer. Validate this mapping in staging before running against production data.

The runbook

Work top to bottom. Tick steps as you go — your progress is saved in this browser.

01 Discovery Establish why you are moving, what "done" means, and who signs off. 0/8

Objective A written scope with agreed success criteria, a named owner per workstream, and a budget approved by finance.

  1. Pull the real numbers out of Zammad

    Support ops 1 day

    Export counts for tickets (open and closed separately), contacts, organisations, attachments, macros, triggers, automations, views and SLA policies. Note the oldest ticket date — history depth drives the whole timeline. Estimating from memory is the single most common cause of a blown migration window.

    Data Profiler Get real record counts instead of estimating from memory
  2. Decide what history actually moves

    Support lead 2 days

    Agree a cut-off with the support lead: all history, last 24 months, or open tickets plus a read-only archive. Every extra year of closed tickets adds API time and cost without adding much agent value. Get this in writing — it is the decision people relitigate mid-cutover.

    A "move everything" default is what turns a two-week migration into a two-month one.

    COI & ROI Calculator Build the 36-month business case you will need for sign-off
  3. Confirm Tidio can hold your support model

    Solution architect 2-3 days

    Walk your current workflow through Tidio: multi-brand, business hours, SLA targets, CSAT, side conversations, public vs internal notes, and any channel you depend on (voice, chat, WhatsApp, social). List anything with no native equivalent — those are project risks, not configuration details.

  4. Build the business case

    Project sponsor 1-2 days

    Model licence delta, migration effort, agent retraining, and the cost of staying put (Cost of Inaction). Executives approve a number, not a plan, and you will be asked for it again at the go/no-go.

    Helpdesk Migration Planner Turn ticket volume into a dated Zammad → Tidio timeline
  5. Name owners and set the go/no-go date

    Project manager 1 day

    One named owner each for data, configuration, integrations, and agent enablement, plus a decision-maker who can call a rollback. Put the go/no-go meeting in calendars now, 48 hours before the freeze.

  6. Identify dead data

    Spam tickets, test users, orphaned organizations — exclude them from scope. Consider archiving tickets older than 3 years to a secure archive (e.g., AWS S3) instead of paying to store them in Tidio.

  7. Map custom attributes to Tidio fields

    Tidio Contact Properties support five types: text, email, number, phone, and url. Run a pre-migration attribute compatibility check:

  8. Create Tidio operators and departments manually

    The Tidio API is read-only for operators. Every agent must be created through the Tidio admin panel before migration. Budget approximately 2 minutes per operator (name, email, password setup) and 1 minute per department. For a team of 50 operators and 20 departments, this is roughly 2 hours of manual work. (developers.tidio.com)

Zammad → Tidio specifics

Small business (<1,000 tickets)
Use CSV for contacts, keep Zammad in read-only mode for 90 days for historical reference.
One-time migration with ticket history
API-based migration or a managed service.
Enterprise or regulated team
Custom ETL or a managed engineer-led migration.
Ongoing sync
Webhooks + middleware or direct API workers.
Pre-create Contact Properties in Tidio
Custom properties must be defined in Settings > Contact Properties before any contact data can reference them. Note: contact properties cannot currently be deleted, only hidden. This means any incorrectly named or typed property will persist in your schema. Plan your schema on paper first and have it reviewed before creating anything. (help.tidio.com)

Don't move on until

  • Record counts confirmed for tickets, contacts, organisations and macros
  • Success criteria signed off by the support lead
  • Freeze window provisionally booked with the business
02 Data Audit Find out what is actually in the data before you try to move it. 0/7

Objective A profiled, cleaned export with every quality defect either fixed at source or explicitly accepted.

  1. Take a full Zammad export and profile it

    Data engineer 1-2 days

    Export to CSV or JSON and profile every file: row counts, null rates per column, distinct values, and type consistency. Compare row counts against the API totals from Discovery — a gap here means your export is silently truncated, usually by pagination.

    Data Profiler Profile the Zammad export for nulls, outliers and type drift
  2. Validate file structure before anyone writes a transform

    Data engineer 1 day

    Check delimiters, quoting, encoding (expect UTF-8, watch for BOMs and Latin-1), duplicate headers, and embedded newlines in ticket bodies. Ticket descriptions with raw newlines and commas break naive CSV parsers and silently shift columns.

    A single unescaped quote in one ticket body can shift every subsequent column without any error.

    CSV Validator Catch broken headers and ragged rows in the raw export
  3. Inventory PII and set retention

    Compliance / DPO 2 days

    Scan for emails, phone numbers, payment card fragments, national IDs and anything else regulated in ticket bodies and custom fields — support tickets are where customers paste things they should not. Decide what gets migrated, masked, or dropped, and record the legal basis.

    Ticket bodies and attachments routinely contain card and ID data that never appears in a structured field.

    PII & Compliance Scanner Find regulated fields before they land in a new system
  4. Quantify duplicates, orphans and dead references

    Support ops 1-2 days

    Count duplicate contacts (same email, different casing), tickets whose requester no longer exists, organisations with no members, and attachments whose parent ticket is gone. Fix these in Zammad where you can — migrating them just moves the mess.

    Data Cleaner Strip empty rows, stray whitespace and dead columns
  5. Clean and normalise the export

    Data engineer 2 days

    Trim whitespace, drop empty rows and columns, normalise casing on emails and tags, and standardise every timestamp to UTC ISO 8601. Timezone drift is invisible at load time and shows up weeks later as SLA reports nobody can reconcile.

  6. Produce a masked copy for sandbox work

    Data engineer 0.5 day

    Generate a realistic but fake version of the export for testing and for any vendor who needs sample data. Loading real customer PII into a sandbox is a breach in most jurisdictions, and sandboxes are rarely covered by your DPA.

    PII Masker Generate a safe copy for sandbox and vendor testing
  7. Audit your Zammad data

    Count users, organizations, tickets, articles, tags, and custom attributes. Identify which custom object attributes exist on tickets, users, and organizations. For self-hosted Zammad, run direct SQL counts: ``sql SELECT COUNT() FROM users WHERE role_ids @> ARRAY [3]; -- Customers SELECT COUNT() FROM tickets; SELECT COUNT() FROM ticket_articles; SELECT COUNT() FROM organizations; `` For Zammad Cloud, paginate the API and count. (docs.zammad.org)

Zammad → Tidio specifics

How it works
Export flat contact data from Zammad (available under Settings > Users > Import for user CSVs), normalize columns, then import into Tidio's Customers > All contacts import flow.
When to use it
Small datasets, contact-only migrations, or a one-time reference archive where ticket history does not need to be live in Tidio.
Thread integrity audit
For 20 randomly selected tickets with 5+ articles, verify that every Zammad article appears as a reply in the correct chronological order in Tidio.

Don't move on until

  • Export parses cleanly with no ragged rows or encoding errors
  • PII inventory complete and retention decisions recorded
  • Duplicate and orphan records quantified and triaged
03 Field Mapping Turn two schemas into one signed-off mapping spec. 0/6

Objective A reviewed field-level mapping covering every object, with an explicit decision for every field that has no target.

  1. Generate the first-pass Zammad → Tidio field map

    Solution architect 2 days

    Start from an automated match on both schemas, then review every row by hand. Automated matching gets the obvious 70% right and is confidently wrong on the rest — especially anything named "type", "status" or "custom_field_1".

    Schema Mapper Opens pre-loaded with the Zammad → Tidio field pair
  2. Map status, priority and channel values, not just field names

    Support lead 1-2 days

    Enumerate every value in each picklist on both sides and map them explicitly. Value-level mismatches are the defect class that survives all the way to production because the field itself mapped fine — a ticket that should be "Pending" arriving as "Open" reopens SLA clocks.

    Statuses with no target equivalent (on-hold, pending-customer) need a policy decision, not a best guess.

  3. Decide how custom fields land

    Solution architect 2 days

    Create the target custom fields first, matching type exactly (a dropdown mapped to free text can never be mapped back). Where Tidio has no equivalent, decide between a new custom field, a tag, or a note appended to the ticket body — and record which.

  4. Resolve identity and threading

    Data engineer 1 day

    Decide how source IDs are preserved — most platforms will not let you set the primary key, so keep the original ID in a custom field. Without it, reconciliation becomes fuzzy matching and every future support question about an old ticket is unanswerable.

    Losing the original ticket ID makes reconciliation and rollback effectively impossible.

  5. Plan attachments, inline images and threading order

    Data engineer 1-2 days

    Confirm size limits, allowed MIME types, and whether inline images survive as attachments or need rehosting. Decide the comment ordering and author attribution rules: comments loaded out of order, or all attributed to the API user, destroy the conversation history agents rely on.

  6. Freeze and sign off the mapping spec

    Project manager 1 day

    Version the spec, walk the support lead through it row by row, and get explicit sign-off. Any change after this point goes through change control — mid-flight mapping edits are how partial loads happen.

Don't move on until

  • Every source field is mapped, deliberately dropped, or parked in a custom field
  • Status, priority and channel value maps agreed with the support lead
  • Mapping spec version-controlled and signed off
04 Test Migration Prove the pipeline on a small, representative slice. 0/6

Objective A pilot load into a Tidio sandbox that reconciles cleanly and has been reviewed by real agents.

  1. Stand up a Tidio sandbox that matches production config

    Solution architect 2-3 days

    Create the custom fields, groups, brands, business hours and SLA policies first. A pilot into a default sandbox tests nothing, because the failures you care about are all configuration mismatches.

  2. Pick a deliberately nasty pilot sample

    Data engineer 0.5 day

    Take 500-1000 records chosen for difficulty, not convenience: the longest ticket threads, tickets with the most attachments, non-Latin character sets, merged and split tickets, deleted requesters, and every status value. A clean random sample proves only that easy records are easy.

  3. Run the load with masked data and instrument everything

    Data engineer 1-2 days

    Log every API request and response with its source record ID. When 40 records fail out of 10,000 you need to know exactly which ones and why, without re-running the whole batch.

    PII Masker Never load real customer PII into a sandbox
  4. Measure real throughput against the rate limit

    Data engineer 1 day

    Record achieved records-per-hour under Tidio's actual rate limits, including retries and backoff. Extrapolate to the full volume: if the maths says the full load exceeds your freeze window, you fix that now, not on cutover night.

    Published rate limits are ceilings, not throughput. Assume real-world rates are meaningfully lower once retries and backoff are counted.

  5. Reconcile the pilot and triage every failure

    Data engineer 1-2 days

    Diff source against target on record counts and field-level values. Every discrepancy gets a root cause and a fix — "probably fine" at pilot scale becomes thousands of broken records at full scale.

    Migration Validation Tool Diff the pilot batch against source before scaling up
  6. Put real agents in front of the pilot data

    Support lead 2 days

    Have two or three agents work sample tickets end to end in the sandbox. They find the things reconciliation cannot see: unreadable threading, missing context, macros that no longer make sense. Fix the mapping, then re-run.

Don't move on until

  • Pilot batch reconciles to 100% on record counts
  • Agents have reviewed sample tickets and confirmed they are workable
  • Measured throughput extrapolates to a viable full-load window
05 Cutover Execute the switch inside a controlled, reversible window. 0/6

Objective All in-scope data live in Tidio, agents working in the new system, and a rollback path that stayed available throughout.

  1. Pre-load history before the freeze

    Data engineer 3-10 days

    Load closed tickets and contacts days or weeks ahead while Zammad stays live. Only open tickets and the final delta need to move inside the freeze — this is the single biggest lever on window length.

    Helpdesk Migration Planner Size the freeze window from Tidio's real API limits
  2. Publish the runbook with times, owners and abort criteria

    Project manager 1 day

    A timed sequence: freeze start, final export, delta load, channel switch, smoke test, go/no-go, agent switch. Name who does each step and the explicit condition that triggers a rollback. Decide the abort criteria before the night, when nobody wants to be the one to call it.

  3. Freeze Zammad and take the final delta

    Support ops 2-4 hours

    Stop new ticket creation, let agents finish in-flight replies, then export everything changed since the pre-load. Announce the freeze to the whole business, not just support — someone always tries to raise a ticket during it.

    Tickets created during an unenforced freeze land in the old system and are the most common source of permanently lost data.

  4. Load the delta and open tickets

    Data engineer 2-6 hours

    Run the delta load, then reconcile counts before touching any channel. Do not repoint email until the delta has verified — an inbound ticket arriving mid-load is far harder to untangle than a few extra minutes of freeze.

    Migration Validation Tool Confirm the final delta landed before you reopen
  5. Repoint channels and verify with live traffic

    IT / integrations 2-4 hours

    Switch email forwarding and MX or connector settings, update chat widgets and web forms, and re-authorise integrations. Then send real test tickets through every channel and confirm each lands, routes and triggers the right automation.

    Email forwarding changes can take up to a full DNS TTL to propagate — check the TTL days in advance and lower it if needed.

    Cron Expression Builder Schedule the delta syncs that run through the freeze
  6. Run the go/no-go and switch the agents

    Project sponsor 1-2 hours

    Walk the exit criteria with the decision-maker, call it explicitly, then move agents over with a named person on hand for the first few hours. Keep Zammad read-only rather than cancelled — cancelling the old contract on day one removes your only fallback.

Zammad → Tidio specifics

Rollback plan
If Tidio was empty before migration, rollback means deleting all migrated contacts and tickets via the API (use your ID mapping table to identify migrated records). If Tidio had existing data, tag all migrated records with a migration_batch_id property so you can isolate and remove them if needed.

Don't move on until

  • Full historical load complete and counts matched
  • Inbound channels repointed and verified with live test tickets
  • Rollback decision point passed explicitly, not by default
06 Validation Prove the migration is complete, then close it out. 0/9

Objective Documented evidence that data, workflow and reporting all survived, and a signed acceptance.

  1. Run the full reconciliation

    Data engineer 1-2 days

    Compare source and target on every object: total counts, counts by status, counts by group, attachment counts, and field-level spot checks on a random sample. Produce one report you can hand to an auditor.

    Migration Validation Tool Reconcile Zammad and Tidio record-for-record
  2. Verify field completeness, not just record counts

    Data engineer 1 day

    Re-profile the loaded data and compare null rates per field against the source profile. Matching record counts with a field that silently arrived empty is the failure mode counts alone will never catch.

    Data Profiler Prove field completeness held up through the load
  3. Rebuild reporting and compare against baselines

    Support ops 2-3 days

    Recreate your core dashboards — volume, first response time, resolution time, CSAT — and compare to pre-migration figures for the same period. Explain every variance; a changed SLA calculation is a real finding, not a rounding error.

    SLA and first-response metrics are usually recalculated from the loaded timestamps, so they will differ if any timestamp mapping was approximate.

  4. Test the workflow layer end to end

    Support ops 2 days

    Fire every trigger, automation, SLA escalation, macro and notification with a live ticket. Workflow does not migrate — it gets rebuilt — so it is untested until someone has actually watched it run.

  5. Confirm compliance and produce the audit trail

    Compliance / DPO 1 day

    Re-scan the loaded data for regulated fields, confirm retention and deletion policies are configured in Tidio, and file the evidence with your PII decisions from the audit phase.

    PII & Compliance Scanner Produce the compliance evidence your auditor will ask for
  6. Sign off, then decommission on a schedule

    Project sponsor 1 day

    Get written acceptance against the Discovery success criteria. Keep Zammad read-only for an agreed period (30-90 days is typical), take a final archive export, and only then cancel. Diarise the decommission date so it does not quietly renew.

  7. Rebuild automations

    Zammad Triggers, Schedulers, and Macros do not migrate. Document each Zammad trigger's conditions and actions, then rebuild equivalent logic using Tidio's Flows (for chatbot-style automations) and routing rules (for ticket assignment). Pay special attention to SLA timers — Tidio's SLA configuration is under Settings > Helpdesk and uses different escalation logic than Zammad's.

  8. Rebuild canned responses

    Zammad text modules have no migration path. Export them via GET /api/v1/text_modules and recreate them as Tidio canned responses. If you have more than 50 text modules, consider scripting this through Tidio's admin interface.

  9. Monitor for gaps

    Run the automated count comparison daily for the first two weeks post-migration. Watch for missing replies (articles that failed silently), broken contact associations, or missing custom property values. Set up a Slack/Teams alert if the dead-letter queue gets new entries during delta sync.

Zammad → Tidio specifics

Field-level spot checks
Randomly sample 50 contacts and 20 tickets. Compare every field programmatically — do not rely on visual inspection alone.
Edge case verification
Specifically check: tickets from users who belonged to multiple organizations; tickets with 10+ articles; tickets with attachments; merged tickets (if migrated); tickets with internal notes.
UAT process
Have 3–5 senior support agents log into Tidio and manually review 10 complex historical tickets each. If attachments or internal notes are missing, halt the migration and fix the transformation logic before proceeding.
Knowledge Base
Tidio does not have a native Knowledge Base equivalent to Zammad's structured KB (categories → articles → translations). If you used Zammad's KB heavily, migrate those articles to a dedicated tool (Document360, Notion, or GitBook) and link them within Tidio chat responses. Alternatively, export Zammad KB articles via GET /api/v1/knowledge_base/ endpoints and archive them as HTML/Markdown files.
Train agents
Tidio's interface is significantly different from Zammad's. Key differences agents will notice: (1) no Organization tab — company info is in Contact Properties; (2) conversations are chat-centric, not email-centric; (3) ticket search works differently; (4) internal notes use a different UI flow. Budget 2–4 hours of hands-on training per agent.

Don't move on until

  • Full reconciliation report attached to the project record
  • Reporting baselines match pre-migration figures within agreed tolerance
  • Formal acceptance signed and archive retention scheduled

Field mapping reference

The field-by-field mapping for each object. Use this as the starting point for your mapping spec.

Object Object 12 fields
Zammad fieldTidio fieldNotes
Users (Customers) Contacts Match on email. At least one of email, first_name, last_name, or phone required. Store Zammad user ID as distinct_id (max 55 chars). (developers.tidio.com)
User Custom Attributes Contact Properties Must pre-create property schema in Tidio admin before import. Types limited to: text, email, number, phone, url. (help.tidio.com)
Organizations Contact Properties / Metadata No Organization object in Tidio. Flatten org name, domain, notes to contact-level properties. (docs.zammad.org)
Groups Departments Manual creation required. API exposes department IDs for retrieval only. (developers.tidio.com)
Agents / Admins Operators Manual creation required. Tidio API is read-only for operators. Budget ~2 minutes per operator for manual creation in the admin panel.
Tickets Tickets Map requester to Tidio Contact ID. Status mapping required: map to open, pending, solved. (developers.tidio.com)
Ticket Articles Ticket Replies / Messages Sequential replay via the Reply endpoint. Map internal=true → message_type=internal, internal=false → message_type=public.
Merged Tickets No equivalent Zammad state merged with parent link. Either skip, migrate as standalone, or append articles to parent ticket's reply chain.
Tags Tags Resolve tag names to Tidio tag IDs before load. (developers.tidio.com)
Attachments External links in message body Download from Zammad, host externally, embed link in reply content.
Knowledge Base No import pathway Manual recreation or archive externally.
SLAs / Triggers / Macros No import pathway Rebuild in Tidio's Flows and workflow settings.

Risk matrix

Per-object risk for this pair. Plan extra validation around anything marked high.

ObjectRiskNotes
Tickets medium Tickets map structurally to Tidio's ticket object, but status values require explicit mapping, and merged tickets in Zammad have no Tidio equivalent, requiring a case-by-case decision to skip, migrate standalone, or append articles to a parent ticket.
Ticket Articles high Zammad's per-message article model has no direct Tidio equivalent and must be sequentially replayed as ticket replies, with no guarantee of preserving original timestamps or sender attribution accurately.
Contacts medium Contact creation carries a high deduplication risk because POST /contacts silently creates new records on duplicate email or distinct_id submissions, requiring lookup-then-PATCH logic and strict distinct_id length enforcement under 55 characters.
Organizations high Tidio has no Organization object, so all organization data must be flattened into contact properties, which is an irreversible transformation that breaks relational organization updates for all associated contacts.
Custom Fields medium Zammad user custom attributes must be pre-created as Tidio contact property definitions in the admin panel before import, and the available property types are limited to text, email, number, phone, and URL, which may not accommodate all Zammad attribute types.
Agents and Operators high Tidio's API is entirely read-only for operator records, so all agents must be manually created in the admin panel before migration, introducing a manual bottleneck and a risk of assignment mismatches if operator IDs are not carefully reconciled.
Groups and Departments medium Zammad Groups map to Tidio Departments, but the Tidio API only retrieves department IDs and does not support creation, requiring all departments to be manually pre-created and their IDs catalogued before tickets can be assigned.
Tags low Tags are supported in Tidio but require resolving Zammad tag names to Tidio tag IDs before the load phase, which adds a lookup step but is technically straightforward with a pre-built tag ID reference table.
Attachments high Attachments cannot be uploaded natively via the Tidio API and must be downloaded from Zammad, hosted on external storage, and embedded as URLs in reply message bodies, risking broken links if external hosting is not maintained long-term.
Knowledge Base high Tidio has no knowledge base import pathway, so all Zammad knowledge base articles must be manually recreated in Tidio or archived in an external system, representing a complete data migration gap with no automation available.

The hard parts

What makes this specific migration difficult, beyond the mechanics.

Organization Model Flattening

Tidio has no relational Organization object, so all Zammad organization data — name, domain, notes, and custom attributes — must be denormalized into contact-level properties, making future bulk organization updates impossible within Tidio itself.

Ticket Article Sequential Replay

Zammad's per-message Article model has no direct Tidio equivalent, requiring each article to be replayed in chronological order via Tidio's Reply endpoint with internal or public message type mapped from the original article's internal flag.

Operator and Department Pre-creation

Tidio's API is read-only for operator records and exposes department IDs for retrieval only, meaning all agents and departments must be manually created in the Tidio admin panel before any automated migration load can reference them.

Aggressive Tidio Rate Limiting

Tidio enforces strict API rate limits of 60 requests per minute on Plus plans and 120 on Premium, requiring queued request architecture and retry logic to migrate any dataset of meaningful size without hitting 429 errors.

Contact Deduplication Risk

Tidio's POST /contacts endpoint always creates a new contact record regardless of duplicate email or distinct_id, returning 201 Created with no warning, so migrations must implement a lookup-then-PATCH pattern or use the batch endpoint to avoid creating duplicate contacts.

Attachment and Knowledge Base Loss

Zammad attachments have no native upload path in Tidio and must be downloaded, hosted externally, and embedded as links in reply content, while Zammad knowledge base articles have no import pathway at all and must be manually recreated or archived outside Tidio.

What breaks

Known failure modes. Have a recovery plan for each before you cut over.

Organization flattening

Zammad organizations with dozens of members all share a single org record. In Tidio, you must duplicate the org name as a Contact Property on every member. If the org has custom attributes, each one becomes a separate property on each contact. If a Zammad user belongs to multiple organizations (via the organization_ids array), you must decide which one becomes the primary company_name, since Tidio's flat schema cannot handle one-to-many company relationships. Consider storing additional org IDs in a semicolon-delimited text property (e.g., secondary_orgs: "Org-A;Org-B").

Attachment handling

Zammad stores attachments within ticket articles and exposes them via the attachment download endpoint (/api/v1/ticket_attachment/TICKET_ID/ARTICLE_ID/ATTACHMENT_ID). Tidio's documented ticket create/reply endpoints do not show attachment upload parameters. Download each attachment from Zammad, host it externally (S3 with pre-signed URLs or GCS with signed URLs, set to expire in 5+ years), and embed the link in the reply body. For a migration of 10,000 tickets, expect attachment storage in the range of 5–50 GB depending on your industry. (docs.zammad.org)

Duplicate contacts

Zammad allows multiple users with different roles sharing the same email. Tidio's POST /contacts always creates a new record — there is no error, no deduplication, no warning. The response is 201 Created with a brand new UUID. Merge or choose a canonical record before migration, and always call GET /contacts?email=... before every create call. (developers.tidio.com)

Timestamps

Tidio's API does not allow you to set created_at on tickets or replies. Historical timestamps from Zammad cannot be preserved natively. Two workarounds: (1) embed the original timestamp in the message body — prepend [Original Date: 2023-04-15T14:30:00Z] to the imported message content; (2) store the original timestamp in a ticket custom field named original_created_at. Neither is ideal, but the custom field approach preserves sort/filter capability. (developers.tidio.com)

Internal notes vs. public replies

Zammad's ticket articles have a boolean internal flag. Map this to Tidio's message_type field (internal vs public). If you get this wrong, sensitive internal discussions become visible to the customer. Validate by querying migrated tickets and checking message_type for every reply against the source internal flag.

Merged tickets

Zammad tickets with state merged have a link to their parent ticket. Tidio has no merge concept. Three options: (1) skip merged tickets entirely — simplest, but you lose that conversation history; (2) migrate merged tickets as standalone tickets with a custom field pointing to the parent ticket's Tidio ID; (3) append the merged ticket's articles to the parent ticket's reply chain, prefixed with [Merged from Ticket #123]. Option 3 preserves the most context but is the most complex to implement.

Rate limiting math

At 60–120 requests per minute, a migration of 10,000 tickets with 5 articles each requires approximately 60,000 API calls (10K contact creates + 10K ticket creates + 40K replies + status patches + tag operations). At 120 rpm with zero errors, that's roughly 8.3 hours of continuous API calls. With a realistic 5–10% retry rate, budget 10–12 hours. Build in exponential backoff, checkpoint logic (persist progress to database, not just memory), and resume capability. (developers.tidio.com)

Custom schema constraints

Tidio's contact property types are limited to five (text, email, number, phone, url). Complex Zammad attributes (select, tree select, boolean, datetime) require simplification — see the attribute compatibility table in the Pre-Migration Planning section. Existing contact properties in Tidio cannot be deleted, only hidden. Creating a property with the wrong name or type is permanent clutter. (help.tidio.com)

Zammad Cloud vs. Self-Hosted

Zammad Cloud instances do not expose direct database access — all extraction must go through the REST API. Self-hosted instances (both Docker and package-based) can extract directly from PostgreSQL, bypassing API pagination limits. If you're on Zammad Cloud with more than 50,000 tickets, contact Zammad support about bulk export options before relying solely on paginated API calls.

Tools used in this playbook

All free, all run entirely in your browser — nothing is uploaded.

FAQ

Can I migrate Zammad ticket history to Tidio?

Yes, but only via the API. You must extract ticket articles from Zammad and replay them sequentially as replies in Tidio using the POST /tickets/{ticketId}/reply endpoint. There is no bulk ticket import option. Original timestamps cannot be preserved natively — embed them in message content or a custom field.

Does Tidio support organizations like Zammad?

No. Tidio has no dedicated Organization object. You must flatten organization data (name, domain, notes) into Contact Properties on individual contact records. The organizational hierarchy from Zammad is lost, and updating a company name on one contact will not propagate to others.

How do I avoid duplicate contacts in Tidio during migration?

Tidio's POST /contacts endpoint always creates a new contact and does not overwrite matching email or distinct_id. Look up existing contacts first and use PATCH for updates, or use the /contacts/batch endpoint for controlled create/update operations.

Can I migrate Zammad agents to Tidio via API?

No. The Tidio API is read-only for operators. All agents and admins must be created manually through the Tidio admin panel before starting the migration.

What Zammad data cannot be migrated to Tidio?

Knowledge Base articles, SLA policies, triggers, macros, text modules, and agent accounts have no API import pathway in Tidio. Attachments have no native upload path in ticket replies. These must be manually recreated, archived externally, or hosted as external links.

Or skip all of this and let us handle it

Book a 30-minute call and we'll scope your migration in a single session.