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

pbx0-sdk

v1.0.8

Published

PBX SDK for authentication and API integration

Readme

PBX0 SDK

A lightweight, modular TypeScript SDK for integrating with PBX APIs. Built with Axios, featuring automatic token management, request interceptors, and centralized error handling.


Table of Contents


Installation

npm install pbx0-sdk

Quick Start

import { PBX0SDK } from 'pbx0-sdk';

const pbx = new PBX0SDK();

// Authenticate
const user = await pbx.auth.login({
  email: '[email protected]',
  password: 'your-password',
});

// Fetch users
const users = await pbx.user.getAll({ page: 1, limit: 10 });

// Fetch companies
const companies = await pbx.company.getAll({ page: 1, limit: 10 });

Architecture

The SDK follows a modular architecture. Each business domain is a separate module, all sharing a single HTTP client with built-in authentication.

PBX0SDK (entry point)
  ├── auth          → Authentication (login, token refresh)
  ├── user          → Users & contacts
  ├── department    → Departments
  ├── account       → Accounts, clusters, sales agents
  ├── company       → Companies
  ├── extension     → Extensions
  ├── did           → DIDs, port-ins, music-on-hold
  ├── ivr           → IVR menus
  ├── queue         → Call queues
  ├── netwatch      → Network monitoring
  ├── schedule      → Time-of-day routing
  ├── callGroup     → Call/hunt groups
  └── carrier       → Carriers & carrier trunks

Core Layer

| Component | Purpose | |-----------|---------| | PBXClient | Creates the Axios HTTP client with base URL | | AuthManager | Singleton that stores access token & expiry | | Request Interceptor | Injects Authorization: Bearer <token> on every request | | Response Interceptor | Auto-refreshes token on 401, queues concurrent failures | | Response Handler | Unwraps { status, data } envelope, throws PBXError on failure | | PBXError | Custom error class with statusCode and errors fields |

Base URL Configuration

The SDK automatically resolves the API base URL from environment variables. You do not need to pass baseURL when constructing PBX0SDK:

| Environment Variable | Context | Priority | |---------------------|---------|----------| | API_URL | Server-side (Node.js) | Highest | | NEXT_PUBLIC_API_URL | Client-side (Browser) | Fallback |

// No config needed — SDK reads API_URL or NEXT_PUBLIC_API_URL automatically
const pbx = new PBX0SDK();

You may still explicitly pass baseURL to override the environment variables:

const pbx = new PBX0SDK({ baseURL: 'https://custom-api.example.com/api' });

API Response Format

The SDK expects all API responses to follow this Laravel-style structure:

{
  "status": true,
  "message": "Success",
  "data": { ... }
}

On success, the SDK automatically unwraps and returns response.data.data. On failure, it throws a PBXError.


Authentication

Login

const user = await pbx.auth.login({
  email: '[email protected]',
  password: 'your-password',
});
// Returns user object
// Token is automatically stored in AuthManager

Token Management

// Manually set a token (e.g., from NextAuth session)
pbx.setToken('your-access-token', Date.now() + 3600 * 1000);

// Clear token (logout)
pbx.clearToken();

Auto Token Refresh

When a 401 response is received, the SDK automatically:

  1. Calls /auth/refresh to obtain a new token
  2. Queues any concurrent requests that arrive during refresh
  3. Replays queued requests with the new token
  4. Falls back to clearing the token if refresh fails

No manual handling required.


Module Reference


1. AuthModule

Access: pbx.auth

| Method | Endpoint | Description | |--------|----------|-------------| | login(payload) | POST /auth/login | Authenticate with email & password | | refreshToken() | POST /auth/refresh | Refresh the access token |

Login Example:

const user = await pbx.auth.login({
  email: '[email protected]',
  password: 'your-password',
});

2. UserModule

Access: pbx.user

| Method | Endpoint | Description | |--------|----------|-------------| | getAll(options?) | GET /users | List users (paginated) | | getById(id) | GET /users/:id | Get user by ID | | create(payload) | POST /users | Create a new user | | update(id, payload) | PUT /users/:id | Update a user | | getProfile() | GET /user/profile | Get current user's profile | | getContacts(options?) | GET /contacts | List contacts (paginated) | | createContact(payload) | POST /contacts | Create a new contact |

Examples:

// Get paginated user list
const result = await pbx.user.getAll({ page: 1, limit: 25 });
console.log(result.data);    // User[]
console.log(result.total);   // Total count
console.log(result.current_page);

// Get user by ID
const user = await pbx.user.getById('123');

// Create user
const newUser = await pbx.user.create({
  name: 'John Doe',
  email: '[email protected]',
  role: 'admin',
});

// Update user
await pbx.user.update('123', { name: 'Jane Doe' });

// Get my profile
const profile = await pbx.user.getProfile();

