TypeScript SDK

Official RevKeen SDK for TypeScript and JavaScript

The RevKeen TypeScript SDK provides a type-safe interface to the RevKeen API. It works with Node.js, Deno, Bun, and modern browsers.

Installation

npm install @revkeen/sdk

Requirements

  • Node.js 18+ (or Deno, Bun)
  • TypeScript 4.7+ (optional, for type checking)

Quick Start

import RevKeen from '@revkeen/sdk';

const client = new RevKeen({
  apiKey: process.env.REVKEEN_API_KEY,
});

// Create a customer
const customer = await client.customers.create({
  email: 'john@example.com',
  name: 'John Doe',
});

console.log(customer.data.id);

Configuration

import RevKeen from '@revkeen/sdk';

const client = new RevKeen({
  // Required
  apiKey: 'rk_live_xxxxxxxx',
  
  // Optional
  baseUrl: 'https://api.revkeen.com',   // API base URL
  timeout: 30000,                        // Request timeout in ms
  maxRetries: 3,                         // Retry attempts for failures
  fetch: customFetch,                    // Custom fetch implementation
  httpAgent: customAgent,                // Custom HTTP agent (Node.js)
});

Environment Variables

The SDK automatically reads from environment variables:

REVKEEN_API_KEY=rk_live_xxxxxxxx

Resources

Customers

// List customers
const customers = await client.customers.list({
  limit: 20,
  page: 1,
});

// Create a customer
const customer = await client.customers.create({
  email: 'john@example.com',
  name: 'John Doe',
  companyName: 'Acme Inc',
  metadata: {
    salesforce_id: '00Q123',
  },
});

// Retrieve a customer
const customer = await client.customers.retrieve('cus_xxxxxxxx');

// Update a customer
const customer = await client.customers.update('cus_xxxxxxxx', {
  name: 'John Smith',
});

// Delete a customer
await client.customers.delete('cus_xxxxxxxx');

Products

// List products
const products = await client.products.list({
  kind: 'subscription',
  isActive: true,
});

// Create a product
const product = await client.products.create({
  productId: 'pro_monthly',
  name: 'Pro Plan',
  kind: 'subscription',
  pricingModel: 'recurring',
  amountMinor: 2900,
  currency: 'USD',
  interval: 'month',
  intervalCount: 1,
  trialDays: 14,
});

// Retrieve a product
const product = await client.products.retrieve('prod_xxxxxxxx');

// Update a product
const product = await client.products.update('prod_xxxxxxxx', {
  name: 'Pro Plan (Updated)',
});

Subscriptions

// List subscriptions
const subscriptions = await client.subscriptions.list({
  customerId: 'cus_xxxxxxxx',
  status: 'active',
});

// Create a subscription
const subscription = await client.subscriptions.create({
  customerId: 'cus_xxxxxxxx',
  productId: 'prod_xxxxxxxx',
  trialDays: 14,
});

// Retrieve a subscription
const subscription = await client.subscriptions.retrieve('sub_xxxxxxxx');

// Update a subscription (change plan)
const subscription = await client.subscriptions.update('sub_xxxxxxxx', {
  productId: 'prod_yyyyyyyy',
  proration: 'create_prorations',
});

// Cancel a subscription
await client.subscriptions.cancel('sub_xxxxxxxx', {
  cancelAtPeriodEnd: true,
});

// Pause a subscription
await client.subscriptions.pause('sub_xxxxxxxx', {
  resumeAt: '2025-03-01T00:00:00Z',
});

// Resume a subscription
await client.subscriptions.resume('sub_xxxxxxxx');

Invoices

// List invoices
const invoices = await client.invoices.list({
  customerId: 'cus_xxxxxxxx',
  status: 'sent',
});

// Create an invoice
const invoice = await client.invoices.create({
  customerId: 'cus_xxxxxxxx',
  currency: 'USD',
  dueDate: '2025-02-15T00:00:00Z',
  lineItems: [
    {
      description: 'Consulting Services',
      quantity: 10,
      unitAmountMinor: 15000,
    },
  ],
});

// Submit for approval
await client.invoices.submit('inv_xxxxxxxx');

// Approve an invoice
await client.invoices.approve('inv_xxxxxxxx');

// Send an invoice
await client.invoices.send('inv_xxxxxxxx');

// Void an invoice
await client.invoices.void('inv_xxxxxxxx', {
  reason: 'Duplicate invoice',
});

// Download PDF
const pdfBuffer = await client.invoices.getPdf('inv_xxxxxxxx');

Checkout Sessions

// Create a checkout session
const session = await client.checkoutSessions.create({
  mode: 'subscription',
  productId: 'prod_xxxxxxxx',
  customerId: 'cus_xxxxxxxx',
  successUrl: 'https://yourapp.com/success',
  cancelUrl: 'https://yourapp.com/cancel',
});

// Redirect to checkout
window.location.href = session.data.url;

// Retrieve a session
const session = await client.checkoutSessions.retrieve('chk_xxxxxxxx');

// Expire a session
await client.checkoutSessions.expire('chk_xxxxxxxx');

Webhooks

// List webhook endpoints
const webhooks = await client.webhooks.list();

// Create a webhook endpoint
const webhook = await client.webhooks.create({
  url: 'https://yourapp.com/webhooks/revkeen',
  events: ['invoice.paid', 'subscription.created'],
});

