Skip to main content
RapidDev - Software Development Agency
v0-integrationsNext.js API Route

How to Integrate Pipedrive with V0

To integrate Pipedrive with V0 by Vercel, generate a sales pipeline dashboard UI with V0, create Next.js API routes that call Pipedrive's REST API using your personal or service account API token, store the token in Vercel environment variables, and deploy. Your app can display deals, contacts, activities, and pipeline stages without exposing your API token to the browser.

What you'll learn

  • How to obtain a Pipedrive API token and structure authenticated REST API requests
  • How to build a custom sales pipeline dashboard with V0 showing deals and stage progression
  • How to create Next.js API routes that read and write Pipedrive deals, persons, and activities
  • How to create new Pipedrive deals and contacts from V0-generated forms
  • How to store Pipedrive credentials in Vercel environment variables and deploy securely
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate16 min read35 minutesMarketingApril 2026RapidDev Engineering Team
TL;DR

To integrate Pipedrive with V0 by Vercel, generate a sales pipeline dashboard UI with V0, create Next.js API routes that call Pipedrive's REST API using your personal or service account API token, store the token in Vercel environment variables, and deploy. Your app can display deals, contacts, activities, and pipeline stages without exposing your API token to the browser.

Build Custom Sales Dashboards and Automate CRM Operations with Pipedrive and V0

Pipedrive is built around the philosophy of activity-based selling — the idea that consistent, tracked activities (calls, emails, meetings) lead to closed deals. Its visual pipeline interface is one of the most intuitive in the CRM space, making it popular with small and mid-size sales teams. While Pipedrive has a powerful native interface, sales operations teams often need custom dashboards that surface specific metrics, automate deal creation from external sources like web forms or API events, or present pipeline data in formats tailored to executive reporting needs. V0 lets you rapidly generate these custom sales UIs.

Pipedrive's API is a well-documented REST API with comprehensive coverage of all CRM entities: deals (the opportunities moving through the pipeline), persons (individual contacts), organizations (companies), activities (calls, meetings, tasks), products, and custom fields. The API uses token authentication and follows predictable REST conventions — GET to list and fetch resources, POST to create, PUT/PATCH to update, DELETE to remove. Pagination uses the start and limit query parameters, and most list endpoints support filtering, sorting, and field selection.

For V0-generated apps, the most impactful Pipedrive integration scenarios are custom pipeline dashboards with revenue forecasting that present data differently than Pipedrive's native view, lead capture forms that automatically create Pipedrive persons and deals without manual data entry, and activity tracking dashboards that show which sales reps are most active and which deals are stagnating without recent contact.

Integration method

Next.js API Route

Pipedrive integrates with V0-generated Next.js apps through server-side API routes that call Pipedrive's REST API using an API token. Your API token is stored as a server-only Vercel environment variable and never reaches the browser. V0-generated UI components fetch sales pipeline data from your Next.js API routes, which query Pipedrive for deals, persons, organizations, and activities. For CRM operations like creating deals or updating stages, the same routes use Pipedrive's write endpoints. OAuth2 is available for multi-user apps where each user connects their own Pipedrive account.

Prerequisites

  • A Pipedrive account — available at pipedrive.com with a 14-day free trial (API access available on all plans)
  • Your Pipedrive API token — go to Settings → Personal Preferences → API in your Pipedrive account and copy your personal API token
  • A pipeline configured in Pipedrive with at least one stage — note the Pipeline ID and Stage IDs from Settings → Pipelines
  • A V0 account at v0.dev for generating the dashboard UI and a Vercel account for deployment
  • Basic familiarity with REST APIs — Pipedrive uses standard HTTP methods and query parameters

Step-by-step guide

1

Generate the Sales Dashboard UI with V0

