JSPM

  • Created
  • Published
  • Downloads 80
  • Score
    100M100P100Q33894F
  • License Apache-2.0

Official TypeScript SDK for the ListBee API — one API call to sell and deliver digital content.

Package Exports

  • listbee

Readme

listbee

Official TypeScript SDK for the ListBee API — one API call to sell and deliver digital content.

  • Zero runtime dependencies (native fetch, Node >= 18)
  • Types generated from OpenAPI spec — zero drift
  • Full error hierarchy (RFC 9457)
  • Cursor-based pagination
  • Retry with exponential backoff
  • Idempotency support

Install

npm install listbee
pnpm add listbee

Quick start

import { ListBee } from 'listbee';

const client = new ListBee({ apiKey: 'lb_...' });

// Create a listing, set a deliverable, publish
const listing = await client.listings.create({
  name: 'SEO Playbook',
  price: 2900, // $29.00 in cents
  description: 'A comprehensive guide to modern SEO.',
});

await client.listings.setDeliverables(listing.id, {
  url: 'https://example.com/seo-playbook.pdf',
});

const published = await client.listings.publish(listing.id);
console.log(published.url); // https://buy.listbee.so/r7kq2xy9

Or read from the environment:

export LISTBEE_API_KEY="lb_..."
const client = new ListBee(); // reads LISTBEE_API_KEY automatically

Authentication

Pass your API key explicitly or via the LISTBEE_API_KEY environment variable.

const client = new ListBee({ apiKey: 'lb_...' });
const client = new ListBee(); // env var

The key is validated lazily — an AuthenticationError is raised only when you make the first API call. API keys start with lb_. Get yours at listbee.so.

Resources

Resource Methods
listings create, get, list, update, publish, setDeliverables, removeDeliverables, delete
orders get, list, deliver, refund
customers get, list
files upload
webhooks create, get, list, update, delete, listEvents, retryEvent, test, verify
account get, update, delete
apiKeys list, create, delete
signup create, verify
stripe connect, disconnect

Listings

// Create
const listing = await client.listings.create({
  name: 'SEO Playbook 2026',
  price: 2900,
  description: 'A comprehensive guide to modern SEO techniques.',
  tagline: 'Updated for 2026 algorithm changes',
  highlights: ['50+ pages', 'Actionable tips', 'Free updates'],
  cta: 'Get Instant Access',
  cover_url: 'https://example.com/cover.png',
  compare_at_price: 3900,
  metadata: { source: 'n8n', campaign: 'launch-week' },
});
console.log(listing.id); // lst_r7kq2xy9m3pR5tW1

// Set deliverables (file, URL, or text)
await client.listings.setDeliverables(listing.id, {
  url: 'https://example.com/seo-playbook.pdf',
});

// Publish
const published = await client.listings.publish(listing.id);
console.log(published.url); // https://buy.listbee.so/r7kq2xy9

// Get by ID
const listing = await client.listings.get('lst_r7kq2xy9m3pR5tW1');

// List — with filters
const page = await client.listings.list({
  status: 'published',
  limit: 20,
});
for (const l of page.data) {
  console.log(l.id, l.name, l.status);
}
console.log(page.total_count); // total matching listings

// Update
await client.listings.update('lst_r7kq2xy9m3pR5tW1', { price: 3900 });

// Remove deliverables (revert to external fulfillment)
await client.listings.removeDeliverables('lst_r7kq2xy9m3pR5tW1');

// Delete
await client.listings.delete('lst_r7kq2xy9m3pR5tW1');

Orders

// List — with filters
const page = await client.orders.list({
  status: 'paid',
  buyer_email: 'buyer@example.com',
  created_after: new Date('2026-03-01'),
  created_before: '2026-03-31T23:59:59Z',
});
console.log(page.total_count);

// Get by ID
const order = await client.orders.get('ord_9xM4kP7nR2qT5wY1');
console.log(order.status);       // "pending" | "paid" | "fulfilled" | "canceled" | "failed"
console.log(order.checkout_data); // custom checkout field values
console.log(order.paid_at);       // ISO 8601 timestamp