// Get contacts
const contacts = await pbx.user.getContacts({ page: 1, limit: 50 });

// Create contact
const contact = await pbx.user.createContact({
  name: 'Jane Smith',
  phone: '+1-555-0199',
  email: '[email protected]',
});

3. DepartmentModule

Access: pbx.department

| Method | Endpoint | Description | |--------|----------|-------------| | getAll(options?) | GET /departments | List all departments |

Example:

const departments = await pbx.department.getAll({ page: 1, limit: 20 });
// Returns Department[]

4. AccountModule

Access: pbx.account

| Method | Endpoint | Description | |--------|----------|-------------| | getAll(options?) | GET /accounts | List accounts (paginated) | | getById(id) | GET /accounts/:id | Get account by ID | | create(payload) | POST /accounts | Create a new account | | update(id, payload) | PUT /accounts/:id | Update an account | | getClusters() | GET /clusters | Get all clusters | | getSalesAgents() | GET /sales-agents | Get all sales agents |

Examples:

// List accounts
const accounts = await pbx.account.getAll({ page: 1, limit: 20 });

// Get account by ID
const account = await pbx.account.getById('456');

// Create account
const newAccount = await pbx.account.create({
  name: 'Acme Corp',
  cluster_id: 'cluster-1',
});

// Get clusters
const clusters = await pbx.account.getClusters();

// Get sales agents
const agents = await pbx.account.getSalesAgents();

5. CompanyModule

Access: pbx.company

| Method | Endpoint | Description | |--------|----------|-------------| | getAll(options?) | GET /companies | List companies (paginated) | | getById(id) | GET /companies/:id | Get company by ID | | create(payload) | POST /companies | Create a new company | | update(id, payload) | PUT /companies/:id | Update a company |

Examples:

// List companies
const result = await pbx.company.getAll({ page: 1, limit: 10 });

// Get company by ID
const company = await pbx.company.getById('comp-1');

// Create company
await pbx.company.create({
  company_name: 'New Corp',
  domain: 'newcorp.com',
  email: '[email protected]',
});

// Update company
await pbx.company.update('comp-1', { company_name: 'Updated Corp' });

6. ExtensionModule

Access: pbx.extension

| Method | Endpoint | Description | |--------|----------|-------------| | getAll(options?) | GET /extensions | List extensions (paginated) | | getById(id) | GET /extensions/:id | Get extension by ID | | create(payload) | POST /extensions | Create a new extension | | update(id, payload) | PUT /extensions/:id | Update an extension | | delete(id) | DELETE /extensions/:id | Delete an extension |

Examples:

// List extensions
const result = await pbx.extension.getAll({ page: 1, limit: 20 });

// Create extension
await pbx.extension.create({
  account_id: 'acc-1',
  extension_number: 101,
  route_type: 'user',
  route_id: 'user-123',
});

// Delete extension
await pbx.extension.delete('ext-1');

7. DIDModule

Access: pbx.did

| Method | Endpoint | Description | |--------|----------|-------------| | getAll(options?) | GET /dids | List DIDs (paginated) | | getById(id) | GET /dids/:id | Get DID by ID | | create(payload) | POST /dids | Create a new DID | | update(id, payload) | PUT /dids/:id | Update a DID | | delete(id) | DELETE /dids/:id | Delete a DID | | bulkUpdate(payload) | PATCH /dids/bulk-update | Bulk update DIDs | | getMusicOnHold() | GET /music-on-hold | Get music-on-hold entries | | getPortIns(options?) | GET /dids/port-in | List port-in requests | | getPortInById(id) | GET /dids/port-in/:id | Get port-in by ID | | createPortIn(payload) | POST /dids/port-in | Create port-in request | | updatePortIn(id, payload) | PUT /dids/port-in/:id | Update port-in | | deletePortIn(id) | DELETE /dids/port-in/:id | Delete port-in |

Examples:

// List DIDs
const result = await pbx.did.getAll({ page: 1, limit: 20 });

// Create DID
await pbx.did.create({
  did: '+1-555-1234',
  account_id: 'acc-1',
});

// Bulk update DIDs
const updated = await pbx.did.bulkUpdate({
  ids: ['did-1', 'did-2'],
  account_id: 'acc-2',
});

// Get music on hold list
const music = await pbx.did.getMusicOnHold();

// Port-in operations
const ports = await pbx.did.getPortIns({ page: 1, limit: 20 });
const port = await pbx.did.getPortInById('port-1');
await pbx.did.createPortIn({ number: '+1-555-5678' });
await pbx.did.deletePortIn('port-1');

8. IVRsModule

Access: pbx.ivr

| Method | Endpoint | Description | |--------|----------|-------------| | getAll(options?) | GET /ivrs | List IVRs (paginated) | | getById(id) | GET /ivrs/:id | Get IVR by ID | | create(payload) | POST /ivrs | Create a new IVR | | update(id, payload) | PUT /ivrs/:id | Update an IVR |