// Store the secret for verification
console.log(webhook.data.secret);

// Update a webhook
const webhook = await client.webhooks.update('whk_xxxxxxxx', {
  events: ['invoice.paid', 'subscription.created', 'subscription.cancelled'],
});

// Delete a webhook
await client.webhooks.delete('whk_xxxxxxxx');

Pagination

Manual Pagination

const page1 = await client.customers.list({ limit: 20, page: 1 });
const page2 = await client.customers.list({ limit: 20, page: 2 });

console.log('Total:', page1.pagination.total);
console.log('Pages:', page1.pagination.totalPages);

Auto-Pagination

// Iterate through all results
for await (const customer of client.customers.list()) {
  console.log(customer.id, customer.email);
}

// Get all results as array
const allCustomers = await client.customers.list().all();

Error Handling

import RevKeen, {
  RevKeenError,
  NotFoundError,
  ValidationError,
  UnauthorizedError,
  ForbiddenError,
  RateLimitError,
  InternalServerError,
} from '@revkeen/sdk';

try {
  const customer = await client.customers.retrieve('cus_invalid');
} catch (error) {
  if (error instanceof NotFoundError) {
    // 404 - Resource not found
    console.log('Customer not found');
  } else if (error instanceof ValidationError) {
    // 400/422 - Validation failed
    console.log('Validation error:', error.message);
    console.log('Details:', error.details);
  } else if (error instanceof UnauthorizedError) {
    // 401 - Invalid API key
    console.log('Invalid API key');
  } else if (error instanceof ForbiddenError) {
    // 403 - Insufficient permissions
    console.log('Permission denied');
  } else if (error instanceof RateLimitError) {
    // 429 - Rate limited
    console.log('Rate limited, retry after:', error.retryAfter, 'seconds');
  } else if (error instanceof InternalServerError) {
    // 5xx - Server error
    console.log('Server error, please retry');
  } else if (error instanceof RevKeenError) {
    // Generic API error
    console.log('API error:', error.code, error.message);
  }
}

Webhook Verification

import { verifyWebhook, WebhookEvent } from '@revkeen/sdk/webhooks';

// Express.js example
app.post('/webhooks/revkeen', express.raw({ type: 'application/json' }), (req, res) => {
  const payload = req.body.toString();
  const signature = req.headers['x-revkeen-signature'] as string;
  
  try {
    const event: WebhookEvent = verifyWebhook(
      payload,
      signature,
      process.env.WEBHOOK_SECRET!
    );
    
    switch (event.type) {
      case 'invoice.paid':
        handleInvoicePaid(event.data);
        break;
      case 'subscription.created':
        handleSubscriptionCreated(event.data);
        break;
      case 'subscription.cancelled':
        handleSubscriptionCancelled(event.data);
        break;
    }
    
    res.json({ received: true });
  } catch (error) {
    console.error('Webhook verification failed:', error);
    res.status(400).send('Invalid signature');
  }
});

TypeScript Types

All types are exported from the package:

import RevKeen, {
  // Resource types
  Customer,
  Product,
  Subscription,
  Invoice,
  CheckoutSession,
  Webhook,
  
  // Request types
  CustomerCreateParams,
  ProductCreateParams,
  SubscriptionCreateParams,
  InvoiceCreateParams,
  
  // Response types
  CustomerListResponse,
  ProductListResponse,
  
  // Enums
  SubscriptionStatus,
  InvoiceStatus,
  ProductKind,
  BillingInterval,
} from '@revkeen/sdk';

// Use types in your code
async function createCustomer(params: CustomerCreateParams): Promise<Customer> {
  const response = await client.customers.create(params);
  return response.data;
}

Request Options

Pass request options to individual calls:

// Custom timeout for slow operations
const customers = await client.customers.list({}, {
  timeout: 60000,
});

// Idempotency key for POST requests
const customer = await client.customers.create(
  { email: 'john@example.com' },
  { idempotencyKey: 'unique-request-id' }
);

// Custom headers
const customer = await client.customers.retrieve('cus_xxx', {
  headers: { 'X-Custom-Header': 'value' },
});

Debugging

Enable debug logging:

const client = new RevKeen({
  apiKey: 'rk_live_xxx',
  debug: true,
});

Framework Examples

Next.js App Router

// app/api/checkout/route.ts
import { NextResponse } from 'next/server';
import RevKeen from '@revkeen/sdk';

const client = new RevKeen();

export async function POST(request: Request) {
  const { productId, customerId } = await request.json();
  
  const session = await client.checkoutSessions.create({
    mode: 'subscription',
    productId,
    customerId,
    successUrl: `${process.env.NEXT_PUBLIC_URL}/dashboard`,
    cancelUrl: `${process.env.NEXT_PUBLIC_URL}/pricing`,
  });
  
  return NextResponse.json({ url: session.data.url });
}

Express.js

import express from 'express';
import RevKeen from '@revkeen/sdk';

const app = express();
const client = new RevKeen();

app.post('/api/customers', async (req, res) => {
  try {
    const customer = await client.customers.create(req.body);
    res.json(customer.data);
  } catch (error) {
    res.status(error.status || 500).json({ error: error.message });
  }
});

Related Resources