// Deliver — push content to the buyer (external fulfillment)
const fulfilled = await client.orders.deliver('ord_9xM4kP7nR2qT5wY1', {
  content: 'Your AI-generated report is ready.',
  content_type: 'text',
});
console.log(fulfilled.status); // "fulfilled"

// Or with a URL
await client.orders.deliver('ord_9xM4kP7nR2qT5wY1', {
  content_url: 'https://example.com/report.pdf',
});

// Refund
const refunded = await client.orders.refund('ord_9xM4kP7nR2qT5wY1');
console.log(refunded.status); // "canceled"

Customers

// List customers
const page = await client.customers.list({ limit: 20, email: 'buyer@example.com' });
for (const c of page.data) {
  console.log(c.id, c.email);
}

// Get a customer
const customer = await client.customers.get('cus_7kQ2xY9mN3pR5tW1');
console.log(customer.email, customer.order_count);

Files

import { createReadStream } from 'fs';

// Upload a file (multipart, native FormData)
const file = await client.files.upload({
  file: createReadStream('/path/to/report.pdf'),
  filename: 'report.pdf',
});
console.log(file.id);  // use this ID in setDeliverables

// Then attach to a listing
await client.listings.setDeliverables(listing.id, { file_id: file.id });

Webhooks

import { ListBee, WebhookEventType } from 'listbee';

const client = new ListBee({ apiKey: 'lb_...' });

// Create — subscribe to specific events
const webhook = await client.webhooks.create({
  name: 'Production endpoint',
  url: 'https://example.com/webhooks/listbee',
  events: [
    WebhookEventType.ORDER_PAID,
    WebhookEventType.ORDER_FULFILLED,
    WebhookEventType.CUSTOMER_CREATED,
  ],
});
console.log(webhook.id);     // wh_3mK8nP2qR5tW7xY1
console.log(webhook.secret); // HMAC signing key — save this

// Verify an incoming webhook (HMAC-SHA256, uses crypto.subtle — no dependencies)
const isValid = await client.webhooks.verify({
  payload: rawBodyString,
  signature: req.headers['listbee-signature'],
  secret: webhook.secret,
});

// List delivery events
const events = await client.webhooks.listEvents('wh_3mK8nP2qR5tW7xY1', { status: 'failed' });

// Retry a failed event
await client.webhooks.retryEvent('wh_3mK8nP2qR5tW7xY1', 'evt_abc123');

// Update, test, delete
await client.webhooks.update('wh_3mK8nP2qR5tW7xY1', { enabled: false });
await client.webhooks.test('wh_3mK8nP2qR5tW7xY1');
await client.webhooks.delete('wh_3mK8nP2qR5tW7xY1');

Account

const account = await client.account.get();
console.log(account.id);    // acc_7kQ2xY9mN3pR5tW1
console.log(account.email);
console.log(account.plan);  // free | growth | scale
console.log(account.readiness.operational);

await client.account.update({ ga_measurement_id: 'G-XXXXXXXXXX' });
await client.account.delete();

Signup

Agent self-service onboarding — no API key required:

const client = new ListBee(); // no API key needed

await client.signup.create({ email: 'seller@example.com' });

const result = await client.signup.verify({ email: 'seller@example.com', code: '123456' });
console.log(result.api_key); // lb_... (one-time display)

API keys

const keys = await client.apiKeys.list();

const newKey = await client.apiKeys.create({ name: 'CI pipeline' });
console.log(newKey.key); // lb_... (save this immediately)

await client.apiKeys.delete('lbk_7kQ2xY9mN3pR5tW1');

Stripe

// Generate a Stripe Connect onboarding link
const connect = await client.stripe.connect();
console.log(connect.url); // redirect seller here

// Disconnect Stripe
await client.stripe.disconnect();

Fulfillment modes

  • Managed — ListBee delivers digital content automatically. Call setDeliverables() on the listing, then publish().
  • External — ListBee fires order.paid webhook, your app handles delivery. Call orders.deliver() to push content back.