Examples:

const result = await pbx.ivr.getAll({ page: 1, limit: 10 });
const ivr = await pbx.ivr.getById('ivr-1');
await pbx.ivr.create({ name: 'Main Menu', account_id: 'acc-1' });
await pbx.ivr.update('ivr-1', { name: 'Updated Menu' });

9. QueuesModule

Access: pbx.queue

| Method | Endpoint | Description | |--------|----------|-------------| | getAll(options?) | GET /queues | List queues (paginated) | | getById(id) | GET /queues/:id | Get queue by ID | | create(payload) | POST /queues | Create a new queue | | update(id, payload) | PUT /queues/:id | Update a queue |

Examples:

const result = await pbx.queue.getAll({ page: 1, limit: 10 });
const queue = await pbx.queue.getById('queue-1');
await pbx.queue.create({ name: 'Support Queue', account_id: 'acc-1' });

10. NetwatchModule

Access: pbx.netwatch

| Method | Endpoint | Description | |--------|----------|-------------| | getAll(options?) | GET /netwatches | List netwatch entries | | getById(id) | GET /netwatch/:id | Get netwatch by ID | | create(payload) | POST /netwatch | Create netwatch entry | | update(id, payload) | PUT /netwatch/:id | Update netwatch | | delete(id) | DELETE /netwatch/:id | Delete netwatch | | checkStatus(id) | POST /api/netwatch/:id/check-status | Check netwatch status |

Examples:

const result = await pbx.netwatch.getAll({ page: 1, limit: 10 });

await pbx.netwatch.create({
  description: 'Main Gateway',
  ip_address: '10.0.0.1',
  up_route_type: 'trunk',
  up_route_id: 'trunk-1',
  down_route_type: 'ivr',
  down_route_id: 'ivr-1',
});

const status = await pbx.netwatch.checkStatus('net-1');
// { status: 'OK' | 'Failed', latency?: number }

11. ScheduleModule

Access: pbx.schedule

| Method | Endpoint | Description | |--------|----------|-------------| | getAll(options?) | GET /time-of-day | List schedules (paginated) | | getById(id) | GET /time-of-day/:id | Get schedule by ID | | create(payload) | POST /time-of-day | Create a schedule | | update(id, payload) | PUT /time-of-day/:id | Update a schedule | | delete(id) | DELETE /time-of-day/:id | Delete a schedule |

Examples:

const result = await pbx.schedule.getAll({ page: 1, limit: 10 });
const schedule = await pbx.schedule.getById('sched-1');

await pbx.schedule.create({
  account_id: 'acc-1',
  description: 'Business Hours',
  daymode: { active: true, route_id: 'ivr-1', route_type: 'ivr' },
  nightmode: { active: false },
});

await pbx.schedule.delete('sched-1');

12. CallGroupModule

Access: pbx.callGroup

| Method | Endpoint | Description | |--------|----------|-------------| | getAll(options?) | GET /api/callgroups | List call groups (paginated) | | getById(id) | GET /api/callgroups/:id | Get call group by ID | | create(payload) | POST /api/callgroups | Create a call group | | update(id, payload) | PUT /api/callgroups/:id | Update a call group | | delete(id) | DELETE /api/callgroups/:id | Delete a call group |

Examples:

const result = await pbx.callGroup.getAll({ page: 1, limit: 10 });
const group = await pbx.callGroup.getById('cg-1');

await pbx.callGroup.create({
  account_id: 'acc-1',
  description: 'Sales Team',
  extension: '200',
  strategy: 'ringall',
  ringTime: 30,
  members: [
    { id: 'user-1', name: 'Alice', isActive: true, isMonitoring: false },
  ],
});

await pbx.callGroup.delete('cg-1');

13. CarrierModule

Access: pbx.carrier

| Method | Endpoint | Description | |--------|----------|-------------| | getAll(options?) | GET /carriers | List carriers (paginated) | | getById(id) | GET /carriers/:id | Get carrier by ID | | create(payload) | POST /carriers | Create a new carrier | | update(id, payload) | PUT /carriers/:id | Update a carrier | | getTrunks(options?) | GET /carrier-trunks | List carrier trunks (paginated) |

Examples:

// List carriers
const result = await pbx.carrier.getAll({ page: 1, limit: 10 });

// Create carrier
await pbx.carrier.create({
  company_id: 'comp-1',
  carrier_name: 'My Carrier',
  address: '123 Main St',
  city: 'New York',
  state: 'NY',
  zipcode: '10001',
  billing: { email: '[email protected]', contact: 'John', phone: '', url: '' },
  technical: { email: '', contact: '', phone: '', url: '' },
  porting: { email: '', contact: '', phone: '', url: '' },
});

