Skip to content
pdcli
Get started

Full-account backup

pdcli backup exports your entire account to a directory of JSON files — one per resource — with a manifest checkpoint written after each resource so an interrupted run can pick up where it left off.

Terminal window
pdcli backup # → ./pipedrive-backup
pdcli backup --dir ./my-backup # choose the directory
pdcli backup --dir ./my-backup --resume # skip resources already done

The default directory is pipedrive-backup in the current working directory.

18 resources, fetched sequentially. Each becomes a <name>.json file containing the full list of items:

FileSourcePager
deals.json/api/v2/dealsv2 cursor
persons.json/api/v2/personsv2 cursor
organizations.json/api/v2/organizationsv2 cursor
activities.json/api/v2/activitiesv2 cursor
products.json/api/v2/productsv2 cursor
pipelines.json/api/v2/pipelinesv2 cursor
stages.json/api/v2/stagesv2 cursor
dealFields.json/api/v2/dealFieldsv2 cursor
personFields.json/api/v2/personFieldsv2 cursor
organizationFields.json/api/v2/organizationFieldsv2 cursor
productFields.json/api/v2/productFieldsv2 cursor
activityFields.json/api/v2/activityFieldsv2 cursor
leads.json/api/v1/leadsv1 offset
notes.json/api/v1/notesv1 offset
users.json/api/v1/usersplain
filters.json/api/v1/filtersplain
webhooks.json/api/v1/webhooksplain
currencies.json/api/v1/currenciesplain

The five *Fields.json files are your field definitions — including the per-account custom-field hash keys and their option labels — so a restored record's custom_fields hashes stay meaningful. Core CRM uses v2; leads, notes, users, filters, webhooks, and currencies come from v1 (which is where those endpoints live).

After each resource is written, pdcli updates manifest.json in the backup directory with the completed resources and their item counts:

{
"started_at": "2026-06-04T09:00:00.000Z",
"completed": ["deals", "persons", "organizations"],
"counts": { "deals": 1840, "persons": 5210, "organizations": 612 },
"updated_at": "2026-06-04T09:01:12.000Z"
}

If the run is interrupted, re-run with --resume and pdcli skips every resource already in the manifest, refetching only what's missing:

Terminal window
pdcli backup --dir ./my-backup --resume
Backup complete: 4/18 resources exported to ./my-backup (14 skipped)

Without --resume, a fresh run starts a new manifest and re-exports everything.

The export is sequential by design to keep the rate-limit budget predictable. Each list page costs 20 tokens; the client's 429 backoff handles any bursts (see How pdcli talks to Pipedrive). A large account with hundreds of pages will take time — that's the trade for not tripping the limiter.

Because backup is one non-interactive command with a deterministic exit code, it drops straight into cron or CI. Use env-var auth so nothing prompts:

Terminal window
# nightly at 02:00 — see CI recipes for full examples
0 2 * * * PDCLI_COMPANY_DOMAIN=acme PDCLI_API_TOKEN=$PD_TOKEN \
pdcli backup --dir /backups/pipedrive-$(date +\%F)

For incremental safety on a flaky link, point repeated runs at the same directory with --resume. See CI recipes for a scheduled-job example.

Because pdcli owns the backup format, it can diff two snapshots entirely locally — zero API calls. Point it at two backup directories (older first):

Terminal window
pdcli backup diff ./backup-2026-06-10 ./backup-2026-06-11
┌───────────┬─────┬──────────┬────────────┬──────────┬──────────┐
│ Resource │ ID │ Change │ Field │ Old │ New │
├───────────┼─────┼──────────┼────────────┼──────────┼──────────┤
│ deals │ 42 │ modified │ value │ 100000 │ 150000 │
│ deals │ 42 │ modified │ Region │ EMEA │ APAC │
│ deals │ 99 │ added │ │ │ │
│ persons │ 7 │ removed │ │ │ │
└───────────┴─────┴──────────┴────────────┴──────────┴──────────┘
3 added · 1 removed · 5 modified (11 field changes)

Each record is classified added / removed / modified, and every changed field is one row with its old → new value. Custom-field hash keys and option ids are resolved to names and labels using each snapshot's own captured *Fields.json (still no network); pass --raw to keep the raw hashes. Resources present in only one snapshot are reported separately rather than shown as wholesale added/removed. --output json emits the full { summary, skipped, changes } object for diffing in CI.

Where backup writes a full snapshot every run, sync warehouse appends only what changed since the last run — an incremental NDJSON feed for loading into a data warehouse:

Terminal window
pdcli sync warehouse --dir ./warehouse # first run seeds a full export
pdcli sync warehouse --dir ./warehouse # later runs append only deltas
pdcli sync warehouse --dir ./warehouse --full # rebuild from scratch

Each of the five incremental entities (deals, persons, organizations, activities, products) appends to <entity>.ndjson (one JSON object per line) and advances its own high-water mark in manifest.json. The watermark moves to the newest update_time seen + 1 second (the API's updated_since is inclusive, so this avoids re-emitting the boundary record), and only after the append succeeds — an interrupted run replays rather than skips. --since overrides the start for every entity.

pdcli v0.18.0 · MIT · not affiliated with Pipedrive