CallRail - Accounts & Companies
๐ Overviewโ
CallRail organizes tracking data in a hierarchical structure: Accounts โ Companies โ Trackers โ Calls. Accounts represent the highest level (e.g., agency), while Companies represent individual clients or business units. This module manages account and company listings, CRUD operations, and webhook configurations for real-time event synchronization.
Source Files:
- Controllers:
external/Integrations/Callrail/Controllers/accounts.js,companies.js - Providers:
external/Integrations/Callrail/Providers/accounts-api.js,companies-api.js - Routes:
external/Integrations/Callrail/Routes/accounts.js,companies.js
External APIs:
- CallRail API v3 -
/accounts,/companies,/webhooks
๐๏ธ Collections Usedโ
integrations.callrail.keyโ
- Operations: Read
- Usage: Retrieve API key for authentication
- See Authentication for full schema
analytics.callrail.userconfigโ
- Operations: Read
- Usage: Get configured account/company IDs
- See Authentication for full schema
๐ Data Flowโ
Account Listing Flowโ
sequenceDiagram
participant Client as DashClicks Frontend
participant Controller as Accounts Controller
participant Provider as Accounts API Provider
participant CallRail as CallRail API v3
participant KeysDB as MongoDB (keys)
Client->>Controller: GET /v1/e/callrail/accounts?page=1&per_page=10
Controller->>KeysDB: Find API key for account
KeysDB-->>Controller: Return api_key
Controller->>Provider: getAccounts(api_key, params)
Provider->>CallRail: GET /v3/a/accounts.json
CallRail-->>Provider: Account list with pagination
Provider-->>Controller: Formatted account data
Controller-->>Client: {accounts: [...], total_pages, total_records}
Company Listing Flowโ
sequenceDiagram
participant Client as DashClicks Frontend
participant Controller as Companies Controller
participant Provider as Companies API Provider
participant CallRail as CallRail API v3
participant KeysDB as MongoDB (keys)
Client->>Controller: GET /v1/e/callrail/companies?account_id=470306151
Controller->>KeysDB: Find API key for account
KeysDB-->>Controller: Return api_key
Controller->>Provider: getCompanies(api_key, accountId, params)
Provider->>CallRail: GET /v3/a/470306151/companies.json
CallRail-->>Provider: Company list with pagination
Provider-->>Controller: Formatted company data
Controller-->>Client: {companies: [...], total_pages, total_records}
Webhook Creation Flowโ
sequenceDiagram
participant Client as DashClicks Frontend
participant Controller as Companies Controller
participant Provider as Companies API Provider
participant CallRail as CallRail API v3
participant KeysDB as MongoDB (keys)
Client->>Controller: POST /v1/e/callrail/companies/webhook
Controller->>KeysDB: Find API key for account
KeysDB-->>Controller: Return api_key
Controller->>Provider: addWebhook(api_key, accountId, companyId, url)
Provider->>CallRail: POST /v3/a/{account}/companies/{company}/webhooks.json
CallRail-->>Provider: Webhook created
Provider-->>Controller: Webhook details
Controller-->>Client: {success: true, data: webhook}
๐ง Business Logic & Functionsโ
Account Functionsโ
getAccounts(req, res, next)โ
Purpose: Retrieve paginated list of CallRail accounts
Source: Controllers/accounts.js
External API: GET https://api.callrail.com/v3/a/accounts.json
Authentication: Bearer token (API key)
Parameters:
req.query.page(Number, optional) - Page number (default: 1)req.query.per_page(Number, optional) - Results per page (default: 10, max: 250)req.query.sort(String, optional) - Sort field (e.g., "name", "-created_at")req.auth.account_id(ObjectId) - DashClicks account ID
Returns: JSON response with accounts array
{
"success": true,
"message": "SUCCESS",
"data": {
"accounts": [
{
"id": "470306151",
"name": "Acme Agency",
"companies_count": 12,
"outbound_recording_enabled": true,
"hipaa_account": false
}
],
"page": 1,
"per_page": 10,
"total_pages": 1,
"total_records": 1
}
}
Business Logic Flow:
-
Validate Account Access
- Call
checkAccountAccess(req)to verify account permissions
- Call
-
Retrieve API Key
- Query
callrail.keycollection for account's API key - Exclude soft-deleted keys
- Return error if no key found
- Query
-
Build Query Parameters
- Extract page, per_page, sort from query string
- Apply defaults (page: 1, per_page: 10)
-
Call CallRail API
- Provider makes GET request to
/v3/a/accounts.json - Pass pagination and sorting parameters
- Provider makes GET request to
-
Format Response
- Extract accounts array and pagination metadata
- Return formatted data
Request Example:
GET /v1/e/callrail/accounts?page=1&per_page=10&sort=name
Authorization: Bearer {jwt_token}
Success Response:
{
"success": true,
"message": "SUCCESS",
"data": {
"accounts": [
{
"id": "470306151",
"name": "Acme Agency",
"companies_count": 12,
"outbound_recording_enabled": true,
"hipaa_account": false
}
],
"page": 1,
"per_page": 10,
"total_pages": 1,
"total_records": 1
}
}
Error Response (No API Key):
{
"success": false,
"errno": 400,
"message": "API key not found. Please add your CallRail API key first."
}
Error Handling:
- Invalid Account: Returns 400 with
INVALID_ACCOUNT_ID - No API Key: Returns 400 with descriptive message
- CallRail API Error: Propagated to error middleware
- 401 Unauthorized: Token invalidation handled by main error handler
Example Usage:
// Fetch first page of accounts
const response = await fetch('/v1/e/callrail/accounts?page=1&per_page=10', {
headers: { Authorization: `Bearer ${token}` },
});
const { accounts, total_records } = await response.json();
Side Effects:
- โน๏ธ Database Read: Queries API key
- โน๏ธ External API Call: CallRail API usage
Company Functionsโ
getCompanies(req, res, next)โ
Purpose: Retrieve paginated list of companies for a CallRail account
Source: Controllers/companies.js
External API: GET https://api.callrail.com/v3/a/{account_id}/companies.json
Authentication: Bearer token (API key)
Parameters:
req.query.account_id(String, required) - CallRail account IDreq.query.page(Number, optional) - Page number (default: 1)req.query.per_page(Number, optional) - Results per page (default: 10, max: 250)req.query.sort(String, optional) - Sort fieldreq.query.disabled(Boolean, optional) - Include disabled companiesreq.query.search(String, optional) - Search by company namereq.auth.account_id(ObjectId) - DashClicks account ID
Returns: JSON response with companies array
{
"success": true,
"message": "SUCCESS",
"data": {
"companies": [
{
"id": "com_abc123",
"name": "Acme Corp",
"status": "active",
"time_zone": "America/New_York",
"created_at": "2023-01-15T10:00:00Z",
"disabled_at": null,
"dni_active": true,
"script_url": "https://cdn.callrail.com/companies/123456/abc123/12/swap.js"
}
],
"page": 1,
"per_page": 10,
"total_pages": 2,
"total_records": 15
}
}
Business Logic Flow:
-
Validate Account Access
- Verify account permissions
-
Retrieve API Key
- Query database for CallRail API key
- Return error if not found
-
Validate Required Fields
- Check that
account_idquery parameter provided - Return 400 if missing
- Check that
-
Build Query Parameters
- Extract page, per_page, sort, disabled, search
- Apply defaults
-
Call CallRail API
- Provider makes GET request to
/v3/a/{account_id}/companies.json - Pass all query parameters
- Provider makes GET request to
-
Format Response
- Extract companies array and pagination metadata
- Return formatted data
Request Example:
GET /v1/e/callrail/companies?account_id=470306151&page=1&per_page=10&search=Acme
Authorization: Bearer {jwt_token}
Success Response:
{
"success": true,
"message": "SUCCESS",
"data": {
"companies": [
{
"id": "com_abc123",
"name": "Acme Corp",
"status": "active",
"time_zone": "America/New_York",
"created_at": "2023-01-15T10:00:00Z",
"disabled_at": null,
"dni_active": true,
"script_url": "https://cdn.callrail.com/companies/123456/abc123/12/swap.js",
"callscore_enabled": false,
"lead_scoring_enabled": true,
"swap_exclude_jquery": false,
"swap_ppc_override": false,
"swap_landing_override": false
}
],
"page": 1,
"per_page": 10,
"total_pages": 1,
"total_records": 1
}
}
Error Response (Missing account_id):
{
"success": false,
"errno": 400,
"message": "Callrail account id is required."
}
Error Handling:
- Invalid Account: Returns 400 with
INVALID_ACCOUNT_ID - No API Key: Returns 400 with descriptive message
- Missing account_id: Returns 400 with specific message
- CallRail API Error: Propagated to error middleware
Example Usage:
// Search for companies by name
const response = await fetch('/v1/e/callrail/companies?account_id=470306151&search=Acme&page=1', {
headers: { Authorization: `Bearer ${token}` },
});
const { companies } = await response.json();
Side Effects:
- โน๏ธ Database Read: Queries API key
- โน๏ธ External API Call: CallRail API usage
addWebhook(req, res, next)โ
Purpose: Create a webhook for real-time call event notifications
Source: Controllers/companies.js
External API: POST https://api.callrail.com/v3/a/{account_id}/companies/{company_id}/webhooks.json
Authentication: Bearer token (API key)
Parameters:
req.body.account_id(String, required) - CallRail account IDreq.body.company_id(String, required) - CallRail company IDreq.body.webhook_url(String, required) - Webhook destination URLreq.auth.account_id(ObjectId) - DashClicks account ID
Returns: JSON response with webhook details
{
"success": true,
"message": "SUCCESS",
"data": {
"id": "web_12345",
"account_id": "470306151",
"company_id": "com_abc123",
"url": "https://dashclicks.com/api/webhooks/callrail",
"status": "enabled",
"events": ["call.completed", "call.received"],
"created_at": "2023-10-01T12:00:00Z"
}
}
Business Logic Flow:
-
Validate Account Access
- Verify account permissions
-
Retrieve API Key
- Query database for CallRail API key
-
Validate Required Fields
- Check account_id, company_id, webhook_url provided
- Return 400 if any missing
-
Call CallRail API
- Provider makes POST request to webhooks endpoint
- Pass webhook_url and event configuration
-
Return Webhook Details
- Include webhook ID, status, events subscribed
Request Example:
POST /v1/e/callrail/companies/webhook
Authorization: Bearer {jwt_token}
Content-Type: application/json
{
"account_id": "470306151",
"company_id": "com_abc123",
"webhook_url": "https://dashclicks.com/api/webhooks/callrail"
}
Success Response:
{
"success": true,
"message": "SUCCESS",
"data": {
"id": "web_12345",
"account_id": "470306151",
"company_id": "com_abc123",
"url": "https://dashclicks.com/api/webhooks/callrail",
"status": "enabled",
"events": ["call.completed", "call.received"],
"created_at": "2023-10-01T12:00:00Z"
}
}
Error Response (Missing Fields):
{
"success": false,
"errno": 400,
"message": "Callrail account id, company id and webhook url are required."
}
Webhook Events:
call.completed- Call has endedcall.received- New call receivedform.submission- Form submitted (if DNI enabled)
Error Handling:
- Invalid Account: Returns 400 with
INVALID_ACCOUNT_ID - No API Key: Returns 400 with descriptive message
- Missing Fields: Returns 400 with specific message
- Duplicate Webhook: CallRail returns error if webhook exists
- Invalid URL: CallRail validates webhook URL format
Example Usage:
// Create webhook for company
await fetch('/v1/e/callrail/companies/webhook', {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
account_id: '470306151',
company_id: 'com_abc123',
webhook_url: 'https://dashclicks.com/api/webhooks/callrail',
}),
});
Side Effects:
- โ ๏ธ Webhook Creation: Creates webhook in CallRail system
- โ ๏ธ External API Call: Modifies CallRail configuration
- โน๏ธ Real-time Events: Enables push notifications for calls
updateWebhook(req, res, next)โ
Purpose: Update webhook configuration (enable/disable, change URL)
Source: Controllers/companies.js
External API: PUT https://api.callrail.com/v3/a/{account_id}/companies/{company_id}/webhooks/{webhook_id}.json
Authentication: Bearer token (API key)
Parameters:
req.body.account_id(String, required) - CallRail account IDreq.body.company_id(String, required) - CallRail company IDreq.body.webhook_id(String, required) - Webhook ID to updatereq.body.webhook_url(String, optional) - New webhook URLreq.body.status(String, optional) - "enabled" or "disabled"req.auth.account_id(ObjectId) - DashClicks account ID
Returns: JSON response with updated webhook
{
"success": true,
"message": "SUCCESS",
"data": {
"id": "web_12345",
"account_id": "470306151",
"company_id": "com_abc123",
"url": "https://dashclicks.com/api/webhooks/callrail-v2",
"status": "enabled",
"events": ["call.completed", "call.received"],
"updated_at": "2023-10-05T14:30:00Z"
}
}
Business Logic Flow:
-
Validate Account Access
- Verify account permissions
-
Retrieve API Key
- Query database for CallRail API key
-
Validate Required Fields
- Check account_id, company_id, webhook_id provided
- At least one of webhook_url or status must be provided
-
Call CallRail API
- Provider makes PUT request to webhook endpoint
- Pass updated fields
-
Return Updated Webhook
Request Example:
PUT /v1/e/callrail/companies/webhook
Authorization: Bearer {jwt_token}
Content-Type: application/json
{
"account_id": "470306151",
"company_id": "com_abc123",
"webhook_id": "web_12345",
"status": "disabled"
}
Success Response:
{
"success": true,
"message": "SUCCESS",
"data": {
"id": "web_12345",
"status": "disabled",
"updated_at": "2023-10-05T14:30:00Z"
}
}
Error Response (Missing Fields):
{
"success": false,
"errno": 400,
"message": "Callrail account id, company id, webhook id and webhook url or status are required."
}
Error Handling:
- Invalid Account: Returns 400 with
INVALID_ACCOUNT_ID - No API Key: Returns 400 with descriptive message
- Missing Fields: Returns 400 with specific message
- Invalid Webhook ID: CallRail returns 404 error
- Invalid Status: CallRail returns validation error
Example Usage:
// Disable webhook
await fetch('/v1/e/callrail/companies/webhook', {
method: 'PUT',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
account_id: '470306151',
company_id: 'com_abc123',
webhook_id: 'web_12345',
status: 'disabled',
}),
});
Side Effects:
- โ ๏ธ Webhook Update: Modifies webhook configuration
- โ ๏ธ Event Flow: Disabling stops real-time notifications
- โน๏ธ External API Call: Updates CallRail configuration
Provider Functionsโ
getAccounts(apiKey, params)โ
Purpose: Call CallRail API to retrieve accounts
Source: Providers/accounts-api.js
External API: GET https://api.callrail.com/v3/a/accounts.json
Parameters:
apiKey(String) - CallRail API keyparams(Object) - Query parameters (page, per_page, sort)
Returns: Promise<Object> - API response data
HTTP Request:
GET /v3/a/accounts.json?page=1&per_page=10
Host: api.callrail.com
Authorization: Bearer {api_key}
Example Usage:
const accounts = await accountsApi.getAccounts(apiKey, {
page: 1,
per_page: 10,
sort: 'name',
});
Side Effects:
- โน๏ธ External API Call: CallRail API request
getCompanies(apiKey, accountId, params)โ
Purpose: Call CallRail API to retrieve companies
Source: Providers/companies-api.js
External API: GET https://api.callrail.com/v3/a/{account_id}/companies.json
Parameters:
apiKey(String) - CallRail API keyaccountId(String) - CallRail account IDparams(Object) - Query parameters
Returns: Promise<Object> - API response data
HTTP Request:
GET /v3/a/470306151/companies.json?page=1&per_page=10&search=Acme
Host: api.callrail.com
Authorization: Bearer {api_key}
Example Usage:
const companies = await companiesApi.getCompanies(apiKey, '470306151', {
page: 1,
per_page: 10,
search: 'Acme',
});
Side Effects:
- โน๏ธ External API Call: CallRail API request
addWebhook(apiKey, accountId, companyId, webhookUrl)โ
Purpose: Call CallRail API to create webhook
Source: Providers/companies-api.js
External API: POST https://api.callrail.com/v3/a/{account_id}/companies/{company_id}/webhooks.json
Parameters:
apiKey(String) - CallRail API keyaccountId(String) - CallRail account IDcompanyId(String) - CallRail company IDwebhookUrl(String) - Webhook destination URL
Returns: Promise<Object> - Webhook details
HTTP Request:
POST /v3/a/470306151/companies/com_abc123/webhooks.json
Host: api.callrail.com
Authorization: Bearer {api_key}
Content-Type: application/json
{
"url": "https://dashclicks.com/api/webhooks/callrail"
}
Example Usage:
const webhook = await companiesApi.addWebhook(
apiKey,
'470306151',
'com_abc123',
'https://dashclicks.com/api/webhooks/callrail',
);
Side Effects:
- โ ๏ธ Webhook Creation: Creates webhook in CallRail
- โน๏ธ External API Call: Modifies CallRail configuration
updateWebhook(apiKey, accountId, companyId, webhookId, data)โ
Purpose: Call CallRail API to update webhook
Source: Providers/companies-api.js
External API: PUT https://api.callrail.com/v3/a/{account_id}/companies/{company_id}/webhooks/{webhook_id}.json
Parameters:
apiKey(String) - CallRail API keyaccountId(String) - CallRail account IDcompanyId(String) - CallRail company IDwebhookId(String) - Webhook IDdata(Object) - Update data (url, status)
Returns: Promise<Object> - Updated webhook details
HTTP Request:
PUT /v3/a/470306151/companies/com_abc123/webhooks/web_12345.json
Host: api.callrail.com
Authorization: Bearer {api_key}
Content-Type: application/json
{
"status": "disabled"
}
Example Usage:
const webhook = await companiesApi.updateWebhook(apiKey, '470306151', 'com_abc123', 'web_12345', {
status: 'disabled',
});
Side Effects:
- โ ๏ธ Webhook Update: Modifies webhook configuration
- โน๏ธ External API Call: Updates CallRail configuration
๐ Integration Pointsโ
CallRail Hierarchyโ
Account โ Company Relationship:
- One Account can have multiple Companies
- Companies represent individual clients or business units
- Each Company has its own trackers and calls
Usage Pattern:
- List accounts to get account IDs
- Select account and list companies
- Select company and create trackers
- Trackers generate calls
Webhook Integrationโ
Real-time Event Processing:
- Webhooks send POST requests to specified URL
- Events include call data (caller, duration, recording, etc.)
- Used for immediate campaign attribution and notifications
Webhook Payload Example:
{
"event": "call.completed",
"data": {
"id": "call_12345",
"company_id": "com_abc123",
"customer_phone_number": "+15551234567",
"duration": 180,
"recording": "https://api.callrail.com/recordings/rec_12345.mp3",
"start_time": "2023-10-01T14:30:00Z"
}
}
๐งช Edge Cases & Special Handlingโ
Paginationโ
Issue: Large accounts may have hundreds of companies
Handling:
- Use
per_pageparameter (max 250) - Iterate through pages using
pageparameter - Response includes
total_pagesfor UI implementation
Disabled Companiesโ
Issue: Need to show/hide disabled companies
Handling:
- Use
disabled=truequery parameter to include disabled companies - Default excludes disabled companies
disabled_atfield shows when company was disabled
Search Functionalityโ
Issue: Need to filter companies by name
Handling:
- Use
searchquery parameter for partial name match - CallRail API performs case-insensitive search
- Combine with pagination for efficient browsing
Webhook Duplicationโ
Issue: Creating duplicate webhooks causes errors
Handling:
- CallRail returns error if webhook with same URL exists
- Frontend should check existing webhooks before creation
- Use update endpoint to modify existing webhooks
โ ๏ธ Important Notesโ
- ๐ Hierarchy: Accounts โ Companies โ Trackers โ Calls
- ๐ Filtering: Support for search, pagination, sorting, disabled filter
- ๐ Webhooks: Real-time event notifications for call tracking
- ๐ API Key: Required for all operations (Bearer token)
- ๐ Rate Limits: CallRail API has rate limits (check API docs)
- ๐๏ธ Soft Delete: Companies marked as disabled, not deleted
- ๐ Company Fields: Includes DNI script URL, timezone, lead scoring settings
- โ ๏ธ Webhook Events: Subscribe to specific events (call.completed, call.received)
๐ Related Documentationโ
- Integration Overview: CallRail Integration
- Authentication: API Key Management
- Calls: Call Tracking & Analytics
- Trackers: Phone Number Tracking
- CallRail API: CallRail API Documentation