Install
$ agentstack add skill-voicenterteam-claude-marketplace-call-log ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
> Language. Reply in the user's language: detect what they write — Hebrew→Hebrew, English→English — and mirror it, switching if they switch mid-conversation. This shapes your prose, your questions, and your AskUserQuestion option labels only. It does not change the artifacts you produce — identifiers, JSON keys, BCP-47 language codes, API field names, and other data stay exactly as specified.
> CRM integration context. When the user is building a full CRM integration — not just this API in isolation — always invoke the crm-onboarding skill alongside this one and frame the answer covering all three core services: Click2Call, Screen Pop, and Call History.
Help the developer query call history (CDR records) from the Voicenter Call Log API — filter by date, phone, extension, call type, and choose exactly which fields to return.
When to use this skill
Use this skill when the user wants to:
- Retrieve historical call records for reporting or analytics
- Find all calls to/from a specific phone number or extension
- Get recording URLs for past calls to display in a CRM
- Build missed-call reports (filter by
DialStatus: ABANDONEorNOANSWER) - Correlate a specific call by its ID (
ivruniqueid/CALLID) - Export call data to BI tools or billing systems
- Audit agent activity over a date range
Environment Variables
VOICENTER_API_CODE=your_api_token_here
# The server making requests must also have its IP authorized in Voicenter CPanel
Endpoint
https://api.voicenter.com/hub/cdr/
Accepts: POST-JSON or GET Response: JSON
Authentication
Send your code in the request body. The requesting server's IP must be authorized in the Voicenter CPanel under API Settings.
Request Structure
The request has two parts: search criteria (what to filter) and fields (what to return).
Search Criteria
| Parameter | Type | Required | Description | |---|---|---|---| | code | String | ✅ | API authentication token | | fromdate | ISO 8601 | ✅ | Start date/time in GMT+0 (e.g. 2024-06-01T00:00:00) | | todate | ISO 8601 | ✅ | End date/time in GMT+0 | | phones | String[] | ❌ | Phone numbers to filter (with country code, e.g. "972501234567") | | extensions | String[] | ❌ | SIP extension codes to filter | | IdentityCriteria | String | ❌ | Account, Hierarchical, Department, or User | | callID | String | ❌ | Filter for a specific call by ivruniqueid | | cdrTypes | Integer[] | ❌ | Filter by call type IDs (see table below) | | campaignID | Number[] | ❌ | Filter by dialer campaign IDs | | queueID | Number[] | ❌ | Filter by queue IDs |
CDR Type IDs
| ID | Type Name | |---|---| | 1 | Incoming Call | | 4 | Extension Outgoing | | 8 | Queue | | 9 | Click2Call leg1 | | 10 | Click2Call leg2 | | 11 | VoiceMail | | 13 | XferCDR (transferred) | | 14 | ProductiveCall Leg1 | | 15 | ProductiveCall Leg2 | | 17 | Click 2 IVR | | 18 | Click 2 IVR Incoming | | 19 | Click 2 Queue Incoming | | 21 | Attended CDR leg1 | | 22 | Attended CDR leg2 | | 23 | Auto forward |
Returnable Fields
Choose which CDR fields to receive:
CallerNumber, TargetNumber, Date, DateEpoch, Duration, CallID, Type, CdrType, DialStatus, Targetextension, Callerextension, DID, QueueName, RecordURL, RecordExpect, Price, RingTime, RepresentativeName, RepresentativeCode, UserName, UserId, DTMFData, CustomData, DepartmentName, DepartmentId, TargetPrefixName
Sort
"sort": [
{ "field": "date", "order": "desc" },
{ "field": "Duration", "order": "asc" }
]
Full POST-JSON Request Example
{
"code": "xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"fields": [
"CallerNumber", "TargetNumber", "Date", "Duration", "CallID",
"Type", "CdrType", "DialStatus", "DID", "QueueName",
"RecordURL", "RingTime", "RepresentativeName", "RepresentativeCode",
"DTMFData", "CustomData", "DepartmentName"
],
"search": {
"fromdate": "2024-06-01T00:00:00",
"todate": "2024-06-30T23:59:59",
"cdrTypes": [1, 8, 9, 10],
"phones": ["972501234567"],
"extensions": ["SIPSIP1"],
"IdentityCriteria": "Account"
},
"sort": [{ "field": "date", "order": "desc" }]
}
Response
{
"ERROR_NUMBER": 0,
"ERROR_DESCRIPTION": "OK",
"STATUS_CODE": 200,
"TOTAL_HITS": 2,
"RETURN_HITS": 2,
"CDR_LIST": [
{
"CallerNumber": "0722776772",
"TargetNumber": "972501234567",
"Date": "2024-06-10T09:04:58Z",
"Duration": 2,
"CallID": "202406101204550233243ghff3189e5c",
"CustomData": {},
"Type": "Extension Outgoing",
"CdrType": 4,
"DialStatus": "ANSWER",
"CallerExtension": "SIPSIP1",
"DID": "",
"RecordURL": "https://cpanel.voicenter.co.il/CallsHistory/PlayRecord/2024061043950926.mp3",
"RingTime": 10,
"RepresentativeName": "John Doe",
"RepresentativeCode": "87654321",
"DTMFData": [],
"DepartmentName": "Sales"
}
]
}
Error Codes
| ERRORNUMBER | STATUSCODE | Description | |---|---|---| | 0 | 200 | OK | | 1 | 403 | Rate limit exceeded — wait 5 seconds between requests | | 2 | 403 | Authorization failed — invalid code | | 4 | 403 | IP not authorized — add server IP in CPanel | | 5 | 404 | Date range invalid |
TypeScript Implementation
const CALL_LOG_URL = 'https://api.voicenter.com/hub/cdr/';
const CODE = process.env.VOICENTER_API_CODE!;
interface CdrRecord {
CallerNumber: string;
TargetNumber: string;
Date: string;
Duration: number;
CallID: string;
Type: string;
CdrType: number;
DialStatus: string;
DID: string;
QueueName?: string;
RecordURL: string;
RingTime: number;
RepresentativeName: string;
RepresentativeCode: string;
DTMFData: Array;
CustomData: Record;
}
interface CallLogResponse {
ERROR_NUMBER: number;
ERROR_DESCRIPTION: string;
TOTAL_HITS: number;
RETURN_HITS: number;
CDR_LIST: CdrRecord[];
}
async function getCallLog(
fromdate: string,
todate: string,
options?: {
phones?: string[];
extensions?: string[];
cdrTypes?: number[];
callID?: string;
fields?: string[];
sort?: Array;
}
): Promise {
const body = {
code: CODE,
fields: options?.fields ?? [
'CallerNumber', 'TargetNumber', 'Date', 'Duration', 'CallID',
'Type', 'CdrType', 'DialStatus', 'DID', 'QueueName',
'RecordURL', 'RingTime', 'RepresentativeName', 'CustomData',
],
search: {
fromdate,
todate,
IdentityCriteria: 'Account',
...(options?.phones && { phones: options.phones }),
...(options?.extensions && { extensions: options.extensions }),
...(options?.cdrTypes && { cdrTypes: options.cdrTypes }),
...(options?.callID && { callID: options.callID }),
},
sort: options?.sort ?? [{ field: 'date', order: 'desc' }],
};
const res = await fetch(CALL_LOG_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data: CallLogResponse = await res.json();
if (data.ERROR_NUMBER !== 0) throw new Error(`Call Log error ${data.ERROR_NUMBER}: ${data.ERROR_DESCRIPTION}`);
return data;
}
// Example: get all missed incoming calls today
const { CDR_LIST } = await getCallLog(
'2024-06-01T00:00:00',
'2024-06-01T23:59:59',
{
cdrTypes: [1, 8],
fields: ['CallerNumber', 'Date', 'DialStatus', 'QueueName', 'DID'],
}
);
const missed = CDR_LIST.filter(r => r.DialStatus === 'ABANDONE' || r.DialStatus === 'NOANSWER');
console.log(`Missed calls: ${missed.length}`);
Service Limits
- Maximum 10,000 CDR records per request — break large date ranges into daily chunks
- Maximum 30 requests per minute — add a 2-second delay between sequential requests
- CDRs appear a few minutes after a call ends — not suitable for real-time use
- Only authorized IP addresses can call this API (set in CPanel under API Settings)
Tips
- Use
cdrTypes: [9, 10]to get only Click2Call records and correlate Leg1/Leg2 byCallID. CustomData.OriginalIvrUniqueIDlinks a transferred call back to the original call.RecordURLis a direct MP3 link — store it in your CRM for playback.- All dates in requests must be GMT+0. Israeli time is GMT+2 (or GMT+3 in summer).
DialStatusvalues:ANSWER,NOANSWER,BUSY,CANCEL,ABANDONE,TIMEOUT,VOICEMAIL.
Related Skills
- CDR Notification — Receive CDRs in real time via webhook instead of polling
- Click2Call — The
CALLIDreturned by Click2Call is the same asCallIDin CDR records - Productive Dialer — Filter dialer call records with
cdrTypes: [14, 15] - Active Calls — For live call state; Call Log is for historical records only
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: VoicenterTeam
- Source: VoicenterTeam/claude-marketplace
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.