Open V0 at v0.dev and describe the Pipedrive sales interface you want to build. Sales dashboards work best when they immediately surface the information sales managers or reps need for their daily workflow — deal totals by stage, overdue activities, deals without recent activity, or revenue vs target. When prompting V0, describe the key metrics prominently, the pipeline visualization style (Kanban columns, table with status badges, or a funnel chart), and any filtering controls (by owner, date range, or pipeline). V0 generates React components with shadcn/ui — Table, Card, Badge, Progress, and Select components are particularly useful for CRM dashboards. Include the specific API endpoint paths you plan to create (/api/pipedrive/deals, /api/pipedrive/activities) so V0's generated fetch calls match your backend implementation. For deal cards, describe the fields you want visible at a glance versus in an expanded detail view — keeping cards concise prevents the dashboard from feeling cluttered. After V0 generates the UI, use the Git panel to push to your GitHub repository.

V0 Prompt

Build a Pipedrive sales dashboard with a sticky top nav showing 'Sales Pipeline' title, total pipeline value, and a refresh button. Below, show a horizontal stage pipeline view with stage columns: Qualified Lead / Demo Scheduled / Proposal Sent / Negotiation / Closed Won. Each column has a deal count badge and total stage value. Deal cards within each column show company name, deal title, value in bold, owner first name, and expected close date with a warning icon if overdue. Include a sidebar filter for 'My Deals' vs 'All Deals' and a search input. Load data from /api/pipedrive/deals. Use Pipedrive's green accent color.

Paste this in V0 chat

Pro tip: Ask V0 to add a 'stale deal' indicator — a yellow border on deal cards where the last activity was more than 14 days ago. This is one of the most actionable signals in a sales dashboard and encourages reps to follow up on neglected deals.

Expected result: A Pipedrive-style sales pipeline dashboard renders in V0's preview with stage columns, deal cards, and filtering controls. Components reference /api/pipedrive/deals for data.

2

Create the Pipedrive API Routes for Deals

Pipedrive's REST API uses simple token authentication: append the API token to each request URL as a query parameter (api_token=YOUR_TOKEN) or pass it in the Authorization header as a Bearer token — the header approach is preferred. The API base URL is https://api.pipedrive.com/v1. The deals endpoint at /v1/deals supports filtering with status (open, won, lost, all_not_deleted), pipeline_id, stage_id, user_id (for filtering by sales rep), and start/limit for pagination. Each deal response includes the deal's title, value, currency, status, expected_close_date, person_id, organization_id, and custom field values. The stage_id field links to your pipeline stages, and person_name/org_name are included as convenience fields so you don't need separate lookups for basic display. Create a deals API route that fetches the open deals with pagination support and returns them grouped by stage for the Kanban view. Include the total count (from the additional_data.pagination.total_count field in the response) for progress indicators. For the pipeline summary stats (total value, weighted value), calculate these server-side from the deals array before returning to the frontend.

app/api/pipedrive/deals/route.ts
1// app/api/pipedrive/deals/route.ts
2import { NextRequest, NextResponse } from 'next/server';
3
4const PIPEDRIVE_BASE = 'https://api.pipedrive.com/v1';
5
6async function pipedriveGet<T = unknown>(path: string, params: Record<string, string> = {}): Promise<T> {
7 const token = process.env.PIPEDRIVE_API_TOKEN;
8 if (!token) throw new Error('PIPEDRIVE_API_TOKEN is not configured');
9
10 const url = new URL(`${PIPEDRIVE_BASE}${path}`);
11 url.searchParams.set('api_token', token);
12 Object.entries(params).forEach(([key, val]) => url.searchParams.set(key, val));
13
14 const response = await fetch(url.toString(), {
15 headers: { Accept: 'application/json' },
16 next: { revalidate: 60 }, // Cache for 60 seconds
17 });
18
19 if (!response.ok) throw new Error(`Pipedrive API error: ${response.status}`);
20
21 const result = await response.json();
22 if (!result.success) throw new Error(result.error || 'Pipedrive API request failed');
23
24 return result.data;
25}
26
27interface PipedriveDeal {
28 id: number;
29 title: string;
30 value: number;
31 currency: string;
32 status: string;
33 stage_id: number;
34 stage_order_nr: number;
35 probability: number | null;
36 expected_close_date: string | null;
37 person_name: string | null;
38 org_name: string | null;
39 owner_name: string;
40 add_time: string;
41 update_time: string;
42 activities_count: number;
43 last_activity_date: string | null;
44}
45
46export async function GET(request: NextRequest) {
47 try {
48 const { searchParams } = new URL(request.url);
49 const pipelineId = searchParams.get('pipelineId') || '';
50 const userId = searchParams.get('userId') || '';
51 const status = searchParams.get('status') || 'open';
52
53 const params: Record<string, string> = { status, limit: '500' };
54 if (pipelineId) params.pipeline_id = pipelineId;
55 if (userId) params.user_id = userId;
56
57 const deals = await pipedriveGet<PipedriveDeal[]>('/deals', params);
58
59 // Group deals by stage for Kanban view
60 const dealsByStage = deals.reduce<Record<number, PipedriveDeal[]>>((acc, deal) => {
61 const stageId = deal.stage_id;
62 if (!acc[stageId]) acc[stageId] = [];
63 acc[stageId].push(deal);
64 return acc;
65 }, {});
66
67 // Calculate pipeline summary
68 const totalValue = deals.reduce((sum, d) => sum + (d.value || 0), 0);
69 const weightedValue = deals.reduce(
70 (sum, d) => sum + (d.value || 0) * ((d.probability || 0) / 100),
71 0
72 );
73
74 return NextResponse.json({
75 deals,
76 dealsByStage,
77 summary: {
78 totalDeals: deals.length,
79 totalValue,
80 weightedValue: Math.round(weightedValue),
81 },
82 });
83 } catch (error) {
84 const message = error instanceof Error ? error.message : 'Unknown error';
85 console.error('Pipedrive deals fetch failed:', message);
86 return NextResponse.json({ error: message }, { status: 500 });
87 }
88}

