Skip to content

CRM-Oktivo App Integration Documentation ​

Table of Contents ​

  1. Overview
  2. Architecture
  3. Data Models
  4. API Endpoints
  5. File Changes
  6. Environment Configuration
  7. UI Testing Guide
  8. API Testing Guide
  9. Troubleshooting

Overview ​

This integration enables CRM users to initiate browser-based calls (WebRTC) to prospects via the Oktivo App voice platform. Key features:

  • OAuth Connection: CRM organizations connect to Oktivo App accounts for shared credits
  • Browser-to-Phone Calls: WebRTC audio from browser routed via LiveKit/SIP to prospect's phone
  • Call Recording: Automatic recording of all calls
  • AI Transcription: Speech-to-text with speaker labels (CRM User / Prospect)
  • AI Analysis: Sentiment classification, summary, and key points extraction
  • Call History: Full history with recordings, transcriptions, and analysis per lead

Architecture ​

High-Level System Diagram ​

OAuth Connection Flow ​

Call Flow ​

Post-Call Processing Flow ​


Data Models ​

OktivoConnection (CRM Database) ​

Stores OAuth connection for CRM organizations.

typescript
// File: oktivo_crm/backend/src/models/OktivoConnection.ts

interface IOktivoConnection {
  connectionId: string;              // "oktivo_conn_xxx"
  organizationId: ObjectId;          // CRM Organization (unique)
  oktivoAccountId: string;           // Connected Oktivo org ID
  oktivoAccountName: string;         // Display name
  encryptedAccessToken: string;      // AES-256-GCM encrypted
  encryptedRefreshToken: string;     // AES-256-GCM encrypted
  tokenExpiresAt: Date;              // Token expiration
  status: 'connected' | 'disconnected' | 'token_expiring';
  scopes: string[];                  // Granted OAuth scopes
  createdAt: Date;
  updatedAt: Date;
}

Indexes:

  • organizationId: 1 (unique)
  • connectionId: 1 (unique)
  • tokenExpiresAt: 1
  • status: 1

CrmConnection (Oktivo Database) ​

Stores CRM client registrations.

typescript
// File: oktivo_voice/backend/client_backend/src/models/CrmConnection.ts

interface ICrmConnection {
  connectionId: string;              // "crm_conn_xxx"
  oktivoOrgId: ObjectId;             // Oktivo organization
  crmOrganizationId: string;         // CRM organization ID
  crmOrganizationName: string;       // Display name
  status: 'active' | 'revoked';
  grantedScopes: string[];
  lastActivityAt: Date;
  createdAt: Date;
  updatedAt: Date;
}

Indexes:

  • oktivoOrgId: 1, crmOrganizationId: 1 (unique)
  • connectionId: 1 (unique)
  • status: 1

HumanCall (Oktivo Database) ​

Records browser-to-phone calls.

typescript
// File: oktivo_voice/backend/client_backend/src/models/HumanCall.ts

interface IHumanCall {
  callId: string;                    // "hcall_xxx"
  crmConnectionId: string;
  crmOrganizationId: string;
  crmUserId: string;
  leadPhone: string;                 // E.164 format
  leadName: string;
  livekitRoomName: string;           // "hcall-room-xxx"
  status: 'connecting' | 'ringing' | 'in_progress' | 'ended' | 'failed';
  initiatedAt: Date;
  answeredAt: Date | null;
  endedAt: Date | null;
  duration: number | null;           // seconds
  disconnectReason: string | null;
  recordingUrl: string | null;
  transcription: {
    text: string;
    segments: Array<{
      speaker: 'crm_user' | 'prospect';
      text: string;
      startTime: number;
      endTime: number;
    }>;
    processedAt: Date;
  } | null;
  analysis: {
    sentiment: 'positive' | 'neutral' | 'negative';
    summary: string;                 // 2-4 sentences
    keyPoints: string[];             // 3-5 items
    processedAt: Date;
  } | null;
  transcriptionStatus: 'pending' | 'processing' | 'completed' | 'failed';
  analysisStatus: 'pending' | 'processing' | 'completed' | 'failed';
  creditsCost: number | null;
}

Indexes:

  • callId: 1 (unique)
  • crmOrganizationId: 1, initiatedAt: -1
  • leadPhone: 1, initiatedAt: -1
  • status: 1
  • transcriptionStatus: 1, analysisStatus: 1

API Endpoints ​