// External fulfillment — AI-generated content
const listing = await client.listings.create({
  name: 'Custom SEO Report',
  price: 4900,
  fulfillment: 'external',
  checkout_schema: [
    { type: 'text', key: 'website_url', label: 'Your website URL', required: true },
  ],
});
await client.listings.publish(listing.id);

// On order.paid webhook:
await client.orders.deliver(order.id, {
  content: generatedReport,
  content_type: 'text',
});

Readiness system

Every listing and account includes a readiness field.

const account = await client.account.get();
if (!account.readiness.operational) {
  for (const action of account.readiness.actions) {
    if (action.kind === 'api') {
      console.log(`API action: ${action.code} -> ${action.resolve.endpoint}`);
    } else {
      console.log(`Manual step: ${action.code} -> ${action.resolve.url}`);
    }
  }
}

Idempotency

Pass idempotencyKey to any mutating request. Same key within 24h returns the cached response:

await client.listings.create(
  { name: 'SEO Playbook', price: 2900 },
  { idempotencyKey: 'create-listing-campaign-2026' },
);

Pagination

const page = await client.listings.list({ limit: 10 });
console.log(page.data);        // ListingResponse[]
console.log(page.has_more);    // true if more pages exist
console.log(page.cursor);      // pass to next call
console.log(page.total_count); // total matching items

if (page.has_more) {
  const nextPage = await client.listings.list({ limit: 10, cursor: page.cursor });
}

Error handling

ListBeeError
├── APIConnectionError      network error — request never reached the server
├── APITimeoutError         request timed out
└── APIStatusError          server returned 4xx/5xx
    ├── BadRequestError          400
    ├── AuthenticationError      401
    ├── ForbiddenError           403
    ├── NotFoundError            404
    ├── ConflictError            409
    ├── PayloadTooLargeError     413
    ├── ValidationError          422
    ├── RateLimitError           429
    └── InternalServerError      500+
import { NotFoundError, AuthenticationError, RateLimitError, ErrorCode } from 'listbee';

try {
  await client.listings.get('lst_does-not-exist');
} catch (e) {
  if (e instanceof NotFoundError) {
    console.log(e.status); // 404
    console.log(e.code);   // ErrorCode value
    console.log(e.detail); // human-readable explanation
  } else if (e instanceof RateLimitError) {
    console.log(`Rate limited. Resets at ${e.reset}`);
  }
}

All APIStatusError subclasses expose: status, code (ErrorCode), detail, title, type, param.

Configuration

const client = new ListBee({
  apiKey: 'lb_...',
  timeoutMs: 60_000,   // default: 30000
  maxRetries: 5,        // default: 3; retries on 429/500/502/503/504
  baseUrl: 'https://api.listbee.so', // override for testing
});

Types

All types are importable from listbee:

import {
  ListBee,
  CursorPage,
  ErrorCode,

  // Response types
  type ListingResponse,
  type OrderResponse,
  type CustomerResponse,
  type FileResponse,
  type WebhookResponse,
  type AccountResponse,
  type ApiKeyResponse,
  type SignupResponse,
  type VerifyResponse,
  type WebhookEventResponse,
  type WebhookTestResponse,
  type CheckoutField,

  // Enums
  DeliverableType,   // "file" | "url" | "text"
  FulfillmentMode,   // "managed" | "external"
  ListingStatus,     // "draft" | "published"
  OrderStatus,       // "pending" | "paid" | "fulfilled" | "canceled" | "failed"
  WebhookEventType,
  ActionCode,
  ActionKind,

  // Errors
  ListBeeError,
  APIStatusError,
  APIConnectionError,
  APITimeoutError,
  BadRequestError,
  AuthenticationError,
  ForbiddenError,
  NotFoundError,
  ConflictError,
  PayloadTooLargeError,
  ValidationError,
  RateLimitError,
  InternalServerError,
} from 'listbee';

Requirements

  • Node.js >= 18

License

Apache-2.0. See LICENSE.