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

@telenow/server

v0.1.2

Published

Telenow voice AI SDK for Node, Bun, Deno & edge — place AI agent phone calls, mint browser/app call sessions, transfer & end live calls, verify webhooks, and build custom-LLM streaming (SSE) endpoints. Zero dependencies.

Readme

@telenow/server

Telenow voice AI SDK for Node 18+ / Bun / Deno / Cloudflare Workers. Zero dependencies (global fetch + Web Crypto). From your backend you can: place AI agent phone calls, mint browser/app call sessions, transfer/end live calls, verify webhooks, manage agents, and build Custom API (bring-your-own-LLM) streaming endpoints.

npm install @telenow/server

Before you start

  • A Telenow account + agent (dashboard → Agents). Copy the agent ID from the agent page (or its Publish tab samples).
  • An org API key — dashboard → Developers tab. Keep it server-side only; it's sent as the X-API-Key header.
  • Phone calls additionally need a phone number attached to the agent (dashboard → Numbers).
import { Telenow } from '@telenow/server';

const tn = new Telenow({
  apiKey: process.env.TELENOW_API_KEY!,   // required
  baseUrl: 'https://api.telenow.ai',      // default — override for self-hosted
  // fetch: customFetch,                  // optional fetch override (Node < 18 polyfill)
});

Phone calls

const { sessionId, callId, status } = await tn.calls.create({
  agentId: 'AGENT_UUID',
  to: '+15551234567',                       // E.164
  variables: { order_id: 'A-1042' },        // context variables (required ones must be present)
  identifier: 'customer-9',                 // trusted caller identity for the agent's tools
  firstResponse: 'Hi! Calling about your delivery.', // optional opener override for THIS call
  machineDetection: 'true',                 // 'true' = auto-voicemail, 'hangup' (Plivo)
});

Control a live call (works for phone and web calls — the client SDKs expose call.sessionId for exactly this):

await tn.calls.transfer(sessionId, '+15557654321'); // warm transfer to a human
await tn.calls.end(sessionId);                      // hang up

Web calls (mint a session for your frontend)

The recommended browser/app flow: mint here, hand the result to the client, the client SDK connects — the API key never reaches the browser.

app.post('/voice/session', async (_req, res) => {
  const session = await tn.calls.createWeb({
    agentId: process.env.AGENT_ID!,
    variables: { customer_name: 'Asha' },   // baked in server-side — client can't tamper
    identifier: 'customer-9',
  });
  res.json(session);   // { sessionId, websocketUrl } → TelenowCall({ session })
});

Webhooks

Telenow signs every delivery with X-VoiceAI-Signature: sha256=<hex> (HMAC-SHA256 of the raw body). Always verify before trusting the payload:

app.post('/webhooks/telenow', express.raw({ type: 'application/json' }), async (req, res) => {
  const ok = await tn.webhooks.verify(req.body, req.get('x-voiceai-signature') ?? '', SECRET);
  if (!ok) return res.status(401).end();
  const event = JSON.parse(req.body.toString());
  switch (event.event) {
    case 'call.started':      break; // sessionId, agentId, timestamps
    case 'call.ended':        break; // + duration, optional recording URL & transcript
    case 'transcript.ready':  break; // full transcript
    case 'tool.invoked':      break; // tool name, input, result
  }
  res.status(200).end();
});

Configure endpoints + which events to receive in the dashboard (Webhooks), per agent or org-wide. Payload shapes: webhook events reference.

Custom API — stream your own LLM into calls

When an agent's Brain is set to Custom API, Telenow runs STT + TTS and POSTs each user turn to your endpoint (?calling=true&stream=true, JSON body { query, userId?, ...payload }), then speaks your Server-Sent-Events reply as tokens arrive. These helpers emit the exact wire format:

import { customApiNodeHandler, callEnd } from '@telenow/server';

// Express or node:http
app.post('/telenow-llm', customApiNodeHandler(async function* ({ query, userId }) {
  for await (const token of myLlm.stream(query)) yield token;  // spoken as it streams
  // yield callEnd('Goodbye!');                                // optional: hang up after reply
}, { bearer: process.env.TELENOW_BEARER }));                   // 401s anything without your bearer
import { customApiFetchHandler } from '@telenow/server';

// Next.js route handler / Bun.serve / Workers / Deno
export const POST = customApiFetchHandler(async function* ({ query }) {
  yield `You said: ${query}`;
});

Notes that save debugging time:

  • Yield strings for spoken token deltas; yield callEnd(msg?) (or any { type: ... } object) for control events. The helper appends the SSE [DONE] terminator — even if your generator throws midway, so the turn ends cleanly.
  • Each event is written as one chunk and the provided headers disable proxy buffering (X-Accel-Buffering: no) — without that, nginx batches your tokens into one late burst.
  • Transfer is a REST action, not an SSE event: call tn.calls.transfer(sessionId, to) from inside your handler.
  • Lower-level pieces are exported too: customApiStream, sseEncode, SSE_DONE, SSE_HEADERS.

Agents & everything else

tn.agents.list() / get(id) / create(data) / update(id, data) mirror the Agents API. Anything not wrapped yet: call the REST API with the same X-API-Key header.

Errors

Every non-2xx (and { success: false } envelope) throws TelenowError:

import { TelenowError } from '@telenow/server';
try {
  await tn.calls.create({ agentId, to });
} catch (e) {
  if (e instanceof TelenowError) console.error(e.status, e.message, e.body);
}

| Status | Usual cause | |---|---| | 401 / 403 | Wrong/revoked API key, or the agent's API access toggle is off (Publish tab). | | 400 | Missing required field — often a required context variable, or a non-E.164 number. | | 404 | Wrong agentId / sessionId, or the session already ended. |

Successful responses are unwrapped from the { success, data } envelope — you get the data object directly.


What is Telenow?

Telenow is a voice AI platform for building production-grade phone and web agents. Pick a brain from the built-in LLM/STT/TTS providers (or bring your own model and carrier), give the agent a prompt, tools, and knowledge, and put it on a phone number, your website, or your app. Every call comes with recordings, transcripts, analytics, warm transfer to humans, outbound campaigns, and webhooks.