关于 telnyx
Telnyx TypeScript 库是 Telnyx REST API 的官方 SDK,用于在服务端 TypeScript 或 JavaScript 中调用短信、语音和号码等接口。该库由 Stainless 生成,并附带一个 MCP 服务,供 AI 助手探索接口和发起测试请求。
主要功能
- 01封装 Telnyx REST API 的类型化调用
- 02提供分页遍历与 Webhook 签名验证
- 03内置自动重试与超时配置
- 04支持自定义 fetch 与代理设置
- 05附带可供 AI 助手使用的 MCP 服务
适用场景
- 01在 Node.js 服务中发送短信或发起呼叫控制通话
- 02验证入站 Telnyx Webhook 的签名
- 03让 AI 助手查阅接口文档并发起测试请求
MCP 相关
该库附带一个 MCP 服务,使 AI 助手能够探索 Telnyx API 的端点、发起测试请求并查阅文档。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
Telnyx TypeScript API Library
此库可在服务端 TypeScript 或 JavaScript 中便捷地访问 Telnyx REST API。
此库的完整 API 可在 api.md 中查看。
此库由 Stainless 生成。
MCP 服务
使用 Telnyx MCP 服务,让 AI 助手与此 API 交互,以探索端点、发送测试请求,并使用文档帮助将此 SDK 集成到应用中。
注意:你可能需要在 MCP 客户端中设置环境变量。
安装
npm install telnyx
使用
此库的完整 API 可在 api.md 中查看。
import Telnyx from 'telnyx';
const client = new Telnyx({
apiKey: process.env['TELNYX_API_KEY'], // This is the default and can be omitted
});
const response = await client.calls.dial({
connection_id: 'conn12345',
from: '+15557654321',
to: '+15551234567',
webhook_url: 'https://your-webhook.url/events',
});
console.log(response.data);
示例
以下示例均可运行:
搜索并订购电话号码
const { data: availableNumbers } = await client.availablePhoneNumbers.list({
filter: {
country_code: 'US',
national_destination_code: '312',
limit: 1,
},
});
const phoneNumber = availableNumbers?.[0]?.phone_number;
if (!phoneNumber) throw new Error('No phone numbers found');
const { data: order } = await client.numberOrders.create({
phone_numbers: [{ phone_number: phoneNumber }],
});
发送 SMS
const { data: message } = await client.messages.send({
from: '+15551234567',
to: '+15557654321',
text: 'Hello from Telnyx!',
});
发起呼叫控制通话
const { data: call } = await client.calls.dial({
connection_id: 'your-connection-id',
from: '+15551234567',
to: '+15557654321',
webhook_url: 'https://example.com/webhooks',
});
验证入站 Webhook
使用 Telnyx 公钥配置客户端,并将未经修改的原始请求正文传递给 unwrap。在验证前解析或重新序列化正文会导致签名失效。
const webhookClient = new Telnyx({
apiKey: process.env['TELNYX_API_KEY'],
publicKey: process.env['TELNYX_PUBLIC_KEY'],
});
const event = webhookClient.webhooks.unwrap(rawBody, {
headers: requestHeaders,
});
有关原始正文处理和错误响应,请参阅完整的 Express Webhook 验证示例。
配置重试
默认情况下,连接失败和可重试的 HTTP 响应会重试两次。为客户端设置 maxRetries,或为单个请求覆盖该值:
const retryingClient = new Telnyx({
apiKey: process.env['TELNYX_API_KEY'],
maxRetries: 4,
});
await retryingClient.messages.send(
{
from: '+15551234567',
to: '+15557654321',
text: 'Hello from Telnyx!',
},
{ maxRetries: 0 },
);
请求和响应类型
此库包含所有请求参数和响应字段的 TypeScript 定义。你可以按如下方式导入并使用:
import Telnyx from 'telnyx';
const client = new Telnyx({
apiKey: process.env['TELNYX_API_KEY'], // This is the default and can be omitted
});
const params: Telnyx.NumberOrderCreateParams = {
phone_numbers: [{ phone_number: '+15558675309' }],
};
const numberOrder: Telnyx.NumberOrderCreateResponse = await client.numberOrders.create(params);
每种方法、请求参数和响应字段的文档均可在文档字符串中查看,并会在大多数现代编辑器中通过悬停显示。
文件上传
与文件上传对应的请求参数可以通过多种形式传递:
File(或结构相同的对象)fetchResponse(或结构相同的对象)fs.ReadStream- 我们的
toFile辅助函数的返回值
import fs from 'fs';
import Telnyx, { toFile } from 'telnyx';
const client = new Telnyx();
// If you have access to Node `fs` we recommend using `fs.createReadStream()`:
await client.ai.audio.transcribe({
model: 'distil-whisper/distil-large-v2',
file: fs.createReadStream('/path/to/file'),
});
// Or if you have the web `File` API you can pass a `File` instance:
await client.ai.audio.transcribe({
model: 'distil-whisper/distil-large-v2',
file: new File(['my bytes'], 'file'),
});
// You can also pass a `fetch` `Response`:
await client.ai.audio.transcribe({
model: 'distil-whisper/distil-large-v2',
file: await fetch('https://somesite/file'),
});
// Finally, if none of the above are convenient, you can use our `toFile` helper:
await client.ai.audio.transcribe({
model: 'distil-whisper/distil-large-v2',
file: await toFile(Buffer.from('my bytes'), 'file'),
});
await client.ai.audio.transcribe({
model: 'distil-whisper/distil-large-v2',
file: await toFile(new Uint8Array([0, 1, 2]), 'file'),
});
错误处理
当库无法连接到 API,
或 API 返回非成功状态码(即 4xx 或 5xx 响应)时,
将抛出 APIError 的子类:
const numberOrder = await client.numberOrders
.create({ phone_numbers: [{ phone_number: '+15558675309' }] })
.catch(async (err) => {
if (err instanceof Telnyx.APIError) {
console.log(err.status); // 400
console.log(err.name); // BadRequestError
console.log(err.headers); // {server: 'nginx', ...}
} else {
throw err;
}
});
错误代码如下:
| 状态码 | 错误类型 |
|---|---|
| 400 | BadRequestError |
| 401 | AuthenticationError |
| 403 | PermissionDeniedError |
| 404 | NotFoundError |
| 422 | UnprocessableEntityError |
| 429 | RateLimitError |
| >=500 | InternalServerError |
| N/A | APIConnectionError |
重试
某些错误默认会自动重试 2 次,并采用较短的指数退避。 默认会重试连接错误(例如由网络连接问题导致的错误)、408 请求超时、409 冲突、 429 速率限制以及 >=500 内部错误。
你可以使用 maxRetries 选项进行配置或禁用重试:
// Configure the default for all requests:
const client = new Telnyx({
maxRetries: 0, // default is 2
});
// Or, configure per-request:
await client.numberOrders.create({ phone_numbers: [{ phone_number: '+15558675309' }] }, {
maxRetries: 5,
});
超时
请求默认会在 1 分钟后超时。你可以使用 timeout 选项进行配置:
// Configure the default for all requests:
const client = new Telnyx({
timeout: 20 * 1000, // 20 seconds (default is 1 minute)
});
// Override per-request:
await client.numberOrders.create({ phone_numbers: [{ phone_number: '+15558675309' }] }, {
timeout: 5 * 1000,
});
超时时会抛出 APIConnectionTimeoutError。
请注意,超时的请求默认会重试两次。
自动分页
Telnyx API 中的列表方法采用分页。
你可以使用 for await … of 语法遍历所有页面中的条目:
async function fetchAllAccessIPAddressResponses(params) {
const allAccessIPAddressResponses = [];
// Automatically fetches more pages as needed.
for await (const accessIPAddressResponse of client.accessIPAddress.list({
'page[number]': 1,
'page[size]': 50,
})) {
allAccessIPAddressResponses.push(accessIPAddressResponse);
}
return allAccessIPAddressResponses;
}
或者,你也可以一次请求一页:
let page = await client.accessIPAddress.list({ 'page[number]': 1, 'page[size]': 50 });
for (const accessIPAddressResponse of page.data) {
console.log(accessIPAddressResponse);
}
// Convenience methods are provided for manually paginating:
while (page.hasNextPage()) {
page = await page.getNextPage();
// ...
}
高级用法
访问原始 Response 数据(例如,标头)
所有方法返回的 APIPromise 类型都提供 .asResponse() 方法,可通过该方法访问 fetch() 返回的原始 Response。
成功响应的标头一旦收到,此方法就会立即返回,且不会读取响应正文,因此你可以自由编写自定义解析或流处理逻辑。
你也可以使用 .withResponse() 方法,同时获取原始 Response 和解析后的数据。
与 .asResponse() 不同,此方法会读取正文,并在解析完成后返回。
const client = new Telnyx();
const response = await client.numberOrders
.create({ phone_numbers: [{ phone_number: '+15558675309' }] })
.asResponse();
console.log(response.headers.get('X-My-Header'));
console.log(response.statusText); // access the underlying Response object
const { data: numberOrder, response: raw } = await client.numberOrders
.create({ phone_numbers: [{ phone_number: '+15558675309' }] })
.withResponse();
console.log(raw.headers.get('X-My-Header'));
console.log(numberOrder.data);
日志记录
重要
所有日志消息仅用于调试。日志消息的格式和内容 可能会在不同版本之间发生变化。
日志级别
可以通过以下两种方式配置日志级别:
- 通过
TELNYX_LOG环境变量 - 使用客户端选项
logLevel(如果已设置,则会覆盖环境变量)
import Telnyx from 'telnyx';
const client = new Telnyx({
logLevel: 'debug', // Show all log messages
});
可用的日志级别,从最详细到最简略依次为:
'debug'- 显示调试消息、信息、警告和错误'info'- 显示信息、警告和错误'warn'- 显示警告和错误(默认)'error'- 仅显示错误'off'- 禁用所有日志记录
在 'debug' 级别下,会记录所有 HTTP 请求和响应,包括标头和正文。
某些与身份验证相关的标头会被隐藏,但请求和响应正文中的敏感数据
仍可能可见。
自定义日志记录器
默认情况下,此库会将日志记录到 globalThis.console。你也可以提供自定义日志记录器。
我们支持大多数日志记录库,包括 pino、winston、bunyan、consola、signale 和 @std/log。如果你的日志记录器无法正常工作,请提交 issue。
提供自定义日志记录器时,logLevel 选项仍会控制要输出哪些消息,低于所配置级别的消息不会发送到你的日志记录器。
import Telnyx from 'telnyx';
import pino from 'pino';
const logger = pino();
const client = new Telnyx({
logger: logger.child({ name: 'Telnyx' }),
logLevel: 'debug', // Send all messages to pino, allowing it to filter
});
发起自定义/未记录的请求
此库提供类型定义,便于访问已记录的 API。如果你需要访问未记录的端点、参数或响应属性,仍然可以使用此库。
未记录的端点
若要向未记录的端点发起请求,可以使用 client.get、client.post 和其他 HTTP 动词。
发起这些请求时,客户端上的选项(例如重试)仍会生效。
await client.post('/some/path', {
body: { some_prop: 'foo' },
query: { some_query_arg: 'bar' },
});
未记录的请求参数
若要使用未记录的参数发起请求,可以对该参数使用 // @ts-expect-error。此库不会在运行时验证请求是否符合类型定义,因此你发送的任何额外值都会原样发送。
client.calls.dial({
// ...
// @ts-expect-error baz is not yet public
baz: 'undocumented option',
});
对于使用 GET 动词的请求,任何额外参数都会放在查询中;其他所有请求都会将额外参数放在请求正文中。
如果要显式发送额外参数,可以使用请求选项 query、body 和 headers。
未记录的响应属性
若要访问未记录的响应属性,可以对响应对象使用 // @ts-expect-error,也可以将响应对象转换为所需类型。与请求参数一样,我们不会验证或剔除 API 响应中的额外属性。
自定义 fetch 客户端
默认情况下,此库要求定义全局 fetch 函数。
如果要使用其他 fetch 函数,可以为全局函数添加 polyfill:
import fetch from 'my-fetch';
globalThis.fetch = fetch;
或者将其传递给客户端:
import Telnyx from 'telnyx';
import fetch from 'my-fetch';
const client = new Telnyx({ fetch });
Fetch 选项
如果要设置自定义 fetch 选项,但不覆盖 fetch 函数,可以在实例化客户端或发起请求时提供 fetchOptions 对象。(请求专属选项会覆盖客户端选项。)
import Telnyx from 'telnyx';
const client = new Telnyx({
fetchOptions: {
// `RequestInit` options
},
});
配置代理
若要修改代理行为,可以提供自定义 fetchOptions,为请求添加特定于运行时的代理选项:
Node [文档]
import Telnyx from 'telnyx';
import * as undici from 'undici';
const proxyAgent = new undici.ProxyAgent('http://localhost:8888');
const client = new Telnyx({
fetchOptions: {
dispatcher: proxyAgent,
},
});
Bun [文档]
import Telnyx from 'telnyx';
const client = new Telnyx({
fetchOptions: {
proxy: 'http://localhost:8888',
},
});
Deno [文档]
import Telnyx from 'npm:telnyx';
const httpClient = Deno.createHttpClient({ proxy: { url: 'http://localhost:8888' } });
const client = new Telnyx({
fetchOptions: {
client: httpClient,
},
});
常见问题
语义化版本
此软件包通常遵循 SemVer 约定,但某些不向后兼容的更改可能会作为次要版本发布:
- 仅影响静态类型、不破坏运行时行为的更改。
- 对库内部实现的更改:这些实现从技术上说是公开的,但并非面向外部使用或为外部使用提供文档。(如果您依赖此类内部实现,请提交 GitHub issue 告知我们。)
- 我们预计实际上不会影响绝大多数用户的更改。
我们非常重视向后兼容性,并努力确保您能够顺利升级。
我们期待您的反馈;如果您有疑问、发现错误或有建议,请提交 issue。
要求
支持 TypeScript >= 4.9。
支持以下运行时:
- Web 浏览器(最新版 Chrome、Firefox、Safari、Edge 等)
- Node.js 20 LTS 或更高版本(尚未停止维护)。
- Deno v1.28.0 或更高版本。
- Bun 1.0 或更高版本。
- Cloudflare Workers。
- Vercel Edge Runtime。
- Jest 28 或更高版本,使用
"node"环境(目前不支持"jsdom")。 - Nitro v2.6 或更高版本。
请注意,目前不支持 React Native。
如果您对其他运行时环境感兴趣,请在 GitHub 上提交 issue 或为相关 issue 投票。
贡献
请参阅贡献文档。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。