ahs-cti
v0.0.1
Published
Call Control SDK for Web RTC
Downloads
8,254
Maintainers
Readme
AHS CTI SDK
A powerful, lightweight SDK for real-time call management with dynamic configuration and permission-based access control
🔑AUTHORIZED ACCESS REQUIRED - API Key & Tenant ID🔑
⭐ License Features
- API Key Authentication - Secure access through authorized API keys
- Tenant ID Management - Multi-tenant support with isolated access
- Permission-Based Access Control - Entitlement-driven feature enablement
- Cross-Platform Support - Use across web, mobile, desktop, and server platforms
- Usage Monitoring - Real-time tracking and compliance monitoring
- Flexible Deployment - Deploy on authorized platforms with proper credentials
🚫 Prohibited Activities
- No Unauthorized Access - Cannot use without valid credentials
- No Credential Sharing - API keys and tenant IDs are confidential
- No Reverse Engineering - Cannot decompile or reverse engineer
- No Platform Violations - Must use only on authorized platforms
- No Usage Abuse - Cannot exceed subscription limits
📑 Table of Contents
- ✨ Key Features
- 📦 Installation
- 🚀 Quick Start
- ⚙️ Dynamic Configuration
- 📚 API Reference
- 🔒 Permissions System
- 🔌 WebSocket Events
- 📦 Data Types
- 🌍 Browser Support
- 📄 License
✨ Key Features
🎯 Complete Call Control
- Inbound and outbound call management
- Hold/Resume calls
- Mute/Unmute functionality
- Blind, Attended, and Warm call transfers
- Multi-line conference calling (up to 5 lines)
- Agent status management (Ready, Break, Wrapup)
- End call with disposition tracking
- Ringtone support for incoming calls
⚙️ Dynamic Configuration
- Three-layer config merging - Backend defaults, permission-based controls, and explicit SDK config
- Permission-based feature toggling - Controls auto-disabled based on entitlements
- Runtime URL configuration - All endpoints dynamically resolved from config
- Customizable UI - Material-UI SxProps for button styling
💾 Smart State Management
- Real-time call timer
- Persistent state storage via
@react-solutions/vault - Singleton state pattern
- Cross-component sync via observer pattern
- Full TypeScript support
📦 Installation
npm install ahs-cti🔑 Required Peer Dependencies
npm install react react-dom axios @mui/material @mui/icons-material @emotion/react @emotion/styled @react-solutions/vault🚀 Quick Start
1️⃣ Initialize the SDK
Initialize the SDK at the root of your application with the required credentials and optional dynamic configuration:
import { useEffect } from "react";
import { initSDK } from "ahs-cti";
function App() {
useEffect(() => {
const initialize = async () => {
try {
await initSDK({
// Required credentials
apiKey: "your-api-key",
tenantId: "your-tenant-id",
agentId: "your-agent-id",
// Optional: URL configuration for API endpoints
urlConfig: {
},
// Optional: Feature configuration overrides
sdkConfig: {
},
});
console.log("✅ SDK initialized successfully");
} catch (error) {
console.error("❌ SDK initialization failed:", error);
}
};
initialize();
}, []);
return <YourAppContent />;
}2️⃣ Add Call Control Panel
Drop in the draggable call control panel anywhere in your app:
import { CallControlPanel } from "ahs-cti";
export default function AgentDashboard() {
const handleCallDataChange = (data) => {
console.log("📞 Call data updated:", data);
};
return (
<div>
<h1>Agent Dashboard</h1>
<CallControlPanel onDataChange={handleCallDataChange} />
</div>
);
}3️⃣ Use Call Management Hooks
🔴 Start a Call
import { useClickToCall } from "ahs-cti";
export default function CallButton() {
const { handleStartCall, isLoading, isSuccess, isError, error } =
useClickToCall();
const startCall = () => {
handleStartCall({ mobileNumber: "1234567890" });
};
return (
<button onClick={startCall} disabled={isLoading}>
{isLoading ? "🔄 Calling..." : "📞 Start Call"}
</button>
);
}🔚 End a Call
import { useEndCall } from "ahs-cti";
export default function EndCallButton() {
const { handleEndCall, isLoading } = useEndCall();
const endCall = () => {
handleEndCall({ disposition: "RES" });
};
return (
<button onClick={endCall} disabled={isLoading}>
{isLoading ? "🔄 Ending..." : "🔚 End Call"}
</button>
);
}🚪 Agent Logout
import { useLogout } from "ahs-cti";
export default function LogoutButton() {
const { logout, isLoading } = useLogout();
return (
<button onClick={logout} disabled={isLoading}>
{isLoading ? "🔄 Logging out..." : "🚪 Logout"}
</button>
);
}📞 Get Caller Data
The useGetCallerData hook provides reactive access to current call data independently of CallControlPanel:
import { useGetCallerData } from "ahs-cti";
export default function CallStatusWidget() {
const callerData = useGetCallerData();
return (
<div>
<h3>Current Call Status</h3>
{callerData.status === "ONCALL" ? (
<div>
<p>Active Call: {callerData.phone_number}</p>
<p>Agent: {callerData.agent_id}</p>
<p>Process: {callerData.process_name}</p>
<p>Queue: {callerData.queue_name}</p>
</div>
) : (
<p>No active call</p>
)}
</div>
);
}🔄 Subscribe to SDK State
import { useSDKState } from "ahs-cti";
export default function AgentStatusDisplay() {
const state = useSDKState();
return (
<div>
<p>Agent: {state.agentId}</p>
<p>Status: {state.agentStatus}</p>
<p>Initialized: {state.isInitialized ? "Yes" : "No"}</p>
<p>Hold: {state.hold ? "On Hold" : "Active"}</p>
<p>Mute: {state.mute ? "Muted" : "Unmuted"}</p>
</div>
);
}🔐 Get Authorization Token
Retrieve the access token for external API calls:
import { useGetAuthorizationToken } from "ahs-cti";
export default function ExternalAPICall() {
const token = useGetAuthorizationToken();
const fetchData = async () => {
const response = await fetch("https://api.example.com/data", {
headers: { Authorization: `Bearer ${token}` },
});
// handle response
};
return <button onClick={fetchData}>Fetch External Data</button>;
}⚙️ Dynamic Configuration
The SDK supports a three-layer dynamic configuration system that determines which call control features are enabled.
🔧 SDK Config
Feature toggle options passed via sdkConfig in initSDK():
🎨 Configuration Options
| Option | Type | Default | Description |
| --------------------------- | --------- | ------- | --------------------------------------- |
| disableEndCallButton | boolean | false | Disable the end call button |
| disabledDialButton | boolean | false | Disable the dial/outbound call button |
| disableCallTransferButton | boolean | false | Disable the call transfer button |
| disableBlindTransfer | boolean | false | Disable blind transfer option |
| disableAttendedTransfer | boolean | false | Disable attended transfer option |
| disableWarmTransfer | boolean | false | Disable warm transfer option |
| disableConferenceButton | boolean | false | Disable the conference call button |
| disableHoldButton | boolean | false | Disable the hold functionality |
| disableMuteButton | boolean | false | Disable the mute functionality |
| disabledMoreOptionsButton | boolean | false | Disable the more options menu |
| disableSoftPhone | boolean | false | Disable the embedded soft phone iframe |
| isDraggable | boolean | true | Enable/disable panel dragging |
| enableSmsServices | boolean | false | Enable SMS services |
| enableQueueName | boolean | false | Show queue name in call data |
| enableRingtone | boolean | false | Enable ringtone for incoming calls |
| auto_wrapup_time | number | - | Auto wrapup time in seconds |
| break_time | number | - | Break duration in seconds |
| disabled | SxProps | - | Custom MUI styles for disabled states |
| enabled | SxProps | - | Custom MUI styles for enabled states |
| outlined | SxProps | - | Custom MUI styles for outlined states |
🌐 URL Config
All API endpoints are dynamically resolved from the URL configuration:
interface URLConfig {
id: string; // Configuration identifier
baseURL: string; // Main API base URL
coreBaseURL: string; // Core API URL for call control actions
webSocketURL: string; // WebSocket URL for real-time events
iframeURL: string; // Soft phone iframe URL
iframeAPIURL: string; // Iframe API endpoint
password: string; // Agent password for authentication
accessToken?: string; // Pre-provided access token (optional)
}If baseURL is not provided, the SDK falls back to window.location.origin.
🔐 Permission-Based Controls
The SDK implements a fail-closed permission model. After authentication, the backend returns entitlements that automatically determine which controls are enabled:
// Entitlements structure from login response
{
calls: {
enabled: boolean,
items: [
{ code: "call_inbound", enabled: boolean },
{ code: "call_outbound", enabled: boolean }
]
},
call_transfer: {
enabled: boolean,
items: [
{ code: "call_transfer_blind", enabled: boolean },
{ code: "call_transfer_attended", enabled: boolean },
{ code: "call_transfer_warm", enabled: boolean }
]
},
call_conference: {
enabled: boolean,
items: [
{ code: "call_conference", enabled: boolean }
]
}
}If permissions have not been loaded, all controls are disabled by default.
You can use the exported SDK_PERMISSIONS constants to reference permission codes:
import { SDK_PERMISSIONS } from "ahs-cti";
// Permission categories
SDK_PERMISSIONS.CALLS; // "calls"
SDK_PERMISSIONS.CALL_TRANSFER; // "call_transfer"
SDK_PERMISSIONS.CALL_CONFERENCE; // "call_conference"
// Permission codes
SDK_PERMISSIONS.CALL_INBOUND; // "call_inbound"
SDK_PERMISSIONS.CALL_OUTBOUND; // "call_outbound"
SDK_PERMISSIONS.TRANSFER_BLIND; // "call_transfer_blind"
SDK_PERMISSIONS.TRANSFER_ATTENDED; // "call_transfer_attended"
SDK_PERMISSIONS.TRANSFER_WARM; // "call_transfer_warm"
SDK_PERMISSIONS.CONFERENCE; // "call_conference"📊 Configuration Merge Priority
The SDK merges configuration from three sources (highest priority wins):
1. Explicit sdkConfig (passed to initSDK) <- Highest priority
2. Permission-based controls (from entitlements) <- Medium priority
3. Backend callControls (from login response) <- Lowest priorityThis means:
- Backend defaults set the baseline configuration
- Entitlements override backend defaults based on the agent's permissions
- Explicit
sdkConfigoverrides everything, allowing host applications to force-enable or force-disable features
📚 API Reference
🔧 Core Functions
initSDK(params)
Initialize the SDK with credentials and configuration. Must be called before using any components or hooks. Returns a Promise<void>.
await initSDK({
apiKey: string, // ✅ Required - API key for authentication
tenantId: string, // ✅ Required - Tenant identifier
agentId: string, // ✅ Required - Agent identifier
sessionId?: string, // 📎 Optional - Session identifier
urlConfig?: URLConfig, // 📎 Optional - URL configuration for endpoints
sdkConfig?: SDKConfig, // 📎 Optional - Feature configuration overrides
});isSDKInitialized()
Check if the SDK has been successfully initialized.
const initialized: boolean = isSDKInitialized();getSDKVersion()
Get the current SDK version.
const version: string = getSDKVersion();CallControlPanel
Draggable control panel component for call management.
<CallControlPanel
onDataChange={(data: CallData) => {
// Called when call status, phone number, or any call data changes
}}
/>🪝 React Hooks
| Hook | Description | Returns |
| --------------------------- | -------------------------------------------- | ----------------------------------------------------------- |
| useClickToCall() | Initiate outbound calls | { handleStartCall, isLoading, isSuccess, isError, error } |
| useEndCall() | End active calls with disposition | { handleEndCall, isLoading, isSuccess, isError, error } |
| useLogout() | Agent logout | { logout, isLoading, isSuccess, isError, error } |
| useGetCallerData() | Reactive access to current call data | CallData |
| useSDKState() | Subscribe to full SDK state changes | SDKState |
| useGetAuthorizationToken()| Get the current access token | string \| undefined |
🔌 WebSocket Events
The SDK connects to a WebSocket for real-time call events:
WebSocket URL: {urlConfig.webSocketURL}/api/v1/ws/agent/events?token={accessToken}Connection behavior:
- Auto-reconnects with exponential backoff (base: 2s, max: 30s, up to 60 attempts)
- Sends ping every 30 seconds to keep the connection alive
Event data structure:
{
agent_id: number;
status: CallStatus; // IDLE, READY, ONCALL, RINGING, DIALING, WRAPUP, etc.
type: string; // Call type
event_time: string;
phone_number: string;
convox_id: string;
process_id: number;
process_name: string;
hold: number; // 0 = not held, 1 = held
mute: number; // 0 = not muted, 1 = muted
mode: string; // 'manual' or automated
queue_name: string;
conferencestatus?: { // Present during conference calls
line_1_status: string;
line_1_phonenumber: string;
line_2_status: string;
line_2_phonenumber: string;
// ... up to line 5
}
}📦 Data Types
CallStatus Enum
enum CallStatus {
IDLE = "IDLE",
READY = "READY",
BREAK = "BREAK",
ONCALL = "ONCALL",
WRAPUP = "WRAPUP",
RINGING = "RINGING",
DIALING = "DIALING",
MISSED = "MISSED",
HOLD = "HOLD",
UNHOLD = "UNHOLD",
MUTE = "MUTE",
UNMUTE = "UNMUTE",
DISCONNECTED = "DISCONNECTED",
CONFERENCE = "CONFERENCE",
}CallData
interface CallData {
mobileNumber?: string;
callReferenceId?: string;
convoxId?: string;
type?: string;
status: string;
agent_id: number;
phone_number?: string;
event_time?: string;
convox_id?: string;
process_id?: string;
process_name?: string;
mode?: string;
queue_name?: string;
mute?: number; // 1 = muted, 0 = unmuted
hold?: number; // 1 = on hold, 0 = not on hold
}ConferenceLineTypes
type ConferenceLineTypes = {
line: number; // Line number (1-5)
status: string; // ONCALL, IDLE, LINE USED, etc.
type: "external" | "internal" | "";
phone: string;
isMute: boolean;
isHold: boolean;
isCallStart: boolean;
isMergeCall: boolean;
};StartCallPayload
interface StartCallPayload {
mobileNumber?: string;
}EndCallPayload
interface EndCallPayload {
disposition?: string; // Default: "RES"
}📤 Exported Types
// Types
export type { CallData, CallControlPanelProps, SDKConfig, URLConfig };
export type { SDKPermissionState, ControlsFromPermissions, SDKPermissionContextValue };
export type { RequestResult, RequestOptions };
export type { UseGetRequest, UsePostRequest, UsePutRequest, UseDeleteRequest, UsePatchRequest };
// Enum
export { CallStatus };
// Constants
export { SDK_PERMISSIONS };
// Functions
export { initSDK, getSDKVersion, isSDKInitialized };
// Hooks
export { useLogout, useEndCall, useClickToCall, useGetCallerData, useGetAuthorizationToken, useSDKState };
// Components
export { CallControlPanel };🌍 Browser Support
| Browser | Version | Status |
| ----------------------------------------------------------------------------- | ------- | ---------- |
| | 60+ | ✅ Supported |
|
| 60+ | ✅ Supported |
|
| 12+ | ✅ Supported |
|
| 79+ | ✅ Supported |
📄 License
