ManyDial API Documentation
Comprehensive guide to integrating with ManyDial's programmable voice platform. Build automated calls, verify orders, embed cloud call centers, or add headless agent calling to your own browser interface.
Notes:
- If a call is forwarded,
forwardNumberwill include<forwardNumber>. - The
recordAudioURLandrecordTranscribedfields will be populated only if call recording is enabled. - The
smsfield tracks SMS status (Pending, Delivered, Failed).
Call Center CDN SDK
The headless browser SDK adds ManyDial calling to any web application without embedding the Call Center interface. Your application owns every button, incoming-call alert, ringtone and notification; the SDK owns the agent session, SIP/WebRTC connection and call commands.
ready do not request microphone access, connect SIP or realtime services, or enable incoming calls. The agent becomes available only after a user-initiated login() succeeds.Quick start
- Ask a ManyDial administrator to allowlist the exact origin that will host the SDK.
- Create or copy an active key from the existing API Integration page.
- Serve the page over HTTPS. For local development only, ManyDial can allowlist an exact
http://localhost:<port>origin; every other origin must use HTTPS. - Load the SDK with the agent email, Call Center caller ID and API key. The caller ID identifies the tenant, while the email identifies the agent.
- Await
ready, subscribe to events, then calllogin()from a user gesture. Login activates calling; it does not authenticate the user into your application.
Automatic bootstrap request
No customer backend endpoint is required. The SDK sends the existing key directly to ManyDial in the X-API-Key header. ManyDial resolves the tenant from that key and then validates the active agent, approved Call Center, subscription, API Integration permission and exact request origin.
The API key must be active and the subscription's API Integration feature must equal Yes. Deleting or disabling the key blocks both new SDK sessions and every existing API operation that uses the same key. Treat API_KEY_INACTIVE as loss of authorization and return the host UI to a logged-out state.
The mutable /v1/ URL receives the current v1 release automatically; use an exact /vX.Y.Z/ URL when you need a pinned deployment.
The current release is v1.2.1. v1.2.0 remains the first supported immutable release of the direct API-key contract. Earlier SDK versions are retired and must not be used with the production backend.
Optional advanced security: Subresource Integrity (SRI) lets the browser reject a CDN file whose bytes differ from a pinned release. Use it only with an immutable /vX.Y.Z/ script URL. Copy files["manydial-call-center.min.js"].integrity from that release's /vX.Y.Z/manifest.json, then add it as integrity together with crossorigin="anonymous". Never pin SRI to the mutable /v1/ URL.
Microphone permission
In v1.2.1, login() obtains microphone access for outbound, inbound and both permission modes. The browser prompts only when permission has not already been granted. Call it from a clear user action such as an “Enable calls” button, on HTTPS (or localhost during development). A denied request rejects with MEDIA_PERMISSION_DENIED; a missing input device rejects with MICROPHONE_NOT_FOUND, and telephony stays logged out.
It is normally best to load the SDK at page startup and let login() request access. If your product requires “permission denied means the SDK is never loaded,” request access with the browser API first, then inject the script only after success. Render the real values into the authenticated page; the placeholders below are not production credentials. After the SDK is ready, call login() from a separate user click so browser media activation remains reliable.
Internal PBX login and logout confirmation prompts play through SDK-managed audio without appearing as customer calls. If browser autoplay policy blocks a prompt, the SDK emits AUDIO_PLAYBACK_BLOCKED once. This warning does not by itself mean login or logout failed; use the command promise and latest session state to determine the result.
Complete lifecycle and host UI
The SDK intentionally has no visual UI, ringtone or browser notification. Listen for incomingCall, show accessible answer/reject controls for manual-answer agents, and stop host-owned alerts whenever callStateChange leaves incoming. The event's autoAnswer value reflects the agent's ManyDial policy.
This concise example covers validation, telephony activation, incoming and outbound calls, media, breaks, logout and final cleanup. In a real application, enable each control from the latest SDK state.
Methods, events and state
| Method | Parameters | Result | Valid use | Common errors |
|---|---|---|---|---|
| ready | None | Promise<void> | Once after script load; telephony remains inactive | INVALID_CONFIG, API_KEY_REQUIRED, INVALID_API_KEY, ORIGIN_NOT_ALLOWED |
| login(options?) | { takeover?: boolean } | Promise<ManyDialState> | Logged out; call from a user gesture | MEDIA_PERMISSION_DENIED, MICROPHONE_NOT_FOUND, SESSION_ACTIVE, LEGACY_SESSION_ACTIVE, SIP_REGISTRATION_FAILED |
| logout() | None | Promise<void> | Online or on break, with no ringing/active call | ACTIVE_CALL, INVALID_STATE, QUEUE_OPERATION_FAILED |
| destroy() | None | Promise<void> | Permanent integration teardown with no ringing/active call | ACTIVE_CALL; later commands return DESTROYED |
| call(number) | Customer number: string | Promise<CallState> | Online, idle, outbound/both permission | INVALID_NUMBER, PERMISSION_DENIED, ACTIVE_CALL, INSUFFICIENT_BALANCE, CALL_FAILED |
| answer() / reject() | None | Promise<void> | Manual incoming call is ringing | NO_INCOMING_CALL, CALL_FAILED |
| hangup() | None | Promise<void> | Incoming, outgoing, connecting, active or held call | NO_ACTIVE_CALL, CALL_FAILED |
| mute() / unmute() | None | Promise<void> | Active or held call | NO_ACTIVE_CALL, CALL_FAILED |
| hold() / unhold() | None | Promise<void> | Active or held call | NO_ACTIVE_CALL, CALL_FAILED |
| sendDtmf(digits) | 0-9, A-D, *, # or comma | Promise<void> | Active call | NO_ACTIVE_CALL, DTMF_FAILED |
| getTransferTargets() | None | Promise<TransferTarget[]> | Active call; fetch when opening transfer UI | ACTIVE_CALL_REQUIRED, DATA_UNAVAILABLE |
| transfer(agentId) | Opaque target ID: string | Promise<void> | Active call and currently eligible target | ACTIVE_CALL_REQUIRED, TRANSFER_TARGET_UNAVAILABLE, TRANSFER_FAILED |
| getQueueList() | None | Promise<QueueEntry[]> | Logged in | NOT_LOGGED_IN, DATA_UNAVAILABLE |
| getTodayCallLogs() | None | Promise<TodayCallLog[]> | Logged in | NOT_LOGGED_IN, DATA_UNAVAILABLE |
| getBreakTypes() | None | readonly BreakDefinition[] | Any state | None |
| startBreak(type) / endBreak() | BreakType / none | Promise<BreakState> / Promise<void> | Online and idle / currently on break | ACTIVE_CALL, INVALID_BREAK_TYPE, BREAK_ALREADY_ACTIVE, BREAK_NOT_ACTIVE, QUEUE_OPERATION_FAILED |
| getState() | None | ManyDialState | Any state | None |
| on(event, handler) | Event name and callback | Unsubscribe function | Subscribe before login so no event is missed | None |
on(event, handler) returns an unsubscribe function. Keep it and invoke it when the host component is removed. Only one call is supported per SDK instance.
- Await command promises and drive controls from confirmed state rather than optimistic UI changes.
- Hold/unhold preserves the previous mute state. RTP DTMF accepts 0-9, A-D, *, # and comma.
- Call
destroy()only when permanently disposing of the integration; it is terminal and is not a replacement for logout.
A call ending locally, remotely or because of a system/PBX action is reported through callStateChange. When current becomes idle, clear the host's active-call UI. There is no separate callEnded event in v1.
Queue and today's calls
Both read methods require a logged-in session and return data scoped by the authenticated tenant and agent. After login, the SDK fetches the queue immediately and approximately every five seconds while online or on break. It emits queueListChange for the initial list and whenever that list changes.
Today's call logs are fetched after login and whenever a local call returns to idle. Listen for todayCallLogsChange, or call getTodayCallLogs() when the user requests an immediate refresh. Use getQueueList() the same way; do not add a second queue polling loop. Automatic reads stop after logout, session revocation or destroy(). A refresh failure reports an error without replacing the last rendered list with an empty one.
Queue entries contain call time, queue, caller number and call ID. Today's rows contain customer name, phone, duration, status, type, session ID, agent, creation time, hangup party and recording path. Treat those values as sensitive and do not copy complete rows into analytics or logs.
| Event | Payload | Use |
|---|---|---|
| ready | { state } | Bootstrap is complete; the agent is still logged out. |
| sessionStateChange | { previous, current, state } | Agent session status changed. |
| incomingCall | { callId, from, displayName, autoAnswer } | Render the host incoming-call experience. |
| callStateChange | { previous, current, call } | Update call controls from the latest call state. |
| breakStateChange | { previous, current, break } | Update break controls and availability. |
| queueListChange | { entries: QueueEntry[] } | Replace the displayed waiting-caller list. |
| todayCallLogsChange | { logs: TodayCallLog[] } | Replace the displayed list of today's agent calls. |
| error | { error } | Handle a safe ManyDialError and its request ID. |
State values returned by getState()
- Session: bootstrapping, logged_out, logging_in, online, on_break, logging_out, error, destroyed.
- Call: idle, incoming, outgoing, connecting, active, held, ending; it also exposes direction, remote party, muted and held values.
- Break: none, starting, active, ending; it also exposes the type, reporting label and server start time.
- Connection:
sipRegisteredandrealtimeConnected.
Events can arrive close together during reconnection. Render from the latest event payload or getState(); do not assume transport events occur exactly once.
Permissions and session rules
Your application must authenticate and authorize its own user before rendering the SDK credentials. ManyDial login() does not sign that user into the portal: it activates the already validated agent's telephony session. Calling it is valid for every permission mode. Outbound-only agents become ready to place calls but never join the inbound queue and never receive incoming calls.
| Permission | Login | Outbound | Incoming | Logout |
|---|---|---|---|---|
| Outbound | Activate telephony; do not join the inbound queue | Allowed | Rejected | Deactivate telephony |
| Inbound | Activate telephony and automatically join the inbound queue | Rejected | Allowed | Automatically leave the inbound queue and deactivate telephony |
| Both | Activate telephony and automatically join the inbound queue | Allowed | Allowed | Automatically leave the inbound queue and deactivate telephony |
- All calls are blocked while logged out or on break.
- Logout during a ringing or active call returns
ACTIVE_CALLand leaves the session and call unchanged. - When login returns
SESSION_ACTIVE, replace the idle session only after explicit confirmation andlogin({ takeover: true }). - A takeover retry returning
ACTIVE_CALLorAGENT_ON_BREAKis unsafe; finish the call or break first. - After
AGENT_CONFIGURATION_CHANGED, keep the SDK logged out and retry login to fetch the current configuration. - Transfer target IDs are opaque. Fetch targets when opening the control and keep the original call until
transfer(id)succeeds.
Agent breaks
Break APIs are always present, although a host may choose not to show them. Build options from getBreakTypes() so labels remain consistent with Agent Monitoring and Agent Break Reports.
salah → Salah Breaklunch → Lunch Breaktea → Tea Breakpersonal → Personal Breakmeeting → Meetingtraining → Trainingother → Other- A break can start only while logged in, idle and not already on a break; end it before selecting another type.
- Inbound/both agents automatically leave the inbound queue before a break and rejoin it when the break ends successfully. Outbound-only agents have no inbound queue membership to change.
- A failed queue leave does not start the break; a failed queue rejoin leaves the break active so the host can retry.
- ManyDial uses server timestamps. Live monitoring updates on refresh and historical reports update after normal aggregation.
Framework and server-rendered applications
Vanilla JavaScript can use the global directly. React, Vue and Angular should load the script once, subscribe during component setup and invoke every returned unsubscribe function during cleanup. TypeScript consumers should vendor the release's complete declaration tree because index.d.ts references declaration files in subdirectories.
Java, Python and PHP may render these attributes into an authenticated page, but SIP, WebRTC, events and SDK methods always execute in the user's browser. The API key is therefore visible to that browser even when it originated in server-side configuration.
Errors
Failed commands reject with a ManyDialError containing a stable code, safe message and optional requestId. Use the rejection for action-specific UI and the error event for shared logging; avoid showing both as duplicate notifications.
- Configuration: INVALID_CONFIG, INVALID_REQUEST, ORIGIN_REQUIRED, ORIGIN_NOT_ALLOWED, BOOTSTRAP_FAILED, BOOTSTRAP_EXPIRED, AGENT_NOT_AVAILABLE, AGENT_CONFIGURATION_CHANGED, UNSUPPORTED_PHONE_TYPE.
- API-key authorization: API_KEY_REQUIRED, INVALID_API_KEY, API_KEY_INACTIVE.
- Eligibility and billing: API_INTEGRATION_REQUIRED, SUBSCRIPTION_INACTIVE, INSUFFICIENT_BALANCE, CALL_CONFIGURATION_UNAVAILABLE.
- Agent data: DATA_UNAVAILABLE.
- Media: MEDIA_PERMISSION_DENIED, MICROPHONE_NOT_FOUND, AUDIO_PLAYBACK_BLOCKED.
- Sessions/auth: SESSION_ACTIVE, SESSION_CONFLICT, SESSION_RECOVERY_PENDING, SESSION_BUSY, SESSION_LOGGED_OUT, LEGACY_SESSION_ACTIVE, TAKEOVER_NOT_ALLOWED, SESSION_EXPIRED, ACCESS_TOKEN_REQUIRED, INVALID_ACCESS_TOKEN, INVALID_REFRESH_TOKEN, UNAUTHORIZED, SESSION_TAKEN_OVER.
- Actions: AGENT_ON_BREAK, ACTIVE_CALL, ACTIVE_CALL_REQUIRED, PERMISSION_DENIED, ON_BREAK, NO_INCOMING_CALL, NO_ACTIVE_CALL, CALL_FAILED, TRANSFER_FAILED, TRANSFER_TARGET_UNAVAILABLE, DTMF_FAILED.
- Break/queue: BREAK_ALREADY_ACTIVE, BREAK_NOT_ACTIVE, INVALID_BREAK_TYPE, QUEUE_OPERATION_FAILED.
- Connectivity/availability: NETWORK_ERROR, REQUEST_TIMEOUT, RATE_LIMITED, NOT_AVAILABLE, MONITORING_UNAVAILABLE, SIP_CONNECTION_FAILED, SIP_REGISTRATION_FAILED.
- Lifecycle/input: NOT_READY, NOT_LOGGED_IN, ALREADY_LOGGED_IN, INVALID_NUMBER, INVALID_STATE, INVALID_SESSION_STATE, INVALID_CALL_STATE, INVALID_BREAK_STATE, INVALID_MONITORING_STATE, INVALID_COMMAND_ID, COMMAND_ID_REUSED, DESTROYED, INTERNAL_ERROR.
INVALID_API_KEY means the supplied key is malformed, unknown or inactive. API_KEY_INACTIVE means the key that authorized an existing session has since been deleted or disabled; require a new authorized login after the account owner restores a key. SUBSCRIPTION_INACTIVE blocks SDK initialization or session continuation until the account owner restores service. INSUFFICIENT_BALANCE rejects a new charged outbound call before dialing; keep the existing agent state unchanged and direct the account owner to add balance.
Origin, CSP and security
- Allowlist exact origins only: scheme, hostname and non-default port. Exact
http://localhost:<port>origins are supported only for local development; every other origin must use HTTPS. Do not add paths or wildcards. - Public CDN CORS only permits downloading JavaScript; it does not authorize an SDK session.
- Origin is defense-in-depth, not authentication. A non-browser client can forge it.
- The browser-visible API key has the same full authority on existing
/portal/*APIs; it is not scoped only to this SDK. - Render the key only inside the intended authenticated portal. Anyone who can inspect the page, run injected JavaScript or use a privileged extension can copy it.
- Do not put the key in URLs, analytics, error reports or logs. Deleting or disabling it revokes both SDK and existing API access.
- A restrictive CSP and XSS prevention remain essential because injected code on an allowlisted authenticated page can act as that agent.
Add the exact SIP WebSocket origin supplied for your environment to connect-src when it differs from the API origin. Do not add unsafe-inline only for this SDK; use a same-origin host script or the host's existing CSP nonce/hash policy.
call:authorize is a balance/eligibility preflight only; direct SIP call and automatic inbound-queue operations do not carry the ManyDial API key. If compromise is suspected, separately rotate the shared SIP credential and verify queue state; rotation or endpoint restrictions can also affect the existing iframe. API-key/session revocation does not by itself end an active PBX call or guarantee queue removal.Versioning and browser support
- Use
/vX.Y.Z/for deterministic production upgrades and rollback; matching SHA-384 SRI is optional defense-in-depth. - Use
/v1/only when automatic compatible updates are acceptable; never attach a fixed SRI value to this mutable URL. - Test a new exact version on
cdn-staging.manydial.com, then update the production URL and, if used, its SRI value together. - Supported v1 targets are current desktop Chrome/Edge, Firefox and Safari on HTTPS with WebRTC, WebSocket and microphone access.
- Native iOS, Android, React Native and Flutter applications require a separate native SDK; mobile background calls and OS call integration are not supported.