Dodo Payments

Dodo Payments

Dodo Payments MCP 服务器与代理框架集成,为 AI 驱动的支付操作(如账单、订阅和客户管理)提供轻量级、与无服务器兼容的接口。它使自主代理能够使用 Dodo Payments 安全地代表用户执行操作。

Category
访问服务器

README

Dodo Payments Node API 库

NPM version npm bundle size

该库提供了从服务器端 TypeScript 或 JavaScript 方便地访问 Dodo Payments REST API 的能力。

REST API 文档可以在 docs.dodopayments.com 上找到。该库的完整 API 可以在 api.md 中找到。

它由 Stainless 生成。

安装

npm install dodopayments

使用

该库的完整 API 可以在 api.md 中找到。

<!-- prettier-ignore -->

import DodoPayments from 'dodopayments';

const client = new DodoPayments({
  bearerToken: process.env['DODO_PAYMENTS_API_KEY'], // 这是默认值,可以省略
  environment: 'test_mode', // 默认为 'live_mode'
});

async function main() {
  const payment = await client.payments.create({
    billing: { city: 'city', country: 'AF', state: 'state', street: 'street', zipcode: 'zipcode' },
    customer: { customer_id: 'customer_id' },
    product_cart: [{ product_id: 'product_id', quantity: 0 }],
  });

  console.log(payment.payment_id);
}

main();

请求和响应类型

该库包含所有请求参数和响应字段的 TypeScript 定义。您可以像这样导入和使用它们:

<!-- prettier-ignore -->

import DodoPayments from 'dodopayments';

const client = new DodoPayments({
  bearerToken: process.env['DODO_PAYMENTS_API_KEY'], // 这是默认值,可以省略
  environment: 'test_mode', // 默认为 'live_mode'
});

async function main() {
  const params: DodoPayments.PaymentCreateParams = {
    billing: { city: 'city', country: 'AF', state: 'state', street: 'street', zipcode: 'zipcode' },
    customer: { customer_id: 'customer_id' },
    product_cart: [{ product_id: 'product_id', quantity: 0 }],
  };
  const payment: DodoPayments.PaymentCreateResponse = await client.payments.create(params);
}

main();

每个方法、请求参数和响应字段的文档都可以在文档字符串中找到,并且会在大多数现代编辑器中悬停时显示。

处理错误

当库无法连接到 API,或者 API 返回非成功状态代码(即 4xx 或 5xx 响应)时,将抛出 APIError 的子类:

<!-- prettier-ignore -->

async function main() {
  const payment = await client.payments
    .create({
      billing: { city: 'city', country: 'AF', state: 'state', street: 'street', zipcode: 'zipcode' },
      customer: { customer_id: 'customer_id' },
      product_cart: [{ product_id: 'product_id', quantity: 0 }],
    })
    .catch(async (err) => {
      if (err instanceof DodoPayments.APIError) {
        console.log(err.status); // 400
        console.log(err.name); // BadRequestError
        console.log(err.headers); // {server: 'nginx', ...}
      } else {
        throw err;
      }
    });
}

main();

错误代码如下:

状态码 错误类型
400 BadRequestError
401 AuthenticationError
403 PermissionDeniedError
404 NotFoundError
422 UnprocessableEntityError
429 RateLimitError
>=500 InternalServerError
N/A APIConnectionError

重试

默认情况下,某些错误将自动重试 2 次,并具有短暂的指数退避。 连接错误(例如,由于网络连接问题)、408 请求超时、409 冲突、429 速率限制和 >=500 内部错误都将默认重试。

您可以使用 maxRetries 选项来配置或禁用此功能:

<!-- prettier-ignore -->

// 配置所有请求的默认值:
const client = new DodoPayments({
  maxRetries: 0, // 默认为 2
});

// 或者,配置每个请求:
await client.payments.create({ billing: { city: 'city', country: 'AF', state: 'state', street: 'street', zipcode: 'zipcode' }, customer: { customer_id: 'customer_id' }, product_cart: [{ product_id: 'product_id', quantity: 0 }] }, {
  maxRetries: 5,
});

