Migrate to CCD

Three ways to move data from your current tool into CCD, in order of how much manual work each requires:

  1. OAuth connector — link your account, click "Sync now". Best when you have a HubSpot or Salesforce login and outbound network.
  2. File upload — export from your old tool, upload the CSV/XLSX in Settings → Import. Best for everyone else.
  3. Offline CLIccd 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 use test.salesforce.com by setting SALESFORCE_LOGIN_HOST=test.salesforce.com in 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 typeCCD table
Sales pipelinedeals
Contact listcontacts
Company listcompanies
Tasks / projectsactivities

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:

  1. Settings → Import → "New import"
  2. Pick target module + table
  3. Upload the file (CSV, XLSX, or JSON array)
  4. CCD suggests a mapping based on header similarity — confirm or adjust per column
  5. Choose duplicate behaviour (skip / update / create-new)
  6. 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 use ccd_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_name or last_name is 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-DD with 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 create first (self-host) or download a DSAR export (cloud).

Read next