Pro tip: Add next: { revalidate: 60 } to your Pipedrive fetch calls to enable Next.js ISR caching — this means the pipeline data is refreshed every 60 seconds rather than on every page visit, significantly reducing API calls on a high-traffic dashboard.

Expected result: GET /api/pipedrive/deals returns a list of open deals grouped by stage with a pipeline summary including total value and weighted pipeline value based on deal probabilities.

3

Create the Lead Capture and Deal Creation Route

The deal creation route handles creating new Pipedrive person records and linked deals programmatically. Pipedrive's data model requires creating the person first (contact record), then creating a deal linked to that person. The POST /v1/persons endpoint creates a new contact with fields like name, email, phone, org_id (linked organization), and any custom field values. The POST /v1/deals endpoint then creates the deal with title, value, currency, pipeline_id, stage_id, person_id (from the created person), and expected_close_date. If the lead mentions a company, create or find an organization with POST /v1/organizations before creating the person. You can search for existing organizations with GET /v1/organizations/search?term=COMPANY_NAME to avoid creating duplicates. For lead capture forms, a practical approach is to create the person and deal in a single server-side function, handling the three-step flow (find/create org, create person, create deal) atomically before returning success to the frontend. Include the source information as a note attached to the deal using POST /v1/notes with the deal_id — this preserves the full context of how the lead arrived without cluttering Pipedrive's built-in fields.

V0 Prompt

Add a 'Quick Add Deal' button in the dashboard header that opens a modal form. The form has fields for deal title (required), company name, contact name, contact email, deal value with currency selector (USD/EUR/GBP), expected close date, and pipeline stage dropdown. On submit, POST to /api/pipedrive/create-deal. After success, show a toast 'Deal created in Pipedrive' and add the new deal card to the appropriate stage column without a page reload. Include a link to open the deal in Pipedrive in the success toast.

Paste this in V0 chat

