Pipedrive integration
Create TimeTracking clients and placements from won Pipedrive deals using Pipedrive webhooks and idempotent external-ID upserts.
Last updated: · Markdown version
1. Summary
Status: Recipe (no native connector).
Direction: Pipedrive to TimeTracking (clients, placements). Optional: approved totals back to a deal field.
2. Mechanism
- Pipedrive side. Webhook
updated.deal(v1) orchange.deal(v2); filter on status changed towon. Read organization and person via/v1/organizations/{id},/v1/persons/{id}. Custom fields are keyed by hash ids. - Glue. Receiver or iPaaS (Zapier, Make, n8n).
- TimeTracking side.
PUT /clients/by-external/pipedrive/{orgId},PUT /people/by-external/pipedrive/{personId},PUT /placements/by-external/pipedrive/{dealId}. - Totals back (optional).
GET /days?from&to&placement_id=…&status=approved.
Assumption — verify with your Pipedrive admin: which custom fields hold start date, end date, worker and employee number.
3. Prerequisites
- Pipedrive API token and admin rights for webhooks.
- Custom deal fields: start date, end date, job title.
- TimeTracking API key (
write).
4. Entity mapping
| Pipedrive object.field | TimeTracking field | Notes |
|---|---|---|
Organization id |
client external ref | |
Organization name |
client name |
|
Person (worker) id |
person external ref | Only if workers are Pipedrive persons. |
first_name, last_name, email[0].value, phone[0].value |
person fields | |
| Person custom "Employee number" | employeeNumber |
|
Deal id |
placement external ref; ref PD-<id> |
|
| Deal custom start / end | startsOn / endsOn |
|
Deal title / custom job title |
roleTitle |
|
| Deal lost/closed after start | DELETE /placements/{id} (deactivate) |
External-ID strategy. source = pipedrive. No ids need to be written back to Pipedrive: the deal id is the key. Upserts are full replaces.
5. Step-by-step setup
- Add the Pipedrive webhook (
updated.deal) to your receiver; protect it with HTTP basic auth. - Ignore events unless
current.status == "won"andprevious.status != "won"(or the date fields changed on a won deal). - Upsert:
curl -s -X PUT "$TT/clients/by-external/pipedrive/311" -H "Authorization: Bearer $KEY" -H "content-type: application/json" \
-d '{"name":"Logistiek Parkstad","externalRef":"311"}'
curl -s -X PUT "$TT/people/by-external/pipedrive/9001" -H "Authorization: Bearer $KEY" -H "content-type: application/json" \
-d '{"employeeNumber":"1002","firstName":"Fatima","lastName":"El Amrani","email":"fatima@example.com"}'
curl -s -X PUT "$TT/placements/by-external/pipedrive/4410" -H "Authorization: Bearer $KEY" -H "content-type: application/json" \
-H "Idempotency-Key: pd-deal-4410-won" \
-d '{"personExternalRef":"9001","clientExternalRef":"311","ref":"PD-4410","roleTitle":"Orderpicker","startsOn":"2026-11-02","endsOn":"2027-01-29"}'
6. Sync schedule and triggering events
| Trigger | Action |
|---|---|
updated.deal to won |
Upsert client, person, placement. |
| Date fields changed on a won deal | Upsert placement again (full replace). |
timesheet.approved (optional) |
GET /days?placement_id=…&status=approved&from&to, write the sum to a deal field. |
7. Corrections, conflicts and locked periods
TimeTracking owns hours, conflicts and locks. Recompute totals from GET /days (never increment). Ending a placement before existing hours returns 409.
8. Testing checklist
- Winning a test deal returns
created: true; re-saving returnscreated: false. - Changing the end date updates
endsOn. - Losing or reopening a deal creates nothing.
9. Troubleshooting
| Error | Fix |
|---|---|
422 "Person and client must exist …" |
Upsert person and client first (same source). |
422 on dates |
Empty custom date field; skip or default. |
409 |
Placement shortened before existing hours. |
429 |
Wait Retry-After. |
10. Limits and known gaps
No client-contact API. Native Pipedrive marketplace app (OAuth2): Planned.
11. Build it with Claude
Build a Make (or n8n) scenario: Pipedrive webhook updated.deal → filter status changed to won → get organization
and person → TimeTracking PUT /clients/by-external/pipedrive/{orgId} {name} →
PUT /people/by-external/pipedrive/{personId} {firstName, lastName, email, employeeNumber} →
PUT /placements/by-external/pipedrive/{dealId} {personExternalRef, clientExternalRef, ref "PD-<id>", roleTitle,
startsOn, endsOn}. Base https://app.timetracking.tech/api/v1, Bearer key, responses { data } / { error }.
Ask me for my custom field hashes. Error route for 409/422/429.