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

agentcall

v0.1.1

Published

Node.js SDK for AgentCall — programmable phone numbers for AI agents

Readme

agentcall

Node.js SDK for AgentCall — programmable phone numbers for AI agents.

Provision numbers, send/receive SMS, extract OTP codes, and initiate voice calls from your AI agent or backend service.

Install

npm install agentcall

Quick start

import AgentCall from 'agentcall'

const client = new AgentCall('ac_live_xxxxxxxxxxxxx')

// 1. Provision a phone number
const number = await client.numbers.provision({ country: 'US', type: 'local' })
console.log(number.number) // +12125551234

// 2. Send an SMS
await client.sms.send({
  from: number.number,
  to: '+14155559876',
  body: 'Your verification code will arrive shortly.',
})

// 3. Wait for an OTP (polls inbox automatically)
const otp = await client.sms.waitForOTP(number.id, { timeout: 60000 })
console.log(otp) // "482913"

Authentication

Get your API key from the AgentCall dashboard. Keys are prefixed with ac_live_.

const client = new AgentCall('ac_live_xxxxxxxxxxxxx')

Configuration

const client = new AgentCall('ac_live_xxx', {
  baseUrl: 'https://api.agentcall.co', // default
  timeout: 30000,                       // request timeout in ms, default 30s
})

API Reference

client.numbers

numbers.provision(options?)

Provision a new phone number.

const number = await client.numbers.provision({
  country: 'US',          // optional, default 'US'
  type: 'local',          // 'local' | 'tollfree' | 'mobile' | 'sim'
  label: 'Signup flow',   // optional human-readable label
})

Returns: PhoneNumber

{
  id: string
  number: string          // E.164 format, e.g. '+12125551234'
  country: string
  type: string
  label: string | null
  status: string          // 'active' | 'released'
  monthlyRate: number
  provisionedAt: string   // ISO 8601
}

numbers.list(params?)

List all provisioned numbers.

const result = await client.numbers.list({
  limit: 20,        // optional, default 20
  cursor: undefined, // optional, for pagination
  country: 'US',    // optional filter
  type: 'local',    // optional filter
})
// result.data — PhoneNumber[]
// result.hasMore — boolean
// result.nextCursor — string | null

numbers.get(numberId)

Get a single phone number by ID.

const number = await client.numbers.get('num_abc123')

numbers.release(numberId)

Release (deactivate) a phone number. Stops billing. Irreversible.

await client.numbers.release('num_abc123')

client.sms

sms.send(options)

Send an SMS from a provisioned number.

const message = await client.sms.send({
  from: '+12125551234', // your provisioned number (E.164)
  to: '+14155559876',   // destination (E.164)
  body: 'Hello!',       // max 1600 characters
})

Returns: Message

{
  id: string
  direction: string       // 'inbound' | 'outbound'
  from: string
  to: string
  body: string
  otp: string | null      // extracted OTP code, if detected
  status: string          // 'queued' | 'delivered'
  cost: number
  receivedAt: string
  createdAt: string
}

sms.inbox(numberId, options?)

Get inbound messages for a phone number.

const inbox = await client.sms.inbox('num_abc123', {
  limit: 20,          // optional
  cursor: undefined,   // optional, for pagination
  since: '2025-01-01T00:00:00Z', // optional ISO timestamp
  otpOnly: true,       // optional, only return messages with OTP codes
})

sms.get(messageId)

Get a single message by ID.

const msg = await client.sms.get('msg_xyz789')

sms.waitForOTP(numberId, options?)

Poll the inbox until an OTP code arrives. This is the primary method for AI agent verification flows.

const otp = await client.sms.waitForOTP('num_abc123', {
  timeout: 60000,      // max wait in ms, default 60s
  pollInterval: 2000,  // poll frequency in ms, default 2s
  since: new Date().toISOString(), // only look at new messages
})

if (otp) {
  console.log(`Got OTP: ${otp}`)
} else {
  console.log('Timed out waiting for OTP')
}

Returns: string | null — the OTP code, or null if timeout.


client.calls

calls.initiate(options)

Start an outbound phone call.

const call = await client.calls.initiate({
  from: '+12125551234',   // your provisioned number (E.164)
  to: '+14155559876',     // destination (E.164)
  webhookUrl: 'https://example.com/call-events', // optional
  record: false,          // optional, Pro plan only ($0.01/min)
})

Returns: Call

{
  id: string
  direction: string       // 'inbound' | 'outbound'
  from: string
  to: string
  status: string          // 'queued' | 'ringing' | 'in-progress' | 'completed' | 'failed'
  duration: number | null // seconds
  record: boolean
  recordingUrl: string | null
  createdAt: string
}

calls.list(params?)

List call history.

const calls = await client.calls.list({ limit: 20 })

calls.get(callId)

Get a single call by ID.

const call = await client.calls.get('call_abc123')

calls.hangup(callId)

Terminate an active call.

await client.calls.hangup('call_abc123')

client.webhooks

webhooks.create(options)

Register a webhook endpoint for real-time events.

const webhook = await client.webhooks.create({
  url: 'https://example.com/hooks/agentcall',
  events: ['sms.inbound', 'sms.otp', 'call.status'],
})
console.log(webhook.secret) // signing secret, shown once

Valid events: sms.inbound, sms.otp, call.inbound, call.ringing, call.status, call.recording, number.released

webhooks.list()

List all active webhooks.

const hooks = await client.webhooks.list()

webhooks.delete(webhookId)

Deactivate a webhook.

await client.webhooks.delete('wh_abc123')

client.usage

usage.get(period?)

Get usage and cost breakdown for a billing period.

const usage = await client.usage.get('2025-06') // YYYY-MM, defaults to current month

console.log(usage.breakdown.sms.outbound)  // number of outbound SMS
console.log(usage.total)                    // total cost
console.log(usage.currency)                 // 'usd'

Returns: UsageData

{
  period: string
  breakdown: {
    numbers: { count: number; cost: number }
    sms: { inbound: number; outbound: number; cost: number }
    calls: { minutes: number; cost: number }
    recording: { minutes: number; cost: number }
  }
  total: number
  currency: string
}

Error handling

All API errors throw AgentCallError with a code and statusCode:

import AgentCall from 'agentcall'

try {
  await client.numbers.provision({ type: 'sim' })
} catch (err) {
  if (err instanceof Error && 'statusCode' in err) {
    console.error(err.message)    // "SIM numbers require Pro plan"
    console.error(err.code)       // "plan_limit"
    console.error(err.statusCode) // 403
  }
}

Common error codes:

| Code | Status | Meaning | |------|--------|---------| | unauthorized | 401 | Invalid or missing API key | | plan_limit | 403 | Feature or quota requires upgrade | | not_found | 404 | Resource doesn't exist | | validation_error | 422 | Invalid request body | | rate_limited | 429 | Too many requests (auto-retried by SDK) |

The SDK automatically retries rate-limited (429) and server error (5xx) responses up to 3 times with exponential backoff.

License

MIT