app/api/pipedrive/create-deal/route.ts
1// app/api/pipedrive/create-deal/route.ts
2import { NextRequest, NextResponse } from 'next/server';
3
4const PIPEDRIVE_BASE = 'https://api.pipedrive.com/v1';
5
6function pipedriveUrl(path: string): string {
7 const url = new URL(`${PIPEDRIVE_BASE}${path}`);
8 url.searchParams.set('api_token', process.env.PIPEDRIVE_API_TOKEN!);
9 return url.toString();
10}
11
12async function pipedrivePost<T>(path: string, body: Record<string, unknown>): Promise<T> {
13 const response = await fetch(pipedriveUrl(path), {
14 method: 'POST',
15 headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
16 body: JSON.stringify(body),
17 });
18 const result = await response.json();
19 if (!result.success) throw new Error(result.error || 'Pipedrive request failed');
20 return result.data;
21}
22
23interface CreateDealRequest {
24 title: string;
25 contactName: string;
26 contactEmail: string;
27 companyName?: string;
28 value?: number;
29 currency?: string;
30 stageId?: number;
31 expectedCloseDate?: string;
32 source?: string;
33}
34
35export async function POST(request: NextRequest) {
36 try {
37 const body: CreateDealRequest = await request.json();
38 const { title, contactName, contactEmail, companyName, value, currency, stageId, source } = body;
39
40 if (!title || !contactName || !contactEmail) {
41 return NextResponse.json({ error: 'title, contactName, and contactEmail are required' }, { status: 400 });
42 }
43
44 // Step 1: Create or find organization
45 let orgId: number | undefined;
46 if (companyName) {
47 const org = await pipedrivePost<{ id: number }>('/organizations', { name: companyName });
48 orgId = org.id;
49 }
50
51 // Step 2: Create person (contact)
52 const person = await pipedrivePost<{ id: number }>('/persons', {
53 name: contactName,
54 email: [{ value: contactEmail, primary: true }],
55 org_id: orgId,
56 });
57
58 // Step 3: Create the deal linked to person and org
59 const deal = await pipedrivePost<{ id: number; title: string }>('/deals', {
60 title,
61 person_id: person.id,
62 org_id: orgId,
63 value: value || 0,
64 currency: currency || 'USD',
65 stage_id: stageId || process.env.PIPEDRIVE_DEFAULT_STAGE_ID,
66 });
67
68 // Step 4: Add a note with source context
69 if (source) {
70 await pipedrivePost('/notes', {
71 content: `Lead source: ${source}`,
72 deal_id: deal.id,
73 });
74 }
75
76 return NextResponse.json({
77 success: true,
78 deal: { id: deal.id, title: deal.title },
79 person: { id: person.id },
80 });
81 } catch (error) {
82 const message = error instanceof Error ? error.message : 'Unknown error';
83 console.error('Pipedrive deal creation failed:', message);
84 return NextResponse.json({ error: message }, { status: 500 });
85 }
86}

Pro tip: Store your default Pipedrive stage ID (the initial stage for new leads) as a PIPEDRIVE_DEFAULT_STAGE_ID environment variable rather than hardcoding it — this lets you change the entry stage for new deals without code changes.

Expected result: POST /api/pipedrive/create-deal creates a person record, optionally an organization, and a linked deal in Pipedrive. The deal appears in the specified pipeline stage and is linked to the new contact.

4

Configure Vercel Environment Variables and Deploy

Configure Pipedrive credentials in Vercel before deploying. Open the Vercel Dashboard, navigate to your project, and go to Settings → Environment Variables. Add PIPEDRIVE_API_TOKEN with your Pipedrive API token — this is found in your Pipedrive account under Settings → Personal Preferences → API. The token is a 40-character alphanumeric string. Do not use the NEXT_PUBLIC_ prefix — this token must remain server-only since it grants write access to your CRM data. Optionally add PIPEDRIVE_DEFAULT_PIPELINE_ID with the numeric ID of your primary pipeline (found in Pipedrive under Settings → Pipelines) and PIPEDRIVE_DEFAULT_STAGE_ID with your entry stage ID. Set all variables for Production, Preview, and Development, then save. Add the same variables to .env.local for local testing. After deploying, open your Vercel deployment URL and verify that the pipeline dashboard shows your actual Pipedrive deals. If you see 401 errors, your token may have expired or been regenerated — refresh the token in Pipedrive and update the variable. For multi-user apps where each user connects their own Pipedrive account, implement OAuth2 instead of the single API token approach — the OAuth flow is more complex but allows each user to authenticate with their own Pipedrive credentials.

Pro tip: Test your Pipedrive API token quickly by visiting https://api.pipedrive.com/v1/users/me?api_token=YOUR_TOKEN in your browser — if you see your user details, the token is valid and working.

