
Scope: inbound and outbound, with browser audio over WebRTC. This installs as a custom app on your own account — there is no Marketplace review to wait for, and it is usually live within about thirty minutes of upload.
What you get
How it works
client.interface.trigger and the Freshdesk REST API. The depth of any Freshdesk CTI integration is therefore a function of how much the app chooses to write back.
The whole Freshworks surface this app uses today:
The outbound call flow
Inbound calls
The agent clicks Enable inbound calls to this panel once. The backend creates (or reuses) a Vobiz application pointing at its own/inbound-answer webhook and attaches the agent’s selected number to it. Real calls to that number then hit /inbound-answer, which dials sip:… — landing on the same auto-answer path as the outbound bridge leg.
Keep the Freshdesk tab open; the panel has to stay registered to receive the call.
Requirements
The calling backend
The app is a client. It holds no Vobiz credentials and cannot place a call on its own — it talks to a calling backend that you run, which holds the account credentials and drives the Vobiz REST API.The backend is not in the repository. Its complete contract is in
docs/backend-contract.md. Read it before you start — the obvious implementation of the recording endpoint is unsafe, and the document explains why.- Vobiz Auth Tokens are account-level API credentials. Never expose
X-Auth-Tokenin client-side code — see authentication. The backend holds the token and the browser never sees it. - An
<audio>element cannot send authentication headers. Recordings are protected, so playback needs a server-side step.
backend_url installation parameter. The app requires HTTPS and strips trailing slashes.
Security requirements
The app sendsagentId as a plain string in the path, body or query. If your backend trusts that string, every browser route above is unauthenticated and the agentId is guessable. Somebody who learned your backend URL could then read SIP passwords, place calls billed to your account, rewrite your inbound number routing, and download every recording.
Step 1: Pack the app
The Freshworks CLI is pinned to a Node version, with a separate CLI build per Node major. Install the pair the app declares inmanifest.json:
dist/.
fdk pack enforces Freshworks’ 80% coverage floor on every metric, and additionally wants local simulation coverage, which is only produced by running the app inside a real Freshdesk account via ?dev=true. For local builds use fdk pack --skip-coverage; do not use that flag for a Marketplace submission.Step 2: Create the custom app
- In Freshdesk, go to Admin → Apps.
- Click Go to Developer Portal.
- Click Create New App and choose Custom App.
- Select your Freshdesk account.
- Upload the zip from
dist/. - Fill in the app details — name, description, and your team’s support email.
- Save and Publish, then Promote to Live.
Step 3: Install and configure
- Back in Freshdesk, go to Admin → Apps → Manage Apps.
- Filter to Custom.
- Find the app and click Install.
- Fill in the settings:
All three can be changed later without reinstalling, under Admin → Apps → Manage Apps → Custom → Settings → Configure.
Step 4: Open the panel
Open any agent page and look for the Vobiz icon at the bottom left. The panel loads on all agent pages, not only tickets — if the icon does not appear, hard refresh. Then:- Log in with your Vobiz Auth ID and Auth Token, and pick the number to call from. These are entered by the agent at runtime and are not stored by the app.
- Make a call by typing a number and clicking Call, or by clicking any phone number in Freshdesk.
- The first call prompts for microphone permission, since audio runs through the browser.
- Receive calls by clicking Enable inbound calls to this panel once.
Develop without a Vobiz account
The repository ships a mock backend that implements the whole contract with fake data, so the panel can be developed without placing a real call.?dev=true appended, then set the app’s settings at http://localhost:10001/custom_configs:
Any Auth ID and Auth Token are accepted. Use
fail as the Auth ID to exercise the error path. The mock backend’s README covers pointing it at a real Vobiz SIP endpoint to test actual audio.
Tests
app/scripts/app.js and the real markup from app/index.html into jsdom with the Freshworks SDK, JsSIP and fetch faked, so they exercise the code that ships rather than a copy of it. The whole app is three files — app/index.html, app/scripts/app.js and app/styles/style.css. No build step, no framework.
Binding inbound audio
Worth knowing before you touch the SIP code. For an incoming session, JsSIP has not built theRTCPeerConnection yet — session.connection is null until the call is answered. Dereferencing it inside the newRTCSession handler throws, and because the throw happens inside that handler it aborts before .answer() runs.
The symptom is misleading: the browser silently never picks up, Vobiz rings the endpoint until it times out, and the far end is never connected. Bind through the peerconnection event instead:
Troubleshooting
WebRTC inside a Freshdesk iframe. The app registers over SIP-over-WebSocket from inside a Freshworks-hosted iframe, and Freshworks does not publish the Content-Security-Policy applied to app iframes. If your network or the platform blocks the WebSocket, registration fails and the panel reports it. Test on one account before rolling out widely.
Scope today
The panel is a softphone that lives inside Freshdesk. Click-to-call, outbound, inbound and recording playback all work today. Writing back into Freshdesk’s data — creating tickets from calls, logging calls as ticket notes, popping the contact record on an inbound call, attaching recordings — is on the roadmap in the repository’s CHANGELOG. Hold, mute, transfer and conference are not built, and one agent identity is set per installation by an admin. Two constraints to plan around if you extend it:- The CTI sidebar has no page context.
client.data.get("ticket")is not available incti_global_sidebar. Knowing which ticket the agent is viewing needs a separateticket_backgroundinstance, which shares no JavaScript state — so coordination goes through$dbor the backend. - The Freshdesk API key should be a secure iparam, which means calls using it must go through
client.request.invokeTemplaterather thanfetch. Secure iparams are only substituted into request-template headers and are never readable from front-end JavaScript.
Next steps
- Clone the app and mock backend: vobiz-ai/Vobiz-Freshdesk-Calling
- Read the backend contract before implementing your own
- Create the agents’ SIP endpoints: Endpoints API or the console guide
- Read the
<Dial>reference and<User> - Want ticket logging out of the box? See Zendesk, where it ships with the backend