超时

默认情况下,请求在 1 分钟后超时。您可以使用 timeout 选项配置此值:

<!-- prettier-ignore -->

// 配置所有请求的默认值:
const client = new DodoPayments({
  timeout: 20 * 1000, // 20 秒(默认为 1 分钟)
});

// 覆盖每个请求:
await client.payments.create({ billing: { city: 'city', country: 'AF', state: 'state', street: 'street', zipcode: 'zipcode' }, customer: { customer_id: 'customer_id' }, product_cart: [{ product_id: 'product_id', quantity: 0 }] }, {
  timeout: 5 * 1000,
});

超时时,将抛出 APIConnectionTimeoutError

请注意,超时的请求将默认重试两次

自动分页

Dodo Payments API 中的列表方法是分页的。您可以使用 for await … of 语法来迭代所有页面中的项目:

async function fetchAllPayments(params) {
  const allPayments = [];
  // 根据需要自动获取更多页面。
  for await (const paymentListResponse of client.payments.list()) {
    allPayments.push(paymentListResponse);
  }
  return allPayments;
}

或者,您可以一次请求一个页面:

let page = await client.payments.list();
for (const paymentListResponse of page.items) {
  console.log(paymentListResponse);
}

// 提供了方便的方法来手动分页:
while (page.hasNextPage()) {
  page = await page.getNextPage();
  // ...
}

高级用法

访问原始响应数据(例如,标头)

可以通过所有方法返回的 APIPromise 类型上的 .asResponse() 方法访问 fetch() 返回的“原始” Response

您还可以使用 .withResponse() 方法来获取原始 Response 以及已解析的数据。

<!-- prettier-ignore -->

const client = new DodoPayments();

const response = await client.payments
  .create({
    billing: { city: 'city', country: 'AF', state: 'state', street: 'street', zipcode: 'zipcode' },
    customer: { customer_id: 'customer_id' },
    product_cart: [{ product_id: 'product_id', quantity: 0 }],
  })
  .asResponse();
console.log(response.headers.get('X-My-Header'));
console.log(response.statusText); // 访问底层 Response 对象

const { data: payment, response: raw } = await client.payments
  .create({
    billing: { city: 'city', country: 'AF', state: 'state', street: 'street', zipcode: 'zipcode' },
    customer: { customer_id: 'customer_id' },
    product_cart: [{ product_id: 'product_id', quantity: 0 }],
  })
  .withResponse();
console.log(raw.headers.get('X-My-Header'));
console.log(payment.payment_id);

发出自定义/未记录的请求

此库经过类型化,可以方便地访问已记录的 API。如果您需要访问未记录的端点、参数或响应属性,仍然可以使用该库。

未记录的端点

要向未记录的端点发出请求,您可以使用 client.getclient.post 和其他 HTTP 动词。在发出这些请求时,将遵守客户端上的选项,例如重试。

await client.post('/some/path', {
  body: { some_prop: 'foo' },
  query: { some_query_arg: 'bar' },
});

未记录的请求参数

要使用未记录的参数发出请求,您可以在未记录的参数上使用 // @ts-expect-error。此库不会在运行时验证请求是否与类型匹配,因此您发送的任何额外值都将按原样发送。

client.foo.create({
  foo: 'my_param',
  bar: 12,
  // @ts-expect-error baz 尚未公开
  baz: 'undocumented option',
});

对于带有 GET 动词的请求,任何额外的参数都将在查询中,所有其他请求都将在正文中发送额外的参数。

如果您想显式发送一个额外的参数,您可以使用 querybodyheaders 请求选项来完成。

未记录的响应属性

要访问未记录的响应属性,您可以在响应对象上使用 // @ts-expect-error 来访问响应对象,或者将响应对象强制转换为所需的类型。与请求参数一样,我们不会验证或从 API 响应中删除额外的属性。

自定义 fetch 客户端

