--- name: pombo-migrate description: Move an account off another email platform (Mailchimp, Klaviyo, Brevo, ConvertKit, HubSpot, Customer.io, Loops) into Pombo. Contacts, custom fields, suppression list, templates, and automations, in the right order. Use when the user already sends email somewhere else. --- # Migrating to Pombo A migration is data transfer plus a careful cutover. Do it in this order. Each step depends on the one before. Run `pombo-setup` first if the organization is not yet connected and domain-verified. ## 0. Read the old account before you rebuild The user's current tool answers questions you would otherwise guess at: their real audience size, their brand voice as actually written, which campaigns performed. If you can get read access (a scoped API key, never their password, revoked afterwards), pull: - contacts, every custom field, and the subscribe date per contact - the suppression list (unsubscribed, hard-bounced, complained) - the automations and their trigger events - the top few templates by send volume If you cannot get API access, tell the user exactly where each export lives in their tool. You likely know the UI. ## 1. Custom fields first For every column in the contact export that is not email, name, or status, create the field before importing: - `list_contact_fields` to see what exists. - `create_contact_field` per field. Match the type (string, number, date, boolean). A backfill is available if you are adding a field for data you already hold. Importing contacts with a value for a field that does not exist drops the value. ## 2. Contacts - `import_contacts` with the mapped rows, or `create_contact` for a handful. - Map subscribe date to the corresponding field so engagement history is not lost. - The free plan caps an organization at 1,000 subscribed contacts. Unsubscribed, bounced and undeliverable contacts are free and don't count, so always carry them across. If the subscribed part of the export is larger, tell the user before importing. The import rejects rows over the cap rather than silently truncating. ## 3. Suppression, and do not skip this Carry every suppressed contact across with the status that matches why the old tool suppressed them: `unsubscribed` for opt-outs, `bounced` for hard bounces, `complained` for spam complaints. Do not flatten them all to `unsubscribed`: an unsubscribed contact still receives transactional email, a bounced or complained one receives nothing. Merge the suppression list into the contact rows before importing, so each address arrives once with its final status, whatever the old tool's consent column says. Status values are exact and lowercase (`subscribed`, `unsubscribed`, `bounced`, `complained`); anything else fails the row. If the user imports a CSV in the app instead, this matters even more: a CSV import only sets status on contacts it creates, so a later suppression file cannot fix someone the first file brought in as subscribed. They stay in the audience so Pombo never emails them, and they count as suppressed from day one. Skipping this re-emails people who opted out of the old tool, which is the fastest way to wreck a new domain's reputation. ## 4. Templates - `create_template`. For a pixel-identical move, pass the existing HTML or MJML as raw code (`category: "full_template"`). `validate_template` before saving, `preview_template` to eyeball it. - Rewrite merge tags, do not copy them. `*|FNAME|*` (Mailchimp) becomes Pombo's `{{ first_name }}`. Klaviyo's `{{ first_name }}` already matches, but its other profile tags do not: `{{ person.plan }}` becomes `{{ plan }}`, `{{ person|lookup:'Company Size' }}` becomes `{{ company_size }}`, `{{ first_name|default:'friend' }}` becomes `{{ first_name | default: "friend" }}`, and `{% unsubscribe_link %}` becomes `{{ unsubscribe_url }}`. A copied merge tag renders as literal text in the inbox. - Rebuild the two or three templates that matter as editable blocks. Leave the long tail as raw. - Do not leave `src` attributes pointing at the old platform's CDN. Those break when the user cancels. `upload_asset` each image and repoint it. ## 5. Automations become sequences For each automation in the old tool: - `create_sequence` with the matching trigger. Most lifecycle flows are a custom event trigger. See the `pombo-events` skill for wiring the backend. - Add steps with the same delays and the same emails. - Set a goal (`compose_sequence_goal` or the sequence goal fields) so the flow reports conversions, not just opens. - `validate_sequence`, then leave it in draft. Do not activate yet. ## 6. Cut over 1. Confirm the sending domain is verified (`check_sending_domain`). 2. `send_test_email` from two or three templates. Check Outlook and dark mode. 3. Send a small real campaign to a test segment (`pombo-campaigns`). 4. Point production event traffic at `POST /api/v1/events`. 5. Activate the sequences (`set_sequence_status` or `activate_sequence`). 6. Stop the old tool's sends. Keep the old account read-only for a month in case you need to check something. ## Done when Audience, fields, suppression, templates, and automations all run in Pombo, the backend posts events to Pombo, and the old tool is no longer sending.