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 listbeepnpm add listbeeQuick start
import { ListBee, Deliverable, CheckoutField } from 'listbee';
const client = new ListBee({ apiKey: 'lb_...' });
// Create a listing, attach a deliverable, and publish in one call
const listing = await client.listings.createComplete({
name: 'SEO Playbook',
price: 2900, // $29.00 in cents
description: 'A comprehensive guide to modern SEO.',
deliverables: [
Deliverable.url('https://example.com/seo-playbook.pdf'),
],
});
const published = await client.listings.publish(listing.id);
console.log(published.url); // https://buy.listbee.so/r7kq2xy9Or read from the environment:
export LISTBEE_API_KEY="lb_..."const client = new ListBee(); // reads LISTBEE_API_KEY automaticallyAuthentication
Pass your API key explicitly or via the LISTBEE_API_KEY environment variable.
const client = new ListBee({ apiKey: 'lb_...' });
const client = new ListBee(); // env varThe key is validated lazily — an AuthenticationError is raised only when you make the first API call. API keys start with lb_. Get yours at console.listbee.so.
Getting an API key programmatically
Agents can bootstrap access without a dashboard — 3 steps:
import { ListBee } from 'listbee';
// No API key needed for auth endpoints
const client = new ListBee({ apiKey: '' });
// Step 1: Send OTP to the user's email
await client.signup.sendOtp({ email: 'user@example.com' });
// Step 2: Verify with the code from email → short-lived access token (at_, 24h)
const session = await client.signup.verify({ email: 'user@example.com', code: '482910' });
// session.access_token = "at_..." (temporary)
// session.is_new = true (first time) or false (returning)
// Step 3: Use access token to create a permanent API key
const authedClient = new ListBee({ apiKey: session.access_token });
const key = await authedClient.apiKeys.create({ name: 'My Agent' });
// key.key = "lb_..." (permanent — store this)
// From now on, use the permanent key
const permanentClient = new ListBee({ apiKey: key.key });Resources
| Resource | Methods |
|---|---|
listings |
create, get, list, update, publish, setDeliverables, removeDeliverables, addDeliverable, removeDeliverable, createComplete, delete |
orders |
get, list, deliver, ship, 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 |
sendOtp, verify |
stripe |
connect, disconnect |
utility |
ping |
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)
import { Deliverable } from 'listbee';
await client.listings.setDeliverables(listing.id, {
deliverables: [
Deliverable.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');
// Add a single deliverable using the Deliverable class
import { Deliverable } from 'listbee';
await client.listings.addDeliverable('lst_r7kq2xy9m3pR5tW1', Deliverable.url('https://example.com/playbook.pdf'));
await client.listings.addDeliverable('lst_r7kq2xy9m3pR5tW1', Deliverable.text('Your license key: XXXX-XXXX'));
await client.listings.addDeliverable('lst_r7kq2xy9m3pR5tW1', Deliverable.fromToken(file.token));
// Remove a single deliverable by del_ ID
await client.listings.removeDeliverable('lst_r7kq2xy9m3pR5tW1', 'del_4hR9nK2mQ7tV5wX1');
// Create a listing and attach deliverables in one call
const listing = await client.listings.createComplete({
name: 'SEO Playbook',
price: 2900,
deliverables: [
Deliverable.url('https://example.com/seo-playbook.pdf'),
],
});
await client.listings.publish(listing.id);
// 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)
import { Deliverable } from 'listbee';
const fulfilled = await client.orders.deliver('ord_9xM4kP7nR2qT5wY1', {
deliverables: [
Deliverable.text('Your AI-generated report is ready.'),
],
});
console.log(fulfilled.status); // "fulfilled"
// Or deliver a URL
await client.orders.deliver('ord_9xM4kP7nR2qT5wY1', {
deliverables: [
Deliverable.url('https://example.com/report.pdf'),
],
});
// Ship — add tracking for physical orders
const shipped = await client.orders.ship('ord_9xM4kP7nR2qT5wY1', {
carrier: 'USPS',
tracking_code: '9400111899223',
seller_note: 'Enjoy your purchase!',
});
console.log(shipped.status); // "fulfilled"
// 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';
import { Deliverable } from 'listbee';
// Upload a file (multipart, native FormData)
const file = await client.files.upload({
file: createReadStream('/path/to/report.pdf'),
filename: 'report.pdf',
});
console.log(file.token); // use this token in setDeliverables / Deliverable.fromToken()
// Then attach to a listing
await client.listings.setDeliverables(listing.id, {
deliverables: [
Deliverable.fromToken(file.token),
],
});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. Three steps: send OTP, verify code, create a permanent API key.
const client = new ListBee(); // no API key needed
// Step 1 — send OTP to email (creates account on first use)
const otpResult = await client.signup.sendOtp({ email: 'seller@example.com' });
console.log(otpResult.expires_in); // 300 (seconds until code expires)
// Step 2 — verify the 6-digit code
const session = await client.signup.verify({ email: 'seller@example.com', code: '123456' });
console.log(session.access_token); // at_... (24-hour access token)
console.log(session.is_new); // true if account was just created
// Step 3 — create a permanent API key using the access token
const authedClient = new ListBee({ apiKey: session.access_token });
const apiKey = await authedClient.apiKeys.create({ name: 'Production' });
console.log(apiKey.key); // lb_... (save this immediately — shown once)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, thenpublish(). - External — ListBee fires
order.paidwebhook, your app handles delivery. Callorders.deliver()to push content back.
import { Deliverable } from 'listbee';
// One-shot: create listing + attach deliverables
const listing = await client.listings.createComplete({
name: 'SEO Playbook',
price: 2900,
deliverables: [
Deliverable.url('https://example.com/seo-playbook.pdf'),
],
});
await client.listings.publish(listing.id);
// Add or remove individual deliverables after creation
await client.listings.addDeliverable(listing.id, Deliverable.text('Bonus: license key XXXX-XXXX'));
await client.listings.removeDeliverable(listing.id, 'del_4hR9nK2mQ7tV5wX1');
// External fulfillment — AI-generated content
// Use CheckoutField builder for type-safe schema construction
const external = await client.listings.create({
name: 'Custom SEO Report',
price: 4900,
fulfillment: 'external',
checkout_schema: [
CheckoutField.text('website_url', { label: 'Your website URL', sortOrder: 0 }),
CheckoutField.select('urgency', { label: 'How urgent?', options: ['Low', 'Medium', 'High'], required: false, sortOrder: 1 }),
],
});
await client.listings.publish(external.id);
// On order.paid webhook:
await client.orders.deliver(order.id, {
deliverables: [
Deliverable.text(generatedReport),
],
});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 });
}Utility
Verify API connectivity and that your API key is valid:
const ping = await client.utility.ping();
console.log(ping.status); // "ok"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,
Deliverable, // input class: .file() | .url() | .text() | .fromToken()
CheckoutField, // input builder: .text() | .select() | .address() | .date()
PartialCreationError, // thrown when listing is created but deliverable attachment fails
// Response types
type ListingResponse,
type OrderResponse,
type CustomerResponse,
type FileResponse,
type WebhookResponse,
type AccountResponse,
type ApiKeyResponse,
type SignupResponse,
type VerifyResponse,
type WebhookEventResponse,
type WebhookTestResponse,
// 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.
Contributing
Bug reports and feature requests welcome — open an issue on GitHub.