@alguna/sdk

中文文档
0.4.0发布于 2026/10/19Apache-2.0TypeScriptESM + CJS零依赖构建来源已验证近 30 天下载 1.9万

Official TypeScript SDK for the Alguna Public API

原始使用文档
文档目录10 节
  1. Install
  2. Client
  3. Requests
  4. Pagination
  5. Idempotency and retries
  6. Timeouts
  7. Errors
  8. Webhooks
  9. Reference
  10. About this repo

@alguna/sdk

The official TypeScript SDK for the Alguna API: usage-based billing, subscriptions, invoicing and payments. Upgrading from 0.3? Read MIGRATING.md.

Install

npm install @alguna/sdk

The SDK needs Node.js 20 or later, or another runtime with a global fetch and crypto.randomUUID(), such as Deno, Bun or Cloudflare Workers. Use it on a server only: the API key is a secret.

Client

Create an API key in the dashboard under Settings → Connections → Developers → API keys. A key looks like <key_id>.<key_secret>.

import { Alguna } from "@alguna/sdk";

// With no options, the client reads the key from ALGUNA_API_KEY.
const alguna = new Alguna();

const sandbox = new Alguna({
  apiKey: process.env.ALGUNA_SANDBOX_API_KEY, // a string, or a function called on every request
  apiVersion: "2026-04-01", // default: the version this SDK release targets
  baseUrl: "https://api.sandbox.alguna.io", // default: https://api.alguna.io
  headers: { "X-Trace-Id": "abc" }, // sent on every request
  fetch: globalThis.fetch, // your own fetch, for example to add tracing
  logging: { level: "debug", silent: false }, // silent by default
});

new Alguna() throws an AlgunaError when it finds no key: where there is no process.env (Workers, Deno), pass apiKey. Pin apiVersion to keep your integration on one API version when you upgrade the package. The SDK sends User-Agent: alguna-ts/<version> where the runtime allows it (not in browsers); a User-Agent in headers replaces it. console.log(alguna) and JSON.stringify(alguna) never print the API key.

Requests

The client has one field per API resource (alguna.customers, alguna.subscriptions, alguna.invoices, alguna.wallets, …) and one method per operation. The request and response types are exported from the package root (CreateCustomerRequest, InvoiceResponse) and under the AlgunaApi namespace.

import { Alguna } from "@alguna/sdk";

const alguna = new Alguna();

const customer = await alguna.customers.create({
  name: "Acme Corp",
  currency: "USD",
  contacts: [{ email: "[email protected]", is_primary: true }],
});

const invoice = await alguna.invoices.create({
  customer_id: customer.id,
  currency: "USD",
  line_items: [{ description: "Onboarding", unit_price: "500.00", quantity: "1" }],
});

// A hosted customer portal session, where the customer can pay. It is valid for 1 hour.
const session = await alguna.portal.createSession({ customer_id: customer.id });
console.log(invoice.id, session.url);

Every method takes per-request options as its last argument: idempotencyKey (writes), timeoutInSeconds, maxRetries, headers and abortSignal. invoices.generatePdf, quotes.getPdf and subscriptions.downloadPdf return a BinaryResponse: read it with arrayBuffer(), blob() or stream().

For an endpoint the SDK does not cover yet, alguna.fetch(path, init, options) sends a raw request with the client's auth, headers, timeout, Idempotency-Key and retries. It returns the plain Response, whatever its status. When you pass init, the method, headers and body come from init only, not from a Request you pass as path. A stream body, such as the body of a Request, is read into memory before the first attempt, so that a retry can send it again.

Pagination

A list method returns a Page: data holds the items of the current page, and response the full body, with pagination.

import { Alguna } from "@alguna/sdk";

const alguna = new Alguna();

const page = await alguna.customers.list({ limit: 50 });
console.log(page.data.length, page.response.pagination); // { per_page, total_pages }

// The SDK gets the next page when you need it.
for await (const customer of await alguna.customers.list({ limit: 100 })) {
  console.log(customer.id);
}

The API sends at most the operation's limit maximum per page (100 for every list today). Iteration stops at the first page with fewer items than limit, or than that maximum when limit is larger. When the last page is exactly full, the SDK makes one more request, which returns an empty page. To page by hand, use page.hasNextPage() and page.getNextPage().

Idempotency and retries

Every request that is not a GET sends an Idempotency-Key: your idempotencyKey, or a UUID v4 that the SDK makes for the call. Every retry of the call sends the same key, so the API returns the first result and does not do the write again. Pass your own key when you repeat a call yourself, for example after a restart:

import { Alguna } from "@alguna/sdk";

const alguna = new Alguna();

await alguna.customers.create(
  { name: "Acme Corp", currency: "USD" },
  { idempotencyKey: "signup-1234" },
);