CRM Backend Routes (/api/oktivo/*) ​

MethodPathAuthDescription
GET/auth/urlJWTGenerate OAuth authorization URL
GET/auth/callbackPublicHandle OAuth callback
GET/connectionJWTGet connection status
DELETE/connectionJWTDisconnect integration
GET/creditsJWTGet credit balance
POST/calls/:leadIdJWTInitiate call to lead
POST/calls/directJWTDirect call (no lead lookup)
GET/calls/:callIdJWTGet call details
GET/calls/lead/:leadId/historyJWTGet lead's call history
GET/calls/historyJWTGet call history by phone

Oktivo Backend Routes (/api/crm/*) ​

MethodPathAuthDescription
POST/oauth/tokenClient credentialsExchange code for tokens
POST/oauth/refreshClient credentialsRefresh access token
GET/creditsBearer tokenGet credit balance
POST/callsBearer tokenInitiate human call
GET/calls/historyBearer tokenGet paginated call history
GET/calls/:callIdBearer tokenGet call details
POST/calls/:callId/endBearer tokenEmergency call termination

Request/Response Examples ​

Initiate Call (Oktivo Backend):

http
POST /api/crm/calls
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "phone": "+919876543210",
  "name": "John Doe",
  "crmUserId": "user_123",
  "crmOrganizationId": "org_456"
}

Response:

json
{
  "callId": "hcall_abc123",
  "roomName": "hcall-room-abc123",
  "roomToken": "eyJ...",
  "sipPhoneNumber": "+1234567890"
}

Get Call Details:

json
{
  "callId": "hcall_abc123",
  "status": "ended",
  "duration": 145,
  "recordingUrl": "https://s3.../recording.mp3",
  "transcription": {
    "text": "Hello, I'm calling about...",
    "segments": [
      { "speaker": "crm_user", "text": "Hello...", "startTime": 0, "endTime": 3.5 },
      { "speaker": "prospect", "text": "Hi...", "startTime": 3.5, "endTime": 7.2 }
    ]
  },
  "analysis": {
    "sentiment": "positive",
    "summary": "Productive call about 3BHK property interest...",
    "keyPoints": [
      "Interested in 3BHK property",
      "Budget around 80 lakhs",
      "Prefers south Bangalore"
    ]
  }
}

File Changes ​

CRM Repository (oktivo_crm/) ​

New Files Created ​

FileDescription
backend/src/models/OktivoConnection.tsMongoDB model for OAuth connections
backend/src/repositories/OktivoConnectionRepository.tsCRUD operations
backend/src/services/OktivoOAuthService.tsOAuth: auth URL, token exchange, refresh
backend/src/services/OktivoApiClient.tsHTTP client with auto token refresh
backend/src/routes/oktivo.routes.tsExpress routes for /api/oktivo/*
backend/src/controllers/oktivo.controller.tsRoute handlers
backend/src/config/oktivo.config.tsConfiguration
app/src/services/oktivoApi.tsFrontend API client
app/src/hooks/useOktivoConnection.tsConnection state hook
app/src/hooks/useCallStatus.tsCall status via LiveKit data channel
app/src/hooks/useWebRTCReconnect.tsAuto-reconnect logic
app/src/components/Settings/OktivoIntegration.tsxSettings UI component
app/src/components/CallPanel/CallPanel.tsxCall UI with controls
app/src/components/CallPanel/CallControls.tsxMute/End buttons
app/src/components/CallPanel/CallStatus.tsxStatus display
app/src/components/Lead/CallHistory.tsxCall history list
app/src/components/Lead/CallHistoryItem.tsxIndividual call record
app/src/utils/callErrors.tsError message mapping
app/src/pages/OktivoOAuthCallbackPage.tsxOAuth callback handler

Modified Files ​

FileChange
backend/src/app.tsAdded oktivoRoutes at /api/oktivo
backend/.env.exampleAdded Oktivo OAuth variables
app/src/components/LeadDetail.tsxAdded CallHistory component
app/src/components/IntegrationsTab.tsxAdded OktivoIntegration component
app/package.jsonAdded livekit-client: ^2.20.1

Oktivo Voice Repository (oktivo_voice/backend/client_backend/) ​

New Files Created ​

FileDescription
src/models/CrmConnection.tsMongoDB model for CRM connections
src/models/HumanCall.tsMongoDB model for call records
src/repositories/CrmConnectionRepository.tsCRUD operations
src/repositories/HumanCallRepository.tsCRUD + queries
src/middleware/crmAuth.middleware.tsToken validation + credit check
src/services/humanCall.service.tsCall lifecycle, transcription, analysis
src/routes/crm.routes.tsExpress routes for /api/crm/*
src/controllers/crm.controller.tsRoute handlers

Modified Files ​

FileChange
src/app.tsAdded crmRoutes at /api/crm with rate limiter
src/controllers/webhook.controller.tsRoute hcall-room-* to humanCallService
src/config/index.tsAdded CRM OAuth config variables
src/middleware/rateLimiter.middleware.tsAdded createCrmOAuthRateLimiter()
env/client-backend.envAdded CRM OAuth variables

Environment Configuration ​

CRM Backend (oktivo_crm/backend/.env) ​

env
# Oktivo App OAuth Configuration
OKTIVO_CLIENT_ID=crm_client_xxx
OKTIVO_CLIENT_SECRET=your_secret_here
OKTIVO_AUTH_URL=https://api.oktivo.ai/oauth/authorize
OKTIVO_TOKEN_URL=https://api.oktivo.ai/api/crm/oauth/token
OKTIVO_API_URL=https://api.oktivo.ai/api/crm
OKTIVO_REDIRECT_URI=https://crm.oktivo.ai/api/oktivo/auth/callback

# Token encryption key (32 bytes hex)
OKTIVO_TOKEN_ENCRYPTION_KEY=your_32_byte_hex_key_here

Oktivo Backend (oktivo_voice/backend/client_backend/.env) ​

env
# CRM OAuth Provider Configuration
CRM_OAUTH_CLIENT_ID=crm_client_xxx
CRM_OAUTH_CLIENT_SECRET=your_client_secret_here
CRM_OAUTH_REDIRECT_URI=https://crm.oktivo.ai/api/oktivo/auth/callback

# NOTE: CRM OAuth tokens use the unified JWT configuration:
# - ACCESS_TOKEN_SECRET / ACCESS_TOKEN_EXPIRY for access tokens
# - REFRESH_TOKEN_SECRET / REFRESH_TOKEN_EXPIRY for refresh tokens

UI Testing Guide ​

Prerequisites ​

  • [ ] CRM Backend running: npm run dev in oktivo_crm/backend
  • [ ] CRM Frontend running: npm run dev in oktivo_crm/app
  • [ ] Oktivo Backend running: npm run dev in oktivo_voice/backend/client_backend
  • [ ] Valid Oktivo App account with credits
  • [ ] Environment variables configured
  • [ ] Logged in as Organization Admin in CRM

Test 1: Connect Integration ​

  1. Navigate to Settings

    • Click Settings in sidebar
    • Click Integrations tab
  2. Find Oktivo Section

    • Look for "Oktivo App" card
    • Should show "Connect" button
  3. Initiate OAuth

    • Click "Connect"
    • Redirected to Oktivo App login
  4. Authorize

    • Login to Oktivo App (if needed)
    • Click "Authorize"
  5. Verify Connection

    • Redirected back to CRM
    • Should see:
      • ✅ "Connected" status
      • ✅ Account name displayed
      • ✅ Credit balance shown
      • ✅ "Disconnect" button visible

Test 2: Make a Call ​

  1. Find a Lead

    • Go to Leads page
    • Select a lead with a phone number
  2. Initiate Call

    • Click "📞 Call Now" button
    • Confirmation dialog appears
  3. Grant Microphone

    • Browser prompts for permission
    • Click "Allow"
  4. Confirm Call

    • Click "Yes, Call Now"
  5. Monitor Status

    • Watch status change:
      • Connecting... → Ringing... → In Progress
    • Timer starts counting
  6. Test Controls

    • Click Mute → verify mic muted
    • Click Unmute → verify restored
    • Click End Call → call terminates

Test 3: View Call History ​

  1. Wait for Processing

    • After call ends, wait 30-60 seconds
  2. View History

    • Stay on lead detail page
    • Scroll to "Oktivo App Calls" section
  3. Verify Record

    • Call appears with timestamp, duration, status
  4. Expand Details

    • Click to expand
    • Verify:
      • 🎵 Recording player
      • 📝 Transcription text
      • 🤖 AI Analysis (sentiment, summary, key points)

Test 4: Disconnect Integration ​

  1. Go to Settings

    • Settings → Integrations
  2. Disconnect

    • Click "Disconnect"
    • Confirm in dialog
  3. Verify

    • Shows "Connect" button again
    • No account info displayed

Test 5: Error Scenarios ​

ScenarioStepsExpected Result
No phoneTry to call lead without phoneButton disabled, tooltip shows "No phone number"
No creditsUse account with 0 creditsError: "Insufficient credits..."
Not connectedDisconnect, try to callError: "Please connect to Oktivo App..."
Mic deniedDeny microphone permissionError about microphone access
Concurrent callStart 2 calls at onceSecond call blocked: "Active call exists"

API Testing Guide ​

Test OAuth Flow ​

bash
# 1. Exchange code for tokens
curl -X POST http://localhost:3000/api/crm/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "authorization_code",
    "code": "auth_code_here",
    "redirect_uri": "https://crm.example.com/callback",
    "client_id": "crm_client_xxx",
    "client_secret": "your_secret"
  }'

# Response: { "access_token": "...", "refresh_token": "...", "expires_in": 3600 }

Test Credit Balance ​

bash
TOKEN="your_access_token"

curl -X GET http://localhost:3000/api/crm/credits \
  -H "Authorization: Bearer $TOKEN"

# Response: { "balance": 100, "currency": "credits" }

Test Call Initiation ​

bash
curl -X POST http://localhost:3000/api/crm/calls \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+919876543210",
    "name": "Test Lead",
    "crmUserId": "user_123",
    "crmOrganizationId": "org_456"
  }'

# Response: { "callId": "hcall_xxx", "roomName": "...", "roomToken": "..." }

Test Call History ​

bash
curl -X GET "http://localhost:3000/api/crm/calls/history?phone=%2B919876543210" \
  -H "Authorization: Bearer $TOKEN"

# Response: { "calls": [...], "total": 5, "page": 1, "pageSize": 20 }

Test Call Details ​

bash
curl -X GET http://localhost:3000/api/crm/calls/hcall_xxx \
  -H "Authorization: Bearer $TOKEN"

# Response: Full call record with transcription and analysis

Troubleshooting ​

Connection Issues ​

ProblemCauseSolution
OAuth redirect failsWrong redirect URICheck OKTIVO_REDIRECT_URI matches exactly
"Invalid client" errorWrong credentialsVerify OKTIVO_CLIENT_ID and OKTIVO_CLIENT_SECRET
Token refresh failsExpired refresh tokenUser must reconnect in Settings
CORS errorBackend misconfiguredCheck CORS origins in both backends

Call Issues ​

ProblemCauseSolution
Call button disabledNo phone / Not connected / Active callCheck lead has phone, verify connection, end other calls
"Insufficient credits"Account has 0 creditsAdd credits in Oktivo App
No audioMic not workingCheck browser permissions, try different browser
Call stuck on "Connecting"LiveKit unreachableCheck network, verify LiveKit server
WebRTC failedNetwork/firewall issueTry different network, check firewall rules

Post-Call Processing ​

ProblemCauseSolution
No transcriptionProcessing delay / API failureWait 1-2 min, check Deepgram API key
No analysisTranscription not readyWait for transcription to complete first
No recordingCall too short (<10s)Make longer test call

Error Codes ​

HTTPErrorMeaning
401invalid_tokenToken expired or invalid
402insufficient_creditsOrganization has 0 credits
403connection_requiredNo active CRM connection
404call_not_foundCall ID doesn't exist
429rate_limit_exceededToo many requests (30/min)

Quick Reference ​

Key Files by Feature ​

FeatureCRM FilesOktivo Files
OAuthOktivoOAuthService.ts, oktivo.routes.tscrm.routes.ts, crm.controller.ts
CallsoktivoApi.ts, CallPanel.tsxhumanCall.service.ts, crm.controller.ts
HistoryCallHistory.tsx, CallHistoryItem.tsxHumanCallRepository.ts
SettingsOktivoIntegration.tsxN/A

LiveKit Integration ​

  • Room prefix: hcall-room-*
  • Data channel: Used for status updates
  • Webhook events: room.started, participant.joined, participant.left, room.ended

Rate Limits ​

  • CRM endpoints: 30 requests per 60-second window
  • Key: Connection ID (authenticated) or IP (OAuth)
  • Rate limit exceeded: Returns 429 with Retry-After header

Last updated: