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 column | Pact field |
|---|---|
| Account Name | name |
| Website / Domain | domain |
| Lifecycle Stage | stage |
| (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 column | Pact field |
|---|---|
email (dedup key) | |
| First/Last Name | name |
| Account record id | match 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:
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).