Pipedrive to Power BI: illustrative current-snapshot example
Prepared 17 October 2026

All account keys, numeric IDs, titles, cursors, dates, probabilities and values
are synthetic teaching inputs. The JSON contains response-shaped subsets plus
separate teaching metadata, not a live API export or a complete API schema.
It contains no customer records, credentials, API request identifiers or contacts.

FILES AND LOCAL CHECK
pipedrive-source.json: seven synthetic deals, pipeline/stage lookups and page cursors.
deals-snapshot.csv: five current, non-archived, non-deleted reporting rows.
normalise-pipedrive.py: standard-library local normaliser and fixture checks.
measures.dax: seven measures for a table named PipedriveDeals.
expected-results.csv: independent numerical controls and explicit scope counts.

Extract the ZIP, then run from any directory with Python 3:
python3 /path/to/normalise-pipedrive.py --check
Without --check, the script regenerates deals-snapshot.csv beside itself.
It reads only the local fixture, makes no network calls and never changes a CRM.
--write-zip additionally rebuilds the deterministic download ZIP.

WHAT THIS SNAPSHOT MEANS
One synthetic account and one pipeline are captured at 2026-10-14T23:59:59Z.
The fact grain is one visible, non-archived, non-deleted deal at this snapshot.
All included values are GBP. There is no currency conversion. The normaliser
rejects mixed included currencies rather than adding them as if they were GBP.
The two source deal pages deliberately include a deleted row. A separate archived
endpoint-shaped page contains an archived won deal. Both are excluded from this
reporting scope, giving seven source rows and five staged rows.

Do not append repeated copies of this snapshot. The account key and deal ID are
unique within it; a repeated run replaces the CSV. A production current-state
store should upsert by account + deal ID and reconcile archive/deletion changes.
If you preserve multiple snapshots for history, add snapshot time to the grain
and filter to one snapshot before using these measures. Adding snapshot totals
would count the same opportunity repeatedly.

PROBABILITY AND CONTROLS
This example explicitly enables deal probability for its pipeline. A present
deal probability overrides stage probability; an explicit zero stays zero.
When deal probability is null, use stage probability. If neither is configured,
use 100%. Deal and stage probabilities are not multiplied together.
Open A: 10,000 x 20% stage fallback = 2,000.
Open B: 20,000 x 50% deal override = 10,000, even though its stage is 60%.
Open C: 5,000 x 0% deal override = 0, even though its stage is 60%.
Open count = 3; open value = GBP 35,000; weighted open value = GBP 12,000.
Won value = GBP 12,000; lost value = GBP 8,000.
Closed deals = 1 won + 1 lost = 2. Closed-deal win rate = 1 / 2 = 50%.

Weighted value is a probability-weighted planning number, not recognised revenue,
cash received or a promise of future sales. The win rate is the status mix of
closed deals in this visible current snapshot, not a historical cohort conversion
rate or the company's lifetime performance. Won value also describes deal status,
not accounting revenue. Archived/deleted/hidden deals change the reporting scope.

IMPORT TO POWER BI
Import deals-snapshot.csv as UTF-8 comma-separated text, with headers, and name
the table PipedriveDeals. Use whole numbers for IDs; decimal numbers for value and
probability columns; text for statuses/currency/account key. Blank probabilities
must stay null rather than zero. Parse snapshot_at, won_time, lost_time and
update_time as date/time/timezone with UTC; expected_close_date is date-only.
For a UTC date-only visual, derive its date after explicitly converting to UTC.
Import the seven DAX measures individually. Display monetary measures as GBP,
Open Deals/Closed Deals as whole numbers and Closed Deal Win Rate as a percentage.
Compare the controls before adding slicers, relationships or a date table.

The Python mapping and exact arithmetic have been executed locally. The DAX is
provided as a model definition for review. No credentialed Pipedrive request,
Power BI Desktop, DAX engine or Power BI Service refresh has been executed here.
This ZIP is a local teaching fixture, not a production connector or a PBIX file.

SOURCE TO STAGED FIELDS
deal_id <- deal.id; deal_title <- deal.title; status <- deal.status;
value/currency <- deal.value/deal.currency; owner_id <- deal.owner_id;
pipeline_id and stage_id join to the separate lookup IDs for names/probability.
deal_probability_pct <- deal.probability; stage_probability_pct <- stage.deal_probability.
effective_probability_pct/probability_source are derived with null-aware fallback.
snapshot_at/account_key come from teaching metadata, not returned deal fields.
Archived provenance comes from the separate archived-deals response group; no
invented is_archived field is presented as part of a Pipedrive deal response.
The source is a current-state subset. It does not supply stage-change history,
activities, custom-field definitions, product facts or deleted-record history.
Avoid one-to-many product/activity joins that multiply deal rows and value.

CURRENT CONNECTION NOTES AND PRIMARY SOURCES
Pipedrive's reference pages have /docs/api/v1/ in their URLs while documenting
selected v2 methods. Prefer /api/v2/deals, /pipelines, /stages and /dealFields
where available. Use additional_data.next_cursor until null, including lookup
pages. A failed/incomplete page must not be published as a complete snapshot.
Current docs specify x-api-token header for API-token integrations and OAuth for
apps. Store secrets outside public downloads and PBIX query text. OAuth deals:read
covers the relevant reads; authorisation and user visibility still bound coverage.
Deals lists omit archived deals; retrieve them separately if your scope includes
them. Deleted status is returned only when requested, for up to 30 days after
deletion. Build ongoing reconciliation rather than relying on a one-off export.
updated_since is inclusive and updated_until exclusive in RFC3339. Advance a
watermark only after every page succeeds. Stage movement requires changelogs or
snapshots captured over time; the current stage does not reconstruct the journey.

https://developers.pipedrive.com/docs/api/v1/Deals
https://developers.pipedrive.com/docs/api/v1/Pipelines
https://developers.pipedrive.com/docs/api/v1/Stages
https://developers.pipedrive.com/docs/api/v1/DealFields
https://pipedrive.readme.io/docs/core-api-concepts-pagination
https://pipedrive.readme.io/docs/core-api-concepts-authentication
https://pipedrive.readme.io/docs/marketplace-scopes-and-permissions-explanations
https://pipedrive.readme.io/docs/pipedrive-api-v2-migration-guide
https://support.pipedrive.com/en/article/probability-in-pipedrive

For scheduled reporting, first load into an access-controlled, supported source.
Keep extractor freshness separate from semantic-model refresh success. Microsoft
documents eight scheduled daily refreshes on shared capacity and up to 48 on
Premium/PPU/Fabric capacity; connection credentials/gateway requirements still
apply. RelativePath/Query can help some Web.Contents sources refresh, but do not
by themselves implement secure Pipedrive OAuth, pagination or token rotation.
https://learn.microsoft.com/en-us/power-bi/connect-data/refresh-data
https://learn.microsoft.com/en-us/powerquery-m/web-contents