The exceptions are events.ingest, credits.track and credits.check: they get no automatic key, because the API identifies their work by the request body. It removes duplicate events by unique_id, and credits.track draws credit once for the same unique_ids. A new key on each call would replace that identity on credits.track, so a call sent again, for example by a queue, would draw credit twice. The SDK retries these calls without a key. A key that you pass is sent on every attempt. credits.check with reserve needs your key, because the key identifies the hold.

A failed attempt is retried 2 times by default (3 attempts in total) when:

  • the status is 408, 429, 502, 503 or 504;
  • the status is 409 with a Retry-After header. The API sends this only while a request with the same key is still running. A 409 without Retry-After is a real conflict and is not retried;
  • no response arrived: the connection was refused, reset or closed, or the attempt timed out. Workers, Deno and browsers do not say why a connection failed, so there a TLS error is retried too. This is safe: every retried request is a GET, carries an Idempotency-Key, or is one of the exceptions above.

The SDK does not retry after you abort a call through abortSignal. Between attempts it waits 1 s, then 2 s, with random jitter of 10%. When the response has Retry-After (seconds or an HTTP date), it waits that long instead, at most 60 s. Set maxRetries on the client or on one call; 0 turns retries off.

Timeouts

Each attempt times out after 60 s. Set timeout (in milliseconds) on the client, or timeoutInSeconds on one call. A timed-out attempt is retried, so one call can take 3 × the timeout plus the waits. To limit the whole call, pass an abortSignal: when it aborts, the SDK throws AbortError.

import { Alguna } from "@alguna/sdk";

const alguna = new Alguna({ timeout: 10_000 });

// Each attempt may take 5 s; the call, with its retries, at most 20 s.
const customer = await alguna.customers.get("cus_123", {
  timeoutInSeconds: 5,
  abortSignal: AbortSignal.timeout(20_000),
});
console.log(customer.name);

Errors

Every error that the SDK throws extends AlgunaError:

import { Alguna, AlgunaError, NotFoundError, RateLimitError } from "@alguna/sdk";

const alguna = new Alguna();

try {
  await alguna.customers.get("nope");
} catch (error) {
  if (error instanceof NotFoundError) {
    console.log(error.message, error.statusCode, error.requestId);
  } else if (error instanceof RateLimitError) {
    console.log("retry in", error.headers["retry-after"], "seconds");
  } else if (error instanceof AlgunaError) {
    console.log(error.cause); // the underlying error, when there is one
  } else {
    throw error;
  }
}
ErrorWhen
ValidationError400
AuthenticationError401
PermissionDeniedError403
NotFoundError404
ConflictError409
UnprocessableEntityError422 (also a ValidationError)
RateLimitError429
InternalServerError5xx
ApiErrorany other unsuccessful status
ConnectionErrorno response: DNS, TLS, reset connection
TimeoutErrortimeout exceeded (also a ConnectionError)
AbortErroryou aborted through abortSignal

An error from a response has message, statusCode, requestId, code (when the body has one), body and headers (lower-cased). message is the body's detail, else its title, else its message, else the HTTP status text. A connection failure has no statusCode; its cause holds the original error. Give the requestId when you contact support.

Webhooks

AlgunaWebhookEvent is a union of every webhook body. Narrow on type to get a typed data:

import type { AlgunaWebhookEvent } from "@alguna/sdk";

function handle(event: AlgunaWebhookEvent) {
  switch (event.type) {
    case "payment.created":
      console.log(event.data.amount); // a decimal string
      break;
    default:
      break; // new event types can arrive before you upgrade
  }
}

The SDK types a payload; it does not check that Alguna sent it. Alguna signs every delivery with Svix. Before you trust a payload, verify its svix-id, svix-timestamp and svix-signature headers against the raw request body with the Svix library: new Webhook(secret).verify(rawBody, headers). See Verifying signatures.

Reference

About this repo

Alguna generates this SDK from the Alguna API spec in a private repository. Open issues here. Alguna ports code changes to the generator, so a pull request here is not merged as is.

版本与发布记录

@alguna/sdk 共发布 4 个版本,首次发布于 2026/08/11;过去 12 个月发布了 4 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.4.0latest2026/10/1919 天前
0.3.02026/09/161 个月前
0.2.02026/09/012 个月前
0.1.02026/08/112 个月前

关于 @alguna/sdk 的常见问题

@alguna/sdk 是什么?

Official TypeScript SDK for the Alguna Public API

如何安装 @alguna/sdk?

在项目目录运行 npm install @alguna/sdk,或使用 pnpm add / yarn add / bun add。

@alguna/sdk 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@alguna/sdk 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@alguna/sdk 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@alguna/sdk 可以商用吗?

@alguna/sdk 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@alguna/sdk 的下载量有多少?

根据 npm 官方下载统计,@alguna/sdk 在 2026/10/06 – 2026/11/04 这 30 天内被下载 19,262 次,日均约 642 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@alguna/sdk 还在维护吗?

最新版本 0.4.0 发布于 2026/10/19(19 天前);至今共发布 4 个版本,其中过去 12 个月发布了 4 个;首次发布于 2026/08/11。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。