npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ahs-cti

v0.0.1

Published

Call Control SDK for Web RTC

Downloads

8,254

Readme

AHS CTI SDK

npm version npm downloads bundle size

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

🎯 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 priority

This means:

  • Backend defaults set the baseline configuration
  • Entitlements override backend defaults based on the agent's permissions
  • Explicit sdkConfig overrides 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 | | ----------------------------------------------------------------------------- | ------- | ---------- | | Chrome | 60+ | ✅ Supported | | Firefox | 60+ | ✅ Supported | | Safari | 12+ | ✅ Supported | | Edge | 79+ | ✅ Supported |


📄 License

license license