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.
pdcli backup # → ./pipedrive-backuppdcli backup --dir ./my-backup # choose the directorypdcli backup --dir ./my-backup --resume # skip resources already doneThe default directory is pipedrive-backup in the current working directory.
What gets exported
Section titled “What gets exported”18 resources, fetched sequentially. Each becomes a <name>.json file containing the full
list of items:
| File | Source | Pager |
|---|---|---|
deals.json | /api/v2/deals | v2 cursor |
persons.json | /api/v2/persons | v2 cursor |
organizations.json | /api/v2/organizations | v2 cursor |
activities.json | /api/v2/activities | v2 cursor |
products.json | /api/v2/products | v2 cursor |
pipelines.json | /api/v2/pipelines | v2 cursor |
stages.json | /api/v2/stages | v2 cursor |
dealFields.json | /api/v2/dealFields | v2 cursor |
personFields.json | /api/v2/personFields | v2 cursor |
organizationFields.json | /api/v2/organizationFields | v2 cursor |
productFields.json | /api/v2/productFields | v2 cursor |
activityFields.json | /api/v2/activityFields | v2 cursor |
leads.json | /api/v1/leads | v1 offset |
notes.json | /api/v1/notes | v1 offset |
users.json | /api/v1/users | plain |
filters.json | /api/v1/filters | plain |
webhooks.json | /api/v1/webhooks | plain |
currencies.json | /api/v1/currencies | plain |
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).
The manifest and --resume
Section titled “The manifest and --resume”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:
pdcli backup --dir ./my-backup --resumeBackup complete: 4/18 resources exported to ./my-backup (14 skipped)Without --resume, a fresh run starts a new manifest and re-exports everything.
Token-cost awareness
Section titled “Token-cost awareness”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.
Scheduling
Section titled “Scheduling”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:
# nightly at 02:00 — see CI recipes for full examples0 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.
Diffing snapshots: backup diff
Section titled “Diffing snapshots: backup diff”Because pdcli owns the backup format, it can diff two snapshots entirely locally — zero API calls. Point it at two backup directories (older first):
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.
Incremental export: sync warehouse
Section titled “Incremental export: sync warehouse”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:
pdcli sync warehouse --dir ./warehouse # first run seeds a full exportpdcli sync warehouse --dir ./warehouse # later runs append only deltaspdcli sync warehouse --dir ./warehouse --full # rebuild from scratchEach 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.