Connectors
/
Pipedrive
Live · 68 tools

Pipedrive Integration for AI Agents

The Pipedrive API is well-documented. Getting your agent to call it correctly — for real users, with rotating tokens, company-scoped URLs, and scopes that block installs when mismatched — is the part that takes longer than it should.
Pipedrive
Live

CRM

Sales

Status
Live
Tools
68 pre-built
Auth
OAuth 2.0
Credential storage
Sandbox support

OAuth 2.0

Auto token refresh

Revocation detection

BYOC required

The real problem

Why this is harder than it looks

Pipedrive's API is REST, well-documented, and easy to prototype against. Most developers estimate a day or two to wire up a working integration. The problems arrive when you try to run it for multiple real users over time.

The first surprise is Pipedrive's token rotation behavior. When you refresh an access token, Pipedrive issues a new refresh token alongside the new access token — and the old refresh token is invalidated immediately. If your backend doesn't capture and store the new refresh token on every refresh cycle, the next refresh will fail with an invalid_grant error. This is silent in development (tokens last long enough that you may never hit it) but catastrophic in production, where background agents refresh tokens constantly across many users. Developers routinely discover this only after users start getting logged out inexplicably.

Then there's the company-domain issue. Every Pipedrive API call must go to {COMPANYDOMAIN}.pipedrive.com — the base URL is specific to each user's Pipedrive company account. You need to capture the api_domain from the initial token exchange response and store it per-user. If you miss this and hardcode a base URL, every call silently routes to the wrong endpoint for any user whose domain differs.

Pipedrive also requires you to register your own OAuth app in Developer Hub — there is no managed app. Scopes are declared at app registration and requested at authorization time; a mismatch between the two blocks installation with an error your users cannot resolve themselves. And refresh tokens expire after 60 days of inactivity, which means users on low-frequency workflows need re-authorization — and password changes immediately invalidate all their refresh tokens.

Scalekit handles token rotation, per-user domain storage, scope configuration, and revocation detection. Your agent names a tool and passes parameters. Everything else is invisible.

Capabilities

What your agent can do with Pipedrive

Once connected, your agent has 68 pre-built tools covering the full Pipedrive CRM model:

  • Manage deals end-to-end: create, update, move between stages, search by keyword or filter, and list with pagination — including product and participant sub-resources
  • Work with persons and organizations: create and update contacts, search by name or email, list deals per person or org for complete account context
  • Convert and track leads: create unqualified leads, update and archive them, search across titles and notes, and convert to deals once qualified
  • Schedule and query activities: create calls, meetings, emails, and tasks linked to any CRM object; filter by date range, type, or completion status
  • Attach notes and files: create pinned notes on deals, persons, orgs, or leads; upload files and link them to any object
  • Manage pipelines, stages, products, and goals: introspect and update the full sales workflow structure; create and track quota goals per user or team
Setup context

What we're building

This guide connects a sales assistant agent to Pipedrive — helping reps manage their pipeline, log activities, and update CRM records without leaving your product.

🤖
Example agent
Sales assistant creating deals, scheduling follow-up activities, and updating pipeline stages on behalf of each rep
🔐
Auth model
B2B SaaS — each rep connects their own Pipedrive account. identifier = your user ID
⚙️
Scalekit account
app.scalekit.com — Client ID, Secret, Env URL
🔑
Pipedrive OAuth app
Register at developers.pipedrive.com — required for BYOC setup
Setup

1 Setup: One SDK, One credential

Install the Scalekit SDK. The only credential your application manages is the Scalekit API key — no Pipedrive secrets, no user tokens, nothing belonging to your customers.

