Migrate to CCD
Three ways to move data from your current tool into CCD, in order of how much manual work each requires:
- OAuth connector — link your account, click "Sync now". Best when you have a HubSpot or Salesforce login and outbound network.
- File upload — export from your old tool, upload the CSV/XLSX in Settings → Import. Best for everyone else.
- Offline CLI —
ccd import contacts.csv …from a terminal, airgap-friendly. Best for self-host operators behind a firewall.
The mapping flow is the same regardless of source: CCD detects the columns, suggests a mapping, you confirm, it imports. Tool-specific quirks below.
Playbooks
HubSpot
Two paths.
Live sync (recommended). Settings → Integrations → Connect HubSpot → authorize. Back to Settings → Import → "Sync now" on the HubSpot card. Pulls Companies, Contacts, Deals. Re-syncs are idempotent (dedup by HubSpot ID).
CSV upload. In HubSpot:
- Contacts → Actions → Export → CSV. Choose "All properties".
- Companies → Actions → Export → CSV.
- Deals → Actions → Export → CSV.
Upload each separately in Settings → Import, picking the matching CCD table. CCD will not detect HubSpot from the CSV headers (HubSpot's column names are too generic), so the AI mapping/heuristic does most of the work. Confirm the suggested mapping before continuing.
Salesforce
Two paths.
Live sync (recommended). Settings → Integrations → Connect Salesforce → authorize. Back to Settings → Import → "Sync now" on the Salesforce card. Pulls Accounts, Contacts, Opportunities. Dedup by Salesforce ID. Order: Accounts first so Contacts and Opportunities can resolve their account FK to a just-synced Company.
Sandbox orgs. The OAuth flow defaults to
login.salesforce.com(production). For sandboxes usetest.salesforce.comby settingSALESFORCE_LOGIN_HOST=test.salesforce.comin the environment before connecting. Self-host operators set this in their.env; cloud customers can't override.
Salesforce gives every org a unique
instance_url(e.g.https://acme.my.salesforce.com). CCD captures it during OAuth and persists it alongside the access token — no operator action needed.
Data Export Service (CSV). Setup → Data Export. Choose Accounts, Contacts, Opportunities. Wait up to 48 hours for the email with the download. Unzip and upload each CSV separately.
Pipedrive
CSV export is the only path today (no OAuth connector — coming in a future release).
In Pipedrive:
- Persons → "..." menu → Export → All visible columns
- Organizations → "..." menu → Export → All visible columns
- Deals → "..." menu → Export → All visible columns
Upload each in Settings → Import. CCD auto-detects Pipedrive from
the Person - Name, Deal - Title, etc. column headers and pre-fills
the mapping. You should see a "Detected: Pipedrive" banner above the
mapper.
Table choice: Persons → CCD contacts. Organizations → CCD
companies. Deals → CCD deals.
monday.com
Export each board as CSV: board menu (top-right) → "More actions" →
"Export to Excel" → save as .csv from Excel.
CCD auto-detects monday from Item ID, Item Name, Board Name. The
mapping depends on what the board contains — monday is freeform so
your "Items" might be deals, contacts, or tasks. Pick the matching CCD
target table when starting the import.
Common mappings:
| monday board type | CCD table |
|---|---|
| Sales pipeline | deals |
| Contact list | contacts |
| Company list | companies |
| Tasks / projects | activities |
Asana
Project export: project menu → Export / Print → CSV.
CCD auto-detects Asana from Task ID, Assignee Email, Last Modified etc. Tasks map to CCD activities (subject, description,
due_date, status). The assignee is preserved as a note rather than a
linked user — CCD activities don't expose an assignee column in the
import schema, so the Assignee/Assignee Email columns are dropped
during mapping (or you can map them to notes manually).
Project members don't come through the task CSV — invite them separately in Settings → Team. Custom fields aren't included; if you need them, request the Asana API export instead.
Generic CSV / Excel
Any tool that exports CSV or XLSX works:
- Settings → Import → "New import"
- Pick target module + table
- Upload the file (CSV, XLSX, or JSON array)
- CCD suggests a mapping based on header similarity — confirm or adjust per column
- Choose duplicate behaviour (skip / update / create-new)
- Preview, then Execute
10MB / 10k rows per upload. For larger files, split or use the bulk REST endpoint.
Bulk REST (programmatic)
For scripted imports — Zapier, n8n, custom ETL, weekly syncs from a warehouse:
curl -X POST https://your-deploy.example.com/api/v1/import \
-H "Authorization: Bearer ccd_live_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"target_table": "contacts",
"records": [
{ "first_name": "Alice", "last_name": "Smith", "email": "alice@example.com" },
{ "first_name": "Bob", "last_name": "Jones", "email": "bob@example.com" }
],
"dedup_key": "email"
}'
The
ccd_live_…prefix is the production API-key format. Sandbox/ staging keys may useccd_test_…. See REST API → Authentication for the full key-format reference.
Response shape:
{
"data": {
"batch_id": "...",
"target_table": "contacts",
"received": 2,
"inserted": 2,
"skipped_dedup": 0,
"failed": 0,
"errors": []
},
"meta": null,
"errors": []
}
5,000 records per call. Chunk larger imports caller-side.
Offline CLI (self-host airgapped)
When the deploy is behind a firewall with no outbound API access, the OAuth connectors don't work. Use the bundled CLI:
./ccd import contacts.csv --table contacts --key ccd_xxxxxxxxxxxxxxxx
./ccd import companies.csv --table companies --key ccd_xxxxxxxxxxxxxxxx --dedup-key name
./ccd import deals.json --table deals --key ccd_xxxxxxxxxxxxxxxx
The CLI is pure-Node, zero dependencies — works inside the self-host
docker network without phoning home. It reads CSV/JSON, posts to the
local /api/v1/import, and reports per-row errors. XLSX isn't
supported here (convert in your spreadsheet app first).
Exit codes: 0 success | 2 partial success | 3 total failure | 1 usage.
Mapping quirks
A few cross-tool patterns worth knowing:
- Full-name columns. Some exports give "Full Name" as a single
column. The default heuristic doesn't split it — map "Full Name" to
whichever of
first_nameorlast_nameis required, or click "AI Suggest" and the AI mapper will split it for you when the data shape is obvious. - Multi-valued fields. Asana tags, HubSpot lists, Salesforce picklists with multi-select don't come through the connector sync today — only the columns named in the connector's SOQL/property list are pulled. For CSV uploads, multi-value columns import as whatever the source tool serialized them as (typically comma-separated). Run a follow-up cleanup query if you need them as separate records.
- Timezone-naive dates. Pipedrive exports dates as
YYYY-MM-DDwith no timezone. CCD treats them as UTC midnight. If you need local-time semantics, convert before upload. - Phone formatting. No tool normalizes — every export is a
mishmash of
+1-555-...,(555) 555-1234, etc. CCD stores them verbatim; use the formatting helper in Contact detail if you want E.164 later.
Rolling back
Every import creates an import_batches row with all the data
needed to undo. Settings → Import → click a batch → "Roll back". The
rollback is row-precise (deletes only the rows this batch inserted,
preserves edits made since).
Roll back is destructive — once executed it can't be re-executed for the same batch. If you're unsure, take a
ccd backup createfirst (self-host) or download a DSAR export (cloud).
Read next
- REST API reference — full schema for
/api/v1/import+ the bulk endpoint contract. - Settings → Import — UI walkthrough.
- CRM module — what the imported data becomes downstream.