默认情况下,此库在 Node 中使用 node-fetch,并期望在其他环境中有一个全局 fetch 函数。

如果您希望即使在 Node 环境中使用符合 Web 标准的全局 fetch 函数,(例如,如果您正在使用 --experimental-fetch 运行 Node 或使用 NextJS,它使用 undici 进行 polyfill),请在第一次 from "DodoPayments" 导入之前添加以下导入:

// 告诉 TypeScript 和包使用全局 web fetch 而不是 node-fetch。
// 请注意,尽管名称如此,但这不会添加任何 polyfill,而是期望在需要时提供它们。
import 'dodopayments/shims/web';
import DodoPayments from 'dodopayments';

要执行相反的操作,请添加 import "dodopayments/shims/node"(它确实导入了 polyfill)。如果您为 Response 获取了错误的 TypeScript 类型,这也可能很有用(更多详细信息)。

日志记录和中间件

您还可以在实例化客户端时提供自定义 fetch 函数,该函数可用于在每次请求之前/之后检查或更改 RequestResponse

import { fetch } from 'undici'; // 作为一个例子
import DodoPayments from 'dodopayments';

const client = new DodoPayments({
  fetch: async (url: RequestInfo, init?: RequestInit): Promise<Response> => {
    console.log('即将发出请求', url, init);
    const response = await fetch(url, init);
    console.log('收到响应', response);
    return response;
  },
});

请注意,如果给定 DEBUG=true 环境变量,此库将自动记录所有请求和响应。这仅用于调试目的,并且将来可能会更改,恕不另行通知。

配置 HTTP(S) 代理(例如,用于代理)

默认情况下,此库对所有 http/https 请求使用稳定的代理来重用 TCP 连接,从而消除许多 TCP 和 TLS 握手,并将大多数请求的时间缩短约 100 毫秒。

如果您想禁用或自定义此行为,例如在代理后面使用 API,您可以传递一个 httpAgent,该代理用于所有请求(无论是 http 还是 https),例如:

<!-- prettier-ignore -->

import http from 'http';
import { HttpsProxyAgent } from 'https-proxy-agent';

// 配置所有请求的默认值:
const client = new DodoPayments({
  httpAgent: new HttpsProxyAgent(process.env.PROXY_URL),
});

// 覆盖每个请求:
await client.payments.create(
  {
    billing: { city: 'city', country: 'AF', state: 'state', street: 'street', zipcode: 'zipcode' },
    customer: { customer_id: 'customer_id' },
    product_cart: [{ product_id: 'product_id', quantity: 0 }],
  },
  {
    httpAgent: new http.Agent({ keepAlive: false }),
  },
);

语义化版本控制

此包通常遵循 SemVer 约定,但某些向后不兼容的更改可能会作为次要版本发布:

  1. 仅影响静态类型,而不破坏运行时行为的更改。
  2. 对库内部结构的更改,这些更改在技术上是公开的,但并非旨在或记录用于外部使用。(如果您依赖于此类内部结构,请打开一个 GitHub 问题告知我们。)
  3. 我们预计不会影响绝大多数用户的更改。

我们认真对待向后兼容性,并努力确保您可以依赖平稳的升级体验。

我们渴望您的反馈;请打开一个 issue 提出问题、错误或建议。

要求

支持 TypeScript >= 4.5。

支持以下运行时:

  • Web 浏览器(最新的 Chrome、Firefox、Safari、Edge 等)
  • Node.js 18 LTS 或更高版本(非 EOL)版本。
  • Deno v1.28.0 或更高版本。
  • Bun 1.0 或更高版本。
  • Cloudflare Workers。
  • Vercel Edge Runtime。
  • Jest 28 或更高版本,带有 "node" 环境(目前不支持 "jsdom")。
  • Nitro v2.6 或更高版本。

请注意,目前不支持 React Native。

如果您对其他运行时环境感兴趣,请在 GitHub 上打开或支持一个 issue。

贡献

请参阅 贡献文档

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选