pip install scalekit-sdk-python
npm install @scalekit-sdk/node
import scalekit.client import os from dotenv import load_dotenv load_dotenv() scalekit = scalekit.client.ScalekitClient( client_id=os.getenv("SCALEKIT_CLIENT_ID"), client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"), env_url=os.getenv("SCALEKIT_ENV_URL"), ) actions = scalekit.actions
import { ScalekitClient } from '@scalekit-sdk/node'; import 'dotenv/config'; const scalekit = new ScalekitClient( process.env.SCALEKIT_ENV_URL, process.env.SCALEKIT_CLIENT_ID, process.env.SCALEKIT_CLIENT_SECRET ); const actions = scalekit.actions;
Already have credentials?
Connected Accounts

2 Per-User Auth: Creating connected accounts

Each rep gets their own Connected Account, giving them a dedicated auth context. The identifier is any unique string from your system — a UUID, email, whatever you use internally.

response = actions.get_or_create_connected_account( connection_name="pipedrive", identifier="user_pd_456" # your internal user ID ) connected_account = response.connected_account print(f"Status: {connected_account.status}") # Status: PENDING — user hasn't authorized yet
const response = await actions.getOrCreateConnectedAccount({ connectionName: "pipedrive", identifier: "user_pd_456" // your internal user ID }); const connectedAccount = response.connectedAccount; console.log(`Status: ${connectedAccount.status}`); // Status: PENDING — user hasn't authorized yet

This call is idempotent — safe to call on every session start. Returns the existing account if one already exists.

Authorization Flow

3 The authorization flow

The rep authorizes your agent once. Scalekit generates the OAuth URL with correct scopes, redirect handling, and state pre-configured. After approval, you never see the token.

if connected_account.status != "ACTIVE": link = actions.get_authorization_link( connection_name="pipedrive", identifier="user_pd_456" ) # Redirect user → Pipedrive consent screen # Scalekit captures the token on callback return redirect(link.link)
if (connectedAccount.status !== "ACTIVE") { const { link } = await actions.getAuthorizationLink({ connectionName: "pipedrive", identifier: "user_pd_456" }); // Redirect user → Pipedrive consent screen // Scalekit captures the token on callback return redirect(link); }
Token management is automatic
After the user approves, Scalekit stores encrypted tokens — including the per-user company domain — and the connected account moves to ACTIVE. Access tokens are refreshed proactively before expiry, and the rotated refresh token is captured on every cycle. If a rep revokes access from Pipedrive or changes their password, the account moves to REVOKED — no silent invalid_grant failures. Check account.status before critical operations.
BYOC is required for Pipedrive
Pipedrive requires you to register your own app in Developer Hub and supply your own Client ID and Client Secret. Create your app at developers.pipedrive.com, paste the Scalekit redirect URI as the callback URL, configure your scopes, then enter credentials in the Scalekit dashboard. Token management stays fully handled.
Calling Pipedrive

4 Calling Pipedrive: What your agent writes

With the connected account active, your agent calls Pipedrive actions using execute_tool. Name the tool, pass parameters. Scalekit handles token retrieval, request construction, and response parsing.

Create a deal and schedule a follow-up call

The most common first action for a sales agent — create a deal linked to a person and org, then schedule the discovery call in one workflow.

deal = actions.execute_tool( identifier="user_pd_456", tool_name="pipedrive_deal_create", tool_input={ "title": "Acme Corp — Enterprise Plan", "value": 48000, "currency": "USD", "person_id": 1042, "org_id": 305, "stage_id": 2, "expected_close_date": "2026-06-30" } ) deal_id = deal["data"]["id"] activity = actions.execute_tool( identifier="user_pd_456", tool_name="pipedrive_activity_create", tool_input={ "subject": "Discovery call — Acme Corp", "type": "call", "deal_id": deal_id, "due_date": "2026-04-07", "due_time": "10:00", "duration": "00:30" } ) # Returns: { "id": 88, "subject": "Discovery call — Acme Corp", ... }
const deal = await actions.executeTool({ identifier: "user_pd_456", toolName: "pipedrive_deal_create", toolInput: { title: "Acme Corp — Enterprise Plan", value: 48000, currency: "USD", person_id: 1042, org_id: 305, stage_id: 2, expected_close_date: "2026-06-30" } }); const dealId = deal.data.id; const activity = await actions.executeTool({ identifier: "user_pd_456", toolName: "pipedrive_activity_create", toolInput: { subject: "Discovery call — Acme Corp", type: "call", deal_id: dealId, due_date: "2026-04-07", due_time: "10:00", duration: "00:30" } }); // Returns: { id: 88, subject: "Discovery call — Acme Corp", ... }

Search for a person and attach a note

Look up a contact by name, then pin a contextual note to their record. Useful for post-call logging workflows.

results = actions.execute_tool( identifier="user_pd_456", tool_name="pipedrive_persons_search", tool_input={"term": "Jane Smith", "exact_match": False, "limit": 5} ) persons = results["data"]["items"] if persons: person_id = persons[0]["item"]["id"] actions.execute_tool( identifier="user_pd_456", tool_name="pipedrive_note_create", tool_input={ "content": "Spoke with Jane re: renewal. Budget confirmed for Q2.", "person_id": person_id, "pinned_to_person_flag": True } )
const results = await actions.executeTool({ identifier: "user_pd_456", toolName: "pipedrive_persons_search", toolInput: { term: "Jane Smith", exact_match: false, limit: 5 } }); const persons = results.data.items; if (persons.length > 0) { const personId = persons[0].item.id; await actions.executeTool({ identifier: "user_pd_456", toolName: "pipedrive_note_create", toolInput: { content: "Spoke with Jane re: renewal. Budget confirmed for Q2.", person_id: personId, pinned_to_person_flag: true } }); }

Move a deal to the next pipeline stage

Fetch the deal's current stage, resolve the pipeline stages in order, then advance the deal. Always fetch stages at runtime — stage IDs differ per workspace.

deal = actions.execute_tool( identifier="user_pd_456", tool_name="pipedrive_deal_get", tool_input={"deal_id": 9871} ) current_stage = deal["data"]["stage_id"] stages = actions.execute_tool( identifier="user_pd_456", tool_name="pipedrive_stages_list", tool_input={"pipeline_id": deal["data"]["pipeline_id"]} ) stage_ids = sorted(s["id"] for s in stages["data"]) next_stage = stage_ids[stage_ids.index(current_stage) + 1] actions.execute_tool( identifier="user_pd_456", tool_name="pipedrive_deal_update", tool_input={"deal_id": 9871, "stage_id": next_stage} )
const deal = await actions.executeTool({ identifier: "user_pd_456", toolName: "pipedrive_deal_get", toolInput: { deal_id: 9871 } }); const currentStage = deal.data.stage_id; const stages = await actions.executeTool({ identifier: "user_pd_456", toolName: "pipedrive_stages_list", toolInput: { pipeline_id: deal.data.pipeline_id } }); const stageIds = stages.data.map(s => s.id).sort((a, b) => a - b); const nextStage = stageIds[stageIds.indexOf(currentStage) + 1]; await actions.executeTool({ identifier: "user_pd_456", toolName: "pipedrive_deal_update", toolInput: { deal_id: 9871, stage_id: nextStage } });

List deals with a reusable filter

Create a saved filter for high-value open deals, then pass its ID to pipedrive_deals_list for fast, repeatable queries without rebuilding filter logic on every call.

import json filter_result = actions.execute_tool( identifier="user_pd_456", tool_name="pipedrive_filter_create", tool_input={ "name": "High-value open deals", "type": "deals", "conditions": json.dumps({ "glue": "and", "conditions": [{ "glue": "and", "conditions": [ {"object": "deal", "field_id": "status", "operator": "=", "value": "open", "extra_value": None}, {"object": "deal", "field_id": "value", "operator": ">", "value": "50000", "extra_value": None} ] }] }) } ) filter_id = filter_result["data"]["id"] deals = actions.execute_tool( identifier="user_pd_456", tool_name="pipedrive_deals_list", tool_input={"filter_id": filter_id, "limit": 50} ) # Returns: list of deals matching the saved filter
const filterResult = await actions.executeTool({ identifier: "user_pd_456", toolName: "pipedrive_filter_create", toolInput: { name: "High-value open deals", type: "deals", conditions: JSON.stringify({ glue: "and", conditions: [{ glue: "and", conditions: [ { object: "deal", field_id: "status", operator: "=", value: "open", extra_value: null }, { object: "deal", field_id: "value", operator: ">", value: "50000", extra_value: null } ] }] }) } }); const filterId = filterResult.data.id; const deals = await actions.executeTool({ identifier: "user_pd_456", toolName: "pipedrive_deals_list", toolInput: { filter_id: filterId, limit: 50 } }); // Returns: list of deals matching the saved filter
Framework wiring

5 Wiring into your agent framework

Scalekit's tools load directly into LangChain. The agent decides what to call; Scalekit handles auth on every invocation. No token plumbing in your agent logic.

from langchain_anthropic import ChatAnthropic from langchain.agents import AgentExecutor, create_tool_calling_agent from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from scalekit.langchain import get_tools pd_tools = get_tools( connection_name="pipedrive", identifier="user_pd_456" ) prompt = ChatPromptTemplate.from_messages([ ("system", "You are a sales assistant. Use the available tools to help manage Pipedrive deals, contacts, and activities."), MessagesPlaceholder("chat_history", optional=True), ("human", "{input}"), MessagesPlaceholder("agent_scratchpad"), ]) agent = create_tool_calling_agent(ChatAnthropic(model="claude-sonnet-4-6"), pd_tools, prompt) result = AgentExecutor(agent=agent, tools=pd_tools).invoke({ "input": "Find all open deals over $50k and schedule a follow-up call for each one due this week" })
import { ChatAnthropic } from "@langchain/anthropic"; import { AgentExecutor, createToolCallingAgent } from "langchain/agents"; import { ChatPromptTemplate, MessagesPlaceholder } from "@langchain/core/prompts"; import { getTools } from "@scalekit-sdk/langchain"; const pdTools = getTools({ connectionName: "pipedrive", identifier: "user_pd_456" }); const prompt = ChatPromptTemplate.fromMessages([ ["system", "You are a sales assistant. Use the available tools to help manage Pipedrive deals, contacts, and activities."], new MessagesPlaceholder("chat_history", true), ["human", "{input}"], new MessagesPlaceholder("agent_scratchpad"), ]); const agent = await createToolCallingAgent({ llm: new ChatAnthropic({ model: "claude-sonnet-4-6" }), tools: pdTools, prompt }); const result = await AgentExecutor.fromAgentAndTools({ agent, tools: pdTools }).invoke({ input: "Find all open deals over $50k and schedule a follow-up call for each one due this week" });
Other frameworks supported
Tool reference

All 68 Pipedrive tools

Grouped by object and capability. Your agent calls tools by name — no API wrappers to write.

Deals
pipedrive_deal_create
Create a deal with title (required), value, currency, stage, linked person and org, close date, and probability
pipedrive_deal_get
Retrieve full deal details by ID, including linked person, org, stage, and custom fields
pipedrive_deal_update
Update any deal field — stage, value, close date, status, owner. Only supplied fields are changed
pipedrive_deal_delete
Permanently delete a deal by ID
pipedrive_deals_list
List deals with filtering by status, stage, pipeline, owner, or saved filter ID. Supports pagination and sort
pipedrive_deals_search
Search deals by keyword across title, notes, and custom fields with optional person or org scope
pipedrive_deal_activities_list
List all activities linked to a deal, filtered by completion status
pipedrive_deal_products_list
List all products attached to a deal with unit price, quantity, and discount per line
pipedrive_deal_participants_list
List all person participants linked to a deal beyond the primary contact
Persons
pipedrive_person_create
Create a contact with name (required), email, phone, org association, and marketing consent status
pipedrive_person_get
Retrieve a person by ID including linked org, deals, and custom fields
pipedrive_person_update
Update any person field — name, email, phone, org, marketing status
pipedrive_person_delete
Permanently delete a person by ID
pipedrive_persons_list
List persons with optional filter ID, first-character filter, pagination, and sort
pipedrive_persons_search
Search persons by keyword across name, email, phone, and custom fields
Organizations
pipedrive_organization_create
Create an org with name (required), owner, address, and visibility
pipedrive_organization_get
Retrieve an org by ID including linked persons and deals
pipedrive_organization_update
Update any org field — name, owner, address, visibility
pipedrive_organization_delete
Permanently delete an org by ID
pipedrive_organizations_list
List orgs with filter ID, first-character filter, pagination, and sort
pipedrive_organizations_search
Search orgs by keyword across name, address, and notes
pipedrive_organization_deals_list
List all deals linked to an org, filtered by status — useful for account-level pipeline views
pipedrive_person_deals_list
List all deals linked to a specific person, filtered by status
Leads
pipedrive_lead_create
Create a lead with title (required), linked person or org, value, and expected close date
pipedrive_lead_get
Retrieve a lead by UUID
pipedrive_lead_update
Update any lead field or archive/unarchive it
pipedrive_lead_delete
Permanently delete a lead by UUID
pipedrive_leads_list
List leads with optional archived-status filter and pagination
pipedrive_leads_search
Search leads by keyword across title, notes, and linked person or org
Activities
pipedrive_activity_create
Create a call, meeting, email, task, or custom activity linked to any CRM object
pipedrive_activity_get
Retrieve an activity by ID
pipedrive_activity_update
Update any activity field including marking it done
pipedrive_activity_delete
Permanently delete an activity by ID
pipedrive_activities_list
List activities with filtering by type, user, date range, or completion status
pipedrive_activity_types_list
List all activity types configured in the account — use to validate type values before creating activities
Notes
pipedrive_note_create
Create a note (HTML allowed) and optionally pin it to a deal, person, org, or lead
pipedrive_note_get
Retrieve a note and its metadata by ID
pipedrive_note_update
Update note content or pin status
pipedrive_note_delete
Permanently delete a note by ID
pipedrive_notes_list
List notes filtered by linked object (deal, person, org, or lead), date range, or pin status
Files
pipedrive_file_upload
Upload a file (base64 or public URL) and attach it to any CRM object
pipedrive_file_get
Retrieve file metadata and download URL by ID
pipedrive_file_delete
Permanently delete a file by ID
pipedrive_files_list
List all account files with pagination, sort, and optional inclusion of soft-deleted files
Pipelines & Stages
pipedrive_pipeline_create
Create a new sales pipeline with name and optional probability tracking
pipedrive_pipeline_get
Retrieve pipeline details and its stages by ID
pipedrive_pipeline_update
Update pipeline name, probability tracking, display order, or active state
pipedrive_pipeline_delete
Permanently delete a pipeline and its stages (deals are not deleted)
pipedrive_pipelines_list
List all pipelines in the account — no parameters required
pipedrive_stage_create
Create a stage within a pipeline with default probability and optional rotting rules
pipedrive_stage_get
Retrieve a stage by ID
pipedrive_stage_update
Update stage name, probability, rotting rules, display order, or active state
pipedrive_stages_list
List all stages, optionally filtered to a specific pipeline — use to resolve stage IDs before creating deals
Products & Goals
pipedrive_product_create
Create a product catalog entry with name, SKU, price, tax, and category
pipedrive_product_get
Retrieve product details by ID
pipedrive_product_update
Update any product field — name, code, price, tax, category
pipedrive_product_delete
Permanently delete a product by ID
pipedrive_products_list
List all catalog products with optional filter ID, pagination, and sort
pipedrive_goal_create
Create a quota goal for a user or company with type, target, tracking metric, and reporting interval
pipedrive_goal_get
Retrieve goal details and current progress by UUID
pipedrive_goal_update
Update goal target, assignee, duration, or reporting interval
pipedrive_goals_list
List goals filtered by type name, assignee, or active status
Users, Webhooks & Filters
pipedrive_user_get
Retrieve a user by ID including role, email, and active status
pipedrive_users_list
List all users in the account — no parameters required
pipedrive_webhook_create
Register a webhook for real-time notifications on any object type and action (added, updated, deleted, or all)
pipedrive_webhook_delete
Delete a webhook subscription by ID — stops notifications immediately
pipedrive_webhooks_list
List all active webhook subscriptions for the account
pipedrive_filter_create
Create a reusable saved filter for deals, leads, persons, orgs, products, or activities
pipedrive_filter_get
Retrieve a saved filter and its conditions by ID
pipedrive_filters_list
List all saved filters, optionally scoped to a specific object type
Connector notes

Pipedrive-specific behavior

Refresh token rotation — capture the new token on every refresh
Pipedrive rotates refresh tokens on every access token refresh. The old refresh token is invalidated the moment a new one is issued. If your system doesn't capture and store the new refresh token on each cycle, the next refresh will fail with invalid_grant. Scalekit handles this automatically — the rotated token is captured and stored on every refresh without any code changes on your end.
Stage and pipeline IDs differ per workspace
Pipedrive stage and pipeline IDs are integers assigned per account — they are not consistent across customer workspaces. Always call pipedrive_stages_list or pipedrive_pipelines_list at runtime to resolve IDs before creating or updating deals. An agent that hardcodes stage IDs will silently write to the wrong stage for other customers.
Leads use UUIDs; most other objects use integer IDs
Deals, persons, organizations, activities, notes, and most other objects use integer IDs. Leads and goals use UUIDs. Pass the correct type for each tool's ID parameter — mixing them returns a 404, not a type error.
Infrastructure decision

Why not build this yourself

The Pipedrive OAuth flow is documented. Token storage isn't technically hard. But here's what you're actually signing up for:

PROBLEM 01
Refresh token rotation — Pipedrive invalidates the old refresh token the moment you use it, so missing the new token in your storage layer locks users out with no warning
PROBLEM 02
Per-user company domain — every API call must go to that user's specific Pipedrive subdomain, which must be captured at token exchange time and stored alongside the token
PROBLEM 03
Revocation on password change — all refresh tokens are immediately invalidated when a user changes their password, requiring graceful re-authorization prompts in your product
PROBLEM 04
Per-user token isolation across a multi-tenant system — one rep's Pipedrive credentials must never be accessible to another, even within the same organization

That's one connector. Your agent product will eventually need Salesforce, HubSpot, Gmail, Linear, and whatever else your customers ask for. Each has its own OAuth quirks and failure modes.

Scalekit maintains every connector. You maintain none of them.

Ready to ship

Connect Pipedrive in minutes

Free to start. Token rotation fully handled.