Expected result: The Vercel deployment succeeds and the Pipedrive sales dashboard displays real deal data grouped by pipeline stage, with totals and weighted pipeline value calculated from your actual CRM data.

Common use cases

Sales Pipeline Revenue Dashboard

A visual pipeline overview showing all active deals grouped by stage, with total deal value per stage, weighted probability-adjusted revenue, and a conversion rate summary. The dashboard gives sales managers a single-page summary of pipeline health that's easier to reference in weekly sales meetings than navigating through Pipedrive's native UI.

V0 Prompt

Build a sales pipeline dashboard with a Kanban-style view showing deal stages as columns (Qualified/Contact Made/Demo Scheduled/Proposal Sent/Closed Won/Closed Lost). Each column shows total deal count and total value in USD. Deal cards show company name, deal title, deal value, owner name, expected close date, and a colored probability indicator. Include a top summary bar with total pipeline value, weighted value, and win rate percentage. Load data from /api/pipedrive/deals. Use a professional CRM aesthetic with blue and white color scheme.

Copy this prompt to try it in V0

Lead-to-Deal Capture Form

A public-facing contact form that automatically creates a Pipedrive person record and a linked deal when a lead submits their information. Sales reps see new leads appear directly in their Pipedrive pipeline without any manual data entry, with the lead source, message, and initial stage all pre-populated.

V0 Prompt

Create a professional lead capture form with fields for first name, last name, company name, work email, phone number, approximate budget (dropdown: Under $5K / $5K-$20K / $20K-$100K / $100K+), and a project description textarea. On submit, POST to /api/pipedrive/create-lead. Show a thank you page with next steps after successful submission. Include field validation and a loading state. The form should look like a premium consulting firm's contact page with a clean white card layout.

Copy this prompt to try it in V0

Deal Activity Tracker for Sales Reps

An internal dashboard showing each sales rep's activity log — calls made, emails sent, meetings scheduled — over the past week alongside their deal pipeline status. Managers can quickly identify reps with low activity on high-value deals and prioritize coaching conversations.

V0 Prompt

Design a sales activity dashboard with a row per sales rep showing their name, avatar initials, number of activities this week (calls/emails/meetings with icons), pipeline deal count, total pipeline value, and a 'Last Activity' date. Sort by activity count descending. Add a week navigator (Previous/Current Week) at the top. Click a rep row to expand and show their open deals with next scheduled activity. Data loads from /api/pipedrive/activities and /api/pipedrive/deals. Use a dark header with white content cards.

Copy this prompt to try it in V0

Troubleshooting

Pipedrive API returns 401 Unauthorized

Cause: The PIPEDRIVE_API_TOKEN environment variable is missing, expired, or incorrect. Pipedrive API tokens are static but can be regenerated by the user in their account settings.

Solution: Log into Pipedrive and navigate to Settings → Personal Preferences → API. Regenerate or copy the current API token and update PIPEDRIVE_API_TOKEN in Vercel (Settings → Environment Variables). After updating, trigger a redeployment from the Deployments tab.

Deals list returns empty array even though deals exist in Pipedrive

Cause: The status parameter is filtering to only 'open' deals but your deals have different statuses, or the pipeline_id filter is scoping to a pipeline with no deals.

Solution: Try fetching with status=all_not_deleted to include all deal statuses. If you're filtering by pipeline_id, verify the ID matches your actual pipeline (Settings → Pipelines in Pipedrive). You can also test the API directly at https://api.pipedrive.com/v1/deals?api_token=YOUR_TOKEN to see what the raw response looks like.

typescript
1// Fetch all deals without status filter for debugging:
2const deals = await pipedriveGet('/deals', { status: 'all_not_deleted', limit: '10' });

create-deal route creates a new organization for each lead even when the company already exists

Cause: The route always creates a new organization record rather than searching for an existing one first, creating duplicate company records in Pipedrive.

Solution: Before creating a new organization, search for existing ones with GET /v1/organizations/search?term=COMPANY_NAME. If a match is found, use the existing org ID. Only create a new organization if the search returns no results.

