Skip to main content
The Phonely Web SDK lets you add browser-based voice calls to your app without exposing your Phonely API key to the browser. Your server creates a short-lived web call session with Phonely, then your browser passes that session bundle to the SDK.

Install

npm install @phonely-ai/web
Use @phonely-ai/web v0.0.8 or newer.

How It Works

  1. Your browser asks your backend to start a web call for an agent.
  2. Your backend calls Phonely with your API key.
  3. Phonely returns a short-lived session bundle.
  4. Your backend returns that bundle to your browser.
  5. The Web SDK uses the bundle to join the call and read the live transcript.
Never send your Phonely API key to the browser. Keep it in your backend only.

Create A Web Call Session

Call this endpoint from your backend.
POST https://db.phonely.ai/api/agents/{agent_id}/web-call-session
X-Authorization: YOUR_API_KEY
Content-Type: application/json

Request Body

The body is optional. Send {} if you do not need metadata.
{
  "metadata": {
    "callOverrides": {}
  }
}

Response

Return this object from your backend to your browser.
{
  "callId": "abc123",
  "webCallUrl": "https://...",
  "meetingToken": "short-lived-meeting-token",
  "phonelyToken": "short-lived-transcript-token",
  "expiresAt": "2026-06-12T03:00:00+00:00",
  "transcriptUrl": "https://db.phonely.ai/api/calls/abc123/transcript"
}
FieldDescription
callIdThe Phonely call ID for this session.
webCallUrlThe URL the SDK uses to join the web call.
meetingTokenA short-lived token for this web call session.
phonelyTokenA short-lived token the SDK uses for this call’s transcript.
expiresAtWhen the short-lived tokens expire.
transcriptUrlThe transcript endpoint for this call. Return this value to the SDK as received.

Backend Example

export async function POST(request: Request) {
  const { agentId, metadata } = await request.json();

  const response = await fetch(
    `https://db.phonely.ai/api/agents/${encodeURIComponent(agentId)}/web-call-session`,
    {
      method: "POST",
      headers: {
        "X-Authorization": process.env.PHONELY_API_KEY!,
        "Content-Type": "application/json",
      },
      body: JSON.stringify(metadata ? { metadata } : {}),
    }
  );

  if (!response.ok) {
    return Response.json(await response.json(), { status: response.status });
  }

  return Response.json(await response.json());
}

Browser Example

import Phonely from "@phonely-ai/web";

const phonely = new Phonely({
  createWebCallStart: async (options) => {
    const response = await fetch("/api/web-call/start", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(options),
    });

    if (!response.ok) {
      throw new Error("Failed to start web call");
    }

    return response.json();
  },
  transcript: {
    enabled: true,
    autoStart: true,
  },
});

const callId = await phonely.call({ agentId: "agent_123" });

Live Transcript

When transcript.autoStart is enabled, the SDK reads the transcript using the transcriptUrl and phonelyToken from the session response. Return the session response from your backend unchanged so the SDK can use those fields. Listen for transcript updates:
phonely.on("transcript-message", ({ allMessages }) => {
  console.log(allMessages);
});

Token Expiration

Session tokens are short lived. If a token expires, start a new web call session from your backend.