PPactDocs
Developers

Migrate from your old CRM in 3 hours

Export from a market-leading CRM, map fields, and import into Pact without losing relationships.

This recipe moves accounts, contacts, and deals out of a market-leading CRM and into Pact in an afternoon. The slow part is mapping fields once; the import itself is fast.

Estimated time: ~3 hours for a typical mid-size workspace (a few thousand records).

1 — Export from your old CRM (~30 min)

Export three CSVs from your current CRM: Accounts/Companies, Contacts, and Deals/Opportunities. Keep the record ID column from the source system in each file — you'll use it to rebuild relationships.

2 — Import accounts first (~30 min)

Order matters: import accounts before contacts, and contacts before deals, so the links resolve. In Pact go to Accounts → Import, upload the accounts CSV, and map columns:

Source columnPact field
Account Namename
Website / Domaindomain
Lifecycle Stagestage
(source record id)a custom field, e.g. legacy_id

Keeping legacy_id lets you match contacts to the accounts you just created.

3 — Import contacts, matched to accounts (~40 min)

Upload the contacts CSV. Pact deduplicates on email. Map the source account id to the account's legacy_id so each contact attaches to the right company:

Source columnPact field
Emailemail (dedup key)
First/Last Namename
Account record idmatch on legacy_id

Consent on migrated contacts

Imported contacts inherit your workspace's default consent policy. If you can't prove prior opt-in, set their consent to pending and run a re-engagement sequence before marketing to them.

4 — Import deals (~30 min)

Upload the deals CSV into Deals → Import. Map the deal's source account id to legacy_id so deals attach to accounts, and map your pipeline stages onto Pact stages.

5 — Verify with the API (~20 min)

Spot-check the counts against your export with a quick script:

python
import os, requests

H = {"Authorization": f"Bearer {os.environ['PACT_API_KEY']}"}
for entity in ("companies", "contacts", "opportunities"):
    res = requests.get(
        f"https://app.pact.place/v1/{entity}",
        params={"limit": 1}, headers=H, timeout=10,
    )
    res.raise_for_status()
    print(f"{entity}: {res.json()['total']} imported")

Compare each total to the row count of the matching CSV. If a number is short, re-open the import report — it lists skipped rows and why (usually a missing dedup key or an unmapped required column).

What's next?