// Get carrier trunks
const trunks = await pbx.carrier.getTrunks({ page: 1, limit: 10 });

Pagination

Modules that return lists follow a standard paginated response:

interface PaginatedResponse<T> {
  data: T[];             // Array of items for current page
  total: number;         // Total items across all pages
  current_page: number;  // Current page number
  per_page: number;      // Items per page
  last_page: number;     // Total number of pages
}

Modules using QueryOptions support:

interface QueryOptions {
  isPaginated?: boolean;           // Default: true
  page?: number;                   // Default: 1
  limit?: number;                  // Default: 10
  search?: string;                 // Search term
  sort?: string;                   // Sort field (prefix with "-" for descending, e.g. "-createdAt")
  all?: boolean;                   // Fetch all records at once (skips pagination)
  filters?: Record<string, any>;  // Additional query filters
}

Fetching all records:

const allAccounts = await pbx.account.getAll({ all: true });

Fetching all records with sorting:

const allAccounts = await pbx.account.getAll({
  all: true,
  sort: "-createdAt",
});

Paginated with sorting:

const result = await pbx.account.getAll({
  page: 1,
  limit: 25,
  sort: "name",
});

Example: Iterating all pages

async function getAllUsers(): Promise<User[]> {
  let page = 1;
  const all: User[] = [];
  let total = 0;

  do {
    const result = await pbx.user.getAll({ page, limit: 100 });
    all.push(...result.data);
    total = result.total;
    page++;
  } while (all.length < total);

  return all;
}

Error Handling

All SDK methods throw PBXError on API failure:

import { PBX0SDK, PBXError } from 'pbx0-sdk';

try {
  const user = await pbx.user.getById('invalid-id');
} catch (err) {
  if (err instanceof PBXError) {
    console.log(err.message);      // Human-readable error message
    console.log(err.statusCode);   // HTTP status code (e.g., 404)
    console.log(err.errors);       // Field-level validation errors
  }
}

Error Properties

| Property | Type | Description | |----------|------|-------------| | message | string | Error message from the API | | statusCode | number? | HTTP status code | | errors | any | Field-level validation errors (typically Record<string, string[]>) |


Token Management

Setting a Token from External Auth

When using an external authentication system (e.g., NextAuth):

import { PBX0SDK } from 'pbx0-sdk';

const pbx = new PBX0SDK();

// After obtaining a token from your auth provider
pbx.setToken('jwt-access-token', expiresAtTimestamp);

// Later, to log out
pbx.clearToken();

Token Persistence

The token is stored in memory only (via AuthManager singleton). For persistence across page reloads, store the token in localStorage or cookies and call setToken() on app initialization.


Usage Patterns

Client-Side (Browser)

import { PBX0SDK } from 'pbx0-sdk';

// Create a singleton instance
const pbx = new PBX0SDK();

// Set token from your auth system
pbx.setToken(accessToken, expiresAt);

// Use anywhere
async function loadUsers() {
  const result = await pbx.user.getAll({ page: 1, limit: 25 });
  return result.data;
}

Server-Side (Next.js Server Actions)

import { getServerSDK } from '@/libs/server-sdk';

export async function getUsers() {
  const pbx = await getServerSDK();
  const result = await pbx.user.getAll({ page: 1, limit: 10 });
  return { data: result.data, total: result.total };
}

Server SDK factory implementation:

import { PBX0SDK } from 'pbx0-sdk';

let instance: PBX0SDK | null = null;

export async function getServerSDK(): Promise<PBX0SDK> {
  const token = await getAuthTokenFromSession();

  if (!instance) {
    instance = new PBX0SDK();
  }

  if (token) {
    instance.setToken(token, Infinity);
  }

  return instance;
}

Complete Client-Side Integration Example (React)

import { PBX0SDK } from 'pbx0-sdk';
import { useEffect, useState } from 'react';

const pbx = new PBX0SDK();

function UsersPage() {
  const [users, setUsers] = useState<any[]>([]);

  useEffect(() => {
    // Token is assumed to already be set via setToken()
    pbx.user.getAll({ page: 1, limit: 10 })
      .then((result) => setUsers(result.data))
      .catch((err) => console.error('Failed:', err.message));
  }, []);

  return (
    <ul>
      {users.map((u) => <li key={u.id}>{u.name}</li>)}
    </ul>
  );
}

Building & Development

# Build the SDK
npm run build

# Development - watch mode (auto-rebuild on changes)
npm run dev

# Run tests
npm test

# Run example
npm run start

Exports

import { PBX0SDK, PBXError } from 'pbx0-sdk';

| Export | Description | |--------|-------------| | PBX0SDK | Main SDK class with all modules | | PBXError | Custom error class for API errors |


License

MIT