{"id":15517,"library":"ari-client","title":"Asterisk REST Interface (ARI) Client","description":"The `ari-client` package provides a JavaScript client library for interacting with the Asterisk REST Interface (ARI). It offers a higher-level, Asterisk-specific API built upon the underlying `swagger-js` library, simplifying interaction with Asterisk resources such as bridges, channels, endpoints, and playback objects. The library supports both callback-based and Promise-based asynchronous operations for connecting to ARI, listing resources, performing actions (like adding channels to bridges), and creating new resource instances (e.g., `ari.Bridge()`, `ari.Channel()`). It is currently at version 2.2.0, indicating a stable release. While a strict release cadence isn't explicitly stated, its active development suggests ongoing maintenance. Its key differentiator is abstracting the raw Swagger API into an intuitive, resource-oriented interface tailored specifically for Asterisk development.","status":"active","version":"2.2.0","language":"javascript","source_language":"en","source_url":"git://github.com/asterisk/node-ari-client","tags":["javascript","Asterisk","ARI"],"install":[{"cmd":"npm install ari-client","lang":"bash","label":"npm"},{"cmd":"yarn add ari-client","lang":"bash","label":"yarn"},{"cmd":"pnpm add ari-client","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Core dependency for generating the underlying API client from the Swagger/OpenAPI specification. `ari-client` builds its higher-level API on top of this.","package":"swagger-js","optional":false}],"imports":[{"note":"The library primarily uses CommonJS `require` syntax as demonstrated in its documentation and targets Node.js environments. Direct ESM `import` is not officially documented or supported for the main entry point in this version.","wrong":"import client from 'ari-client';","symbol":"client","correct":"const client = require('ari-client');"},{"note":"`connect` is a method exposed by the default export `client`. It is not a named export. Ensure the `client` object is correctly obtained first.","wrong":"import { connect } from 'ari-client';","symbol":"connect","correct":"client.connect(url, username, password)"},{"note":"Resource managers like `bridges`, `channels`, etc., are properties of the `ari` object returned by the `connect` function. They are not directly importable from the `ari-client` package itself.","wrong":"const bridges = require('ari-client').bridges;","symbol":"ari.bridges","correct":"const ari = await client.connect(url, username, password); ari.bridges.list();"}],"quickstart":{"code":"const client = require('ari-client');\n\nconst url = process.env.ARI_URL ?? 'http://localhost:8088/ari';\nconst username = process.env.ARI_USERNAME ?? 'asterisk';\nconst password = process.env.ARI_PASSWORD ?? 'asterisk';\n\nasync function main() {\n  try {\n    console.log(`Connecting to ARI at ${url}...`);\n    const ari = await client.connect(url, username, password);\n    console.log('Successfully connected to ARI.');\n\n    // List all active bridges\n    console.log('Listing existing bridges...');\n    const bridges = await ari.bridges.list();\n    console.log(`Found ${bridges.length} bridge(s).`);\n    bridges.forEach(b => console.log(`  Bridge ID: ${b.id}, Type: ${b.bridge_type}`));\n\n    // Create a new channel and listen for events\n    const channel = ari.Channel();\n    channel.on('StasisStart', (event, channelInstance) => {\n      console.log(`Channel ${channelInstance.id} entered Stasis application.`);\n      // Perform actions with the channel, e.g., answer, play media\n      channelInstance.answer()\n        .then(() => channelInstance.play({media: 'sound:hello-world'}))\n        .then(playback => console.log(`Playing sound: ${playback.id}`))\n        .catch(err => console.error(`Error playing sound: ${err.message}`));\n    });\n    channel.on('ChannelDtmfReceived', (event, channelInstance) => {\n      console.log(`DTMF received on channel ${channelInstance.id}: ${event.digit}`);\n    });\n    channel.on('StasisEnd', (event, channelInstance) => {\n      console.log(`Channel ${channelInstance.id} left Stasis application.`);\n    });\n\n    console.log('Originating a new channel...');\n    const originatedChannel = await channel.originate({\n      endpoint: 'PJSIP/1000',\n      app: 'my-stasis-app',\n      appArgs: 'dialed'\n    });\n    console.log(`Channel ${originatedChannel.id} originated. Waiting for events...`);\n\n    // Keep the process alive to receive events (in a real app, use a proper event loop)\n    // setTimeout(() => { console.log('Exiting after 60 seconds.'); process.exit(0); }, 60000);\n\n  } catch (err) {\n    console.error(`Failed to connect or interact with ARI: ${err.message}`);\n    process.exit(1);\n  }\n}\n\nmain();","lang":"javascript","description":"Demonstrates connecting to Asterisk ARI, listing bridges, creating a new channel, and handling Stasis events using Promises."},"warnings":[{"fix":"Always use `.then().catch()` for Promise-based calls or ensure consistent error-first callbacks. Avoid mixing directly within the same logical flow.","message":"Mixing callback and Promise patterns can lead to inconsistent error handling and control flow. While both are supported, it is best practice to standardize on one for better maintainability.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Ensure `resource.on('Event', handler)` calls precede `resource.create()` or `resource.originate()` to correctly capture initial lifecycle events.","message":"Event listeners on resource instances (e.g., `channel.on('StasisStart', ...)`) must be registered *before* the corresponding create or originate operation is called. Events for resources that don't yet exist in ARI cannot be captured.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"If using `ari.resourceType.operation({...})`, carefully check the API documentation for required IDs. When possible, prefer calling operations on resource instances (e.g., `channel.play({...})`) to leverage implicit ID handling.","message":"When directly calling resource operations via the `ari` client (e.g., `ari.channels.play`), you must manually provide all required IDs (e.g., `channelId`, `playbackId`) in the options object. This differs from calling operations on resource *instances* where the ID is implicit.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-21T00:00:00.000Z","next_check":"2026-07-20T00:00:00.000Z","problems":[{"fix":"Use `const client = require('ari-client');` to import the library in Node.js environments.","cause":"Attempting to use `import client from 'ari-client'` or another ESM import style, but the package is primarily designed for CommonJS `require`.","error":"TypeError: client.connect is not a function"},{"fix":"Verify that Asterisk is running, ARI is enabled and configured correctly (`/etc/asterisk/ari.conf`), the URL (`ws://` or `wss://`), username, and password are all correct. Check firewall rules between your Node.js application and the Asterisk server.","cause":"The connection to the Asterisk ARI server was reset or refused. This often indicates incorrect URL, credentials, network issues, or ARI not being enabled/running on Asterisk.","error":"Error: read ECONNRESET"},{"fix":"Ensure that the `bridgeId` being used is valid and corresponds to an active bridge. Use `ari.bridges.list()` to get a current list of bridges or verify bridge creation was successful.","cause":"An operation was attempted on a bridge ID that does not exist or is no longer active in Asterisk.","error":"UnhandledPromiseRejectionWarning: Error: bridge not found"}],"ecosystem":"npm"}