typescript
1// Search for existing org before creating:
2const searchRes = await pipedriveGet<{ items: Array<{ item: { id: number; name: string } }> }>(
3 '/organizations/search',
4 { term: companyName, limit: '1' }
5);
6const existingOrg = searchRes.items?.[0]?.item;
7const orgId = existingOrg ? existingOrg.id : (await pipedrivePost<{ id: number }>('/organizations', { name: companyName })).id;

Pipeline dashboard loads slowly with many deals

Cause: The deals endpoint is fetching all deals without a limit, or the client is making multiple sequential API calls for deals, stages, and users separately.

Solution: Add a reasonable limit (200-500) to the deals fetch and implement pagination. Use Promise.all to fetch deals, pipelines, and stages in parallel from a single summary API route rather than making sequential requests from the frontend.

Best practices

  • Use server-side API routes for all Pipedrive calls — never expose PIPEDRIVE_API_TOKEN to the browser with NEXT_PUBLIC_ prefix since it grants full CRM write access
  • Cache pipeline data with Next.js fetch revalidation (next: { revalidate: 60 }) to reduce API call frequency on dashboards that multiple users view simultaneously
  • Search for existing persons and organizations before creating new ones to prevent duplicate CRM records that degrade data quality over time
  • Store pipeline and stage IDs as Vercel environment variables rather than hardcoding them so you can change the pipeline structure without code changes
  • For lead capture forms, add honeypot fields or rate limiting to prevent bots from flooding your Pipedrive account with fake deals
  • Include the lead source in a Pipedrive note when creating deals from external forms — this tracking information is valuable for conversion analysis and must be preserved explicitly
  • Implement OAuth2 for multi-user apps where different team members need separate Pipedrive connections — the single API token approach is appropriate only for single-account integrations

Alternatives

Frequently asked questions

Does Pipedrive offer OAuth2 or is API token the only authentication method?

Pipedrive supports both personal API tokens (for single-account integrations) and OAuth2 (for multi-user apps where each user authorizes your app to access their Pipedrive account). The API token approach is simpler and appropriate for internal dashboards. OAuth2 is required if you're building a product that connects to multiple different Pipedrive accounts — for example, an agency building dashboards for clients who each have their own Pipedrive account.

How do I find my Pipedrive pipeline ID and stage IDs?

Navigate to Settings → Company Settings → Pipelines in Pipedrive to see your pipeline list. The pipeline ID appears in the URL when you click on a pipeline. Stage IDs can be fetched programmatically from the Pipedrive API at GET /v1/stages?pipeline_id=YOUR_ID, or you can view them in the Pipedrive API documentation explorer. You can also find IDs by calling GET /v1/pipelines to list all pipelines with their IDs.

Can Pipedrive send webhooks to my Vercel app when deals are updated?

Yes — Pipedrive supports webhooks for events like deal created, deal updated, deal deleted, person created, and activity completed. Configure webhooks in Pipedrive under Settings → Company Settings → Webhooks, pointing to your Vercel API route URL (e.g., /api/pipedrive/webhook). Pipedrive sends a POST request with the event type and changed object data whenever a matching event occurs.

What is Pipedrive's API rate limit?

Pipedrive's API rate limit is 80 requests per 2 seconds per API token on all plans. This translates to approximately 2,400 requests per minute — much higher than most CRM APIs. For typical dashboard use cases, you are very unlikely to hit this limit unless you are building a real-time sync that processes large volumes of data in short bursts.

How do I filter deals to show only my team's deals, not the entire company pipeline?

Use the user_id query parameter on the /v1/deals endpoint to filter deals by sales rep. Pass the Pipedrive user ID of the rep — you can fetch user IDs from GET /v1/users. For the authenticated user's own deals, call GET /v1/users/me to get the current user's ID. If you implement OAuth2, each user's token will naturally scope deal visibility to their assigned deals.

Can I create custom fields in Pipedrive and populate them via the API?

Yes — Pipedrive allows creating custom fields on deals, persons, and organizations through the Fields API. Custom fields are identified by auto-generated alphanumeric keys (like abc123def456). Fetch your deal's custom fields with GET /v1/dealFields to see their keys, then include those keys in your create/update requests. Custom field values follow the same JSON structure as built-in fields.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.