/claim #16797

What does this PR do?

  • Removes all Revert.dev usage for the Pipedrive integration.
  • Implements native Pipedrive OAuth2 (authorization + token exchange + refresh).
  • Adds direct Pipedrive API calls (persons/activities) using Bearer tokens.
  • Adds frontend “Connect Pipedrive” button to start OAuth flow.
  • Persists tokens securely in Cal.com credential storage (Prisma credential row).

Fixes:

  • Fixes #16797
  • Fixes #22492

Files changed (key)

  • packages/app-store/pipedrive-crm/api/auth.ts (new) — GET /api/integrations/pipedrive/auth → redirects to Pipedrive authorize URL
  • packages/app-store/pipedrive-crm/api/callback.ts (new) — GET /api/integrations/pipedrive/callback → exchanges code for tokens, persists credential
  • packages/app-store/pipedrive-crm/lib/CrmService.ts (modified) — native token refresh + Pipedrive API calls (persons/activities)
  • packages/app-store/pipedrive-crm/config.json (modified) — metadata update
  • packages/app-store/pipedrive-crm/components/EventTypeAppCardInterface.tsx (modified) — “Connect Pipedrive” button UI
  • packages/app-store/_utils/oauth/refreshOAuthTokens.ts (updated) — adapter for Pipedrive refresh
  • packages/app-store/_utils/oauth/createOAuthAppCredential.ts (used) — persists credential (no secret leaks)

Note: No Revert.dev references remain in runtime paths for the Pipedrive integration.

Short description of OAuth flow (in-code comments included)

  1. Frontend triggers GET /api/integrations/pipedrive/auth (via “Connect Pipedrive” button).
  2. Server builds redirect to: https://oauth.pipedrive.com/oauth/authorize?client_id=&redirect_uri=/api/integrations/pipedrive/callback&response_type=code&state=
  3. User authorizes; Pipedrive redirects to: GET /api/integrations/pipedrive/callback?code=…&state=…
  4. Callback exchanges code for access_token + refresh_token at https://oauth.pipedrive.com/oauth/token (POST, form-encoded) using client_id & client_secret stored in Cal.com app keys.
  5. Tokens + expiryDate persisted to Prisma credential record via createOAuthAppCredential.
  6. CrmService reads credential.key token object, checks expiryDate before API calls; if expired, refreshes using refresh_token at /oauth/token and persists updated tokens.
  7. Pipedrive API calls use Authorization: Bearer . On refresh, CrmService retries the call.

Error handling

  • 400 returned when client_id / client_secret missing in app keys.
  • Token exchange and refresh failures return clear errors and are logged.
  • Revoked tokens require reconnect; frontend surfaces errors and user can reconnect.
  • credential.key is never exposed in API responses.

How to test locally

Environment setup

  • Configure Pipedrive app keys (client_id, client_secret) in Cal.com app-store for the pipedrive-crm slug (do not commit secrets).
  • Set: WEBAPP_URL_FOR_OAUTH=http://localhost:3000

Register Pipedrive OAuth app with redirect URI:

  • /api/integrations/pipedrive/callback

Run

  • yarn dev (or yarn dx)

Test steps

  1. Open app-store UI or an event-type app card and click “Connect Pipedrive.”
  2. Complete OAuth consent in Pipedrive.
  3. Verify credential record created in DB containing access_token, refresh_token, expiryDate.
  4. Trigger a flow that creates a contact or activity — confirm Pipedrive API requests succeed.
  5. To test refresh: set expiryDate in DB to a past time, trigger an API call — verify tokens refresh automatically and DB updates.
  6. To test disconnect/reconnect: delete credential record and repeat OAuth flow.

Expected behavior

  • OAuth completes successfully.
  • Tokens are stored and refreshed automatically.
  • Pipedrive API calls succeed.
  • No Revert.dev or “pipedrive client id missing” errors occur.

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code.
  • I have updated developer docs in /docs if needed (N/A).
  • I confirm automated tests are in place (manual test steps provided; add unit/integration tests on request).

Checklist

  • Title follows conventional commits: feat(pipedrive-crm): …
  • Type check locally: run yarn type-check:ci --force on changed files
  • Biome formatting applied for changed files
  • No secrets or API keys committed
  • credential.key is not exposed in any API responses
  • Draft PR recommended

Notes / Follow-ups

  • I reused existing app-store OAuth helpers (createOAuthAppCredential, refreshOAuthTokens) to preserve credential persistence and sync endpoint behavior.
  • I can add unit tests for token exchange/refresh flows and run CI checks on request.
  • Please validate translations for any new UI strings; I can add entries to apps/web/public/static/locales/en/common.json.

Claim

Total prize pool $50
Total paid $0
Status Pending
Submitted January 05, 2026
Last updated January 05, 2026

Contributors

KA

Karrrthik7

@Karrrthik7

100%

Sponsors

CA

Cal.com, Inc.

@cal

$50