Backend callbacks
All Trackly paths below are relative tohttps://api.tracklysms.com/api/v1/voice. Send the server-held key as
Authorization: Bearer <Trackly API key>. Reads require voice_calls.read;
creation and cleanup require voice_calls.write.
Callbacks resolve the parsed response envelope. On failure, reject an error
carrying the safe Trackly code; retain HTTP status and Retry-After for your
backend’s handling. Honor the supplied AbortSignal where your transport permits,
use bounded request deadlines, and disable automatic mutation retries.
record is a boolean, defaults to false, and requests recording when supported
for the account. customData accepts up to 32 string pairs: keys contain 1–128
characters, cannot start with $ or contain a null character, and values contain
at most 1,024 characters. Its compact UTF-8 JSON must fit within 8,192 bytes.
Pass either option in the input to startCall(); the SDK forwards it unchanged.
GET /browser-sessions/{id} also returns {session} metadata for authorized
recovery. Session metadata includes id, agentId, externalSubject, status,
expiresAt, and backend. The successful issuance transport contains temporary
SIP registration and ICE configuration. Pass that complete envelope to the SDK;
metadata-only recovery cannot substitute for it.
Adapter example
These/integration/voice/* paths are example routes in your existing backend,
not Trackly endpoints. Implement them using the request table above.
authenticatedJson stands for your existing authenticated request helper; it must
apply your CSRF/origin protections, return parsed JSON, reject errors with code,
and pass through the signal without automatically retrying mutations.
Ownership and retry rules
- Derive a stable
externalSubject, up to 200 characters, from authenticated org and user IDs. Scope mappings by client business when serving multiple clients. Check that every requested session/call belongs to that user; account/key authentication alone does not isolate users sharing a key. - Use the same issuing API key for an agent and its sessions. Plan key rotation with Trackly because a new issuer does not inherit existing browser resources.
- Persist session/call IDs, their owner, attempt keys, original inputs, and unresolved outcomes. Serialize session issuance across tabs and backend workers.
- Session and call creation require a nonblank
Idempotency-Keyof at most 128 characters. Changed input with the same key returns409 idempotency_conflict. A lost response retains the original attempt; do not generate a new key to retry. - Authorize caller/contact selection. Verify returned media URLs against Trackly’s approved transport configuration. Preserve approved WSS/ICE settings; do not add browser-selected relays or credentials.
- Keep credentials in memory and return them with
Cache-Control: no-store. Do not log API keys, SIP passwords, TURN credentials, full session envelopes, or SDP. Keep call/session reads uncached because fresh identity checks authorize incoming media and establish cleanup.
Status, expiry, and cleanup
The browser projection useswaiting_agent, dialing_recipient, connected,
ending, ended, failed, and outcome_unknown. It differs from the generic
Voice API’s individual-leg state names. Use call.state: "connected" for the
telephone conversation and busy: false before another attempt.
The earlier session/registration expiry blocks new calls. An accepted call keeps
its own configured duration limit; renewal does not extend it. Use renew() only
while idle. Provide an explicit playback action if audio_playback_blocked occurs.
Mute affects outgoing microphone audio only; DTMF accepts one 0–9, *, #, or
uppercase A–D digit. An uncertain keypad result is not automatically resent.
On a fresh helper, recover() restores metadata and cleanup controls, not live
audio or credentials. A discovered session sets recovery_required. Request
explicit cleanup using disconnect() and wait for resolution before connecting.
An empty metadata result cannot erase an earlier unknown mutation in your backend.
Local hangup, HTTP 202, session revocation, and an ended browser audio stream are
not individually proof that both call legs have stopped. Preserve busy and
unknown states until matching terminal reads and SDK cleanup resolve them.
Revoke sessions server-side on logout; browser unload callbacks may never arrive.
There is no automatic redial or audio reattachment after reload/network failure.
Quotas and support
The SDK reads an active call approximately once per second. Ten active agents need roughly 600 reads/minute before admission and cleanup. The default key quota is 100 requests/minute and 10,000/hour; arrange an appropriate quota with Trackly before a multi-agent test. Do not add another poller. InspectX-RateLimit-Limit,
X-RateLimit-Remaining, X-RateLimit-Reset, and Retry-After on HTTP 429.
For support, retain UTC time, application attempt ID, Trackly session/call IDs,
safe error code, browser version, and network type. Optional
onTiming callbacks
report bounded setup durations without credentials or network addresses.
Salesforce packaging
Use the section matching your existing component. These are supported Salesforce configuration mechanisms; the preview bundle still needs testing inside your actual org’s security settings and browser environment.Existing LWC component
Upload the downloaded JavaScript bundle as a Static Resource, then load it once usingloadScript from lightning/platformResourceLoader. Use your component’s
audio element and existing handlers. Salesforce documents this in
Use Third-Party JavaScript Libraries.
window; load and use
the SDK in the same component namespace. Keep LWS/Locker enabled and validate
WebSocket, microphone, and audio behavior in the org. See
third-party library considerations for LWS.
Existing Visualforce or Open CTI wrapper
Load the bundle through your current approved static-resource/application setup and retain your existing Salesforce screen-pop and activity-logging integration. The SDK supplies calling behavior; it does not register a Salesforce Call Center. Salesforce lists Open CTI as maintenance-only, with retirement scheduled for February 2028 and restrictions on newly created Agentforce Service orgs. Reusing an existing eligible wrapper is a separate decision from creating a new one. See the Open CTI support policy.Media permissions
Approve Trackly’s exactwss:// media origin under the applicable connect-src
policy, and your backend’s HTTPS origin if the browser calls it directly. An HTTPS
entry does not approve a different WSS URL. Microphone permission is separate:
embedded components need permission through the parent/iframe policy as well as
the browser’s user prompt. Test both the selected microphone and output device.
See Salesforce’s CSP guide.