Skip to main content
The AnySpend Platform SDK client is a headless (no React dependency) TypeScript client for the full AnySpend Platform API. It works everywhere modern JavaScript runs — Node.js, browsers, Cloudflare Workers, Deno, and Bun.

Installation

npm install @b3dotfun/sdk

Quick Start

import { AnySpendPlatformClient } from "@b3dotfun/sdk/anyspend/platform";

const platform = new AnySpendPlatformClient(process.env.ANYSPEND_API_KEY!);

// Create a payment link
const link = await platform.paymentLinks.create({
  name: "Pro Plan - Monthly",
  amount: "29990000",  // 29.99 USDC
  recipient_address: "0xYourAddress",
});

console.log(link.url);

Initialization

import { AnySpendPlatformClient } from "@b3dotfun/sdk/anyspend/platform";

const platform = new AnySpendPlatformClient(process.env.ANYSPEND_API_KEY!, {
  // All options below are optional
  baseUrl: "https://platform-api.anyspend.com/api/v1", // default
  timeout: 30_000,           // request timeout in ms (default: 30s)
  maxRetries: 3,             // auto-retry count for 5xx / network errors
  idempotencyKeyGenerator: () => crypto.randomUUID(), // custom generator
});
You can obtain an API key from the AnySpend Dashboard under Settings > API Keys. Keys are scoped to your organization and can have read-only or read-write permissions.

Available Resources

The client is organized into resource namespaces, each with methods that map directly to REST endpoints.
platform.products.create(data)
platform.products.list(params?)
platform.products.get(id)
platform.products.update(id, data)
platform.products.delete(id)
platform.products.generateLink(id, linkOptions?)
platform.customers.create(data)
platform.customers.list(params?)
platform.customers.get(id)
platform.customers.update(id, data)
platform.customers.delete(id)
platform.customers.transactions(id, params?)
platform.customers.export(params?)
platform.transactions.list(params?)
platform.transactions.get(id)
platform.transactions.stats(params?)
platform.transactions.export(params?)
platform.checkoutSessions.create(data)
platform.checkoutSessions.list(params?)
platform.checkoutSessions.get(id)
platform.checkoutSessions.expire(id)
platform.webhooks.create(data)
platform.webhooks.list(params?)
platform.webhooks.get(id)
platform.webhooks.update(id, data)
platform.webhooks.delete(id)
platform.webhooks.test(id)
platform.webhooks.deliveries(id, params?)
platform.webhooks.retry(id, deliveryId)
platform.discountCodes.create(data)
platform.discountCodes.list(params?)
platform.discountCodes.update(id, data)
platform.discountCodes.delete(id)
platform.discountCodes.validate(code, context?)
platform.discountCodes.batchCreate(codes)
platform.notifications.get()
platform.notifications.update(data)
platform.notifications.linkTelegram(chatId)
platform.notifications.unlinkTelegram()
platform.notifications.testEmail()
platform.notifications.testTelegram()
platform.widgets.create(data)
platform.widgets.list(params?)
platform.widgets.get(id)
platform.widgets.update(id, data)
platform.widgets.delete(id)
platform.widgets.stats(id)
platform.organization.get()
platform.organization.update(data)
platform.analytics.overview(params?)
platform.events.list(params?)

Pagination

All list methods accept optional pagination parameters and return a paginated response:
const page = await platform.transactions.list({
  status: "completed",
  limit: 25,
  cursor: "cur_abc123",
});

console.log(page.data);       // Transaction[]
console.log(page.has_more);   // boolean
console.log(page.next_cursor); // string | null

Auto-Pagination

For convenience, every list method has a corresponding listAutoPaginate helper that returns an async iterator. It fetches pages behind the scenes as you consume items.
for await (const txn of platform.transactions.listAutoPaginate({
  status: "completed",
})) {
  console.log(txn.id, txn.amount);
}
Auto-pagination respects rate limits automatically. If the API returns a 429, the iterator waits for the Retry-After duration before fetching the next page.
You can also collect all results into an array:
const allCustomers = [];
for await (const c of platform.customers.listAutoPaginate()) {
  allCustomers.push(c);
}

Error Handling

The SDK throws typed error classes so you can handle specific failure modes:
import {
  ApiError,
  AuthenticationError,
  PermissionError,
  RateLimitError,
  NotFoundError,
  IdempotencyError,
} from "@b3dotfun/sdk/anyspend/platform";

try {
  const link = await platform.paymentLinks.get("pl_nonexistent");
} catch (err) {
  if (err instanceof NotFoundError) {
    console.log("Link does not exist");
  } else if (err instanceof AuthenticationError) {
    console.log("Invalid or expired API key");
  } else if (err instanceof PermissionError) {
    console.log("API key lacks required permission");
  } else if (err instanceof RateLimitError) {
    console.log(`Rate limited. Retry after ${err.retryAfter} seconds`);
  } else if (err instanceof IdempotencyError) {
    console.log("Idempotency conflict -- request was already processed with different parameters");
  } else if (err instanceof ApiError) {
    // Catch-all for any API error
    console.log(err.status, err.code, err.message);
  }
}

Error Class Reference

ClassHTTP StatusDescription
AuthenticationError401Missing, invalid, or expired API key
PermissionError403API key does not have the required scope
NotFoundError404Resource does not exist
RateLimitError429Too many requests. Includes retryAfter (seconds)
IdempotencyError409Idempotency key was reused with different parameters
ApiErroranyBase class for all API errors

Auto-Retry

The client automatically retries failed requests in the following cases:
  • 5xx server errors — the server had a transient failure
  • Network errors — connection reset, DNS failure, timeout
  • 429 rate limit responses — waits for the Retry-After duration
Retries use exponential backoff with jitter. The default is 3 retries, configurable via the maxRetries option.
const platform = new AnySpendPlatformClient("asp_key", {
  maxRetries: 5, // up to 5 retries
});
Retries are not performed for 4xx errors other than 429, since those indicate a client-side issue that will not resolve by retrying.

Idempotency

All POST and PATCH requests automatically include an Idempotency-Key header. This ensures that if a request is retried (due to a network error, for example), the server will not process it twice. The default generator uses crypto.randomUUID(). You can supply your own:
const platform = new AnySpendPlatformClient("asp_key", {
  idempotencyKeyGenerator: () => `my-app-${Date.now()}-${Math.random()}`,
});
You can also pass a specific idempotency key per-request:
const link = await platform.paymentLinks.create(
  { name: "Order #1234", amount: "50000000", recipient_address: "0x..." },
  { idempotencyKey: "order-1234-link" }
);
Using a deterministic idempotency key (like an order ID) is recommended for critical operations. If you accidentally send the same request twice, the second call returns the original response instead of creating a duplicate.

TypeScript Types

All request and response types are exported for use in your own code:
import type {
  PaymentLink,
  CreatePaymentLinkRequest,
  Transaction,
  Customer,
  CheckoutSession,
  Webhook,
  PaginatedResponse,
} from "@b3dotfun/sdk/anyspend/platform";

Runtime Compatibility

RuntimeSupported
Node.js 18+Yes
Browsers (ES2020+)Yes
Cloudflare WorkersYes
DenoYes
BunYes
The client uses the standard fetch API internally. In Node.js 18+, the built-in fetch is used. No polyfills are required.