Skip to content

SDK Documentation

TempestTouch - Node.js SDK & CLI for cryptocurrency payments

Installation

Install the Tempest Touch SDK using your preferred package manager:

Using pnpm (recommended)

pnpm add tempesttouch

Using npm

npm install tempesttouch

Global CLI Installation

# Install globally for CLI access
pnpm add -g tempesttouch

# Or with npm
npm install -g tempesttouch

Requirements: Node.js 20+ with ESM support

Quick Start

How Tempest Touch Works

  1. Your server calls the Tempest Touch API to create a payment request
  2. Tempest Touch generates a unique payment address and QR code
  3. Your customer sends cryptocurrency to that address
  4. Tempest Touch monitors the blockchain and notifies you via webhook
  5. Funds are automatically forwarded to your wallet (minus fees)

SDK Usage

Basic SDK Example

import { TempestTouchClient, Blockchain } from 'tempesttouch';

// Initialize with your API key (get it from your dashboard)
const tempesttouch = new TempestTouchClient({
  apiKey: 'cp_live_your_api_key_here',
});

// Create a payment when customer checks out
  const result = await tempesttouch.createPayment({
  businessId: 'your-business-id',  // From your dashboard
  amount: 100,                      // Amount in fiat currency
  currency: 'USD',                  // Fiat currency (default: USD)
  blockchain: Blockchain.BTC,       // Cryptocurrency to accept
  description: 'Order #12345',      // Shown to customer
  metadata: {                       // Your custom data
    orderId: '12345',
    customerEmail: 'customer@example.com'
  }
});

// Display to customer
console.log('Send payment to:', result.payment.payment_address);
console.log('Amount:', result.payment.crypto_amount, result.payment.blockchain);
console.log('QR Code:', result.payment.qr_code);

cURL Example

Direct API Call

curl -X POST https://tempesttouch.com/api/payments/create \
  -H "Authorization: Bearer cp_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "business_id": "your-business-id",
    "amount": 100,
    "blockchain": "BTC",
    "description": "Order #12345",
    "metadata": {"orderId": "12345"}
  }'

CLI Usage

CLI Quick Start

# Configure your API key (one-time setup)
tempesttouch config set-key cp_live_your_api_key

# Create a Bitcoin payment
tempesttouch payment create --business-id biz_123 --amount 100 --blockchain BTC

# Create an Ethereum payment with description
tempesttouch payment create --business-id biz_123 --amount 50 --blockchain ETH --description "Order #12345"

# Create a USDC payment on Polygon
tempesttouch payment create --business-id biz_123 --amount 25 --blockchain USDC_POL

# Send with fiat amount (wallet commands)
tempesttouch wallet send --chain SOL --to abc... --amount-fiat 10 --fiat USD
tempesttouch wallet send --chain ETH --to 0x123... --amount-fiat 25 --fiat EUR

# Get payment details
tempesttouch payment get pay_abc123

# List payments
tempesttouch payment list --business-id biz_123

# Get exchange rates with fiat support
tempesttouch rates get BTC --fiat USD
tempesttouch rates get SOL --fiat EUR

SDK Client Configuration

Initialize the tempesttouchClient with your API key from your business dashboard:

Client Initialization

import { TempestTouchClient } from 'tempesttouch';

const client = new TempestTouchClient({
  // Required: Your API key (starts with cp_live_)
  apiKey: 'cp_live_your_api_key_here',
  
  // Optional: Custom API URL (defaults to https://tempesttouch.com/api)
  baseUrl: 'https://tempesttouch.com/api',
  
  // Optional: Request timeout in milliseconds (default: 30000)
  timeout: 30000,
});

Environment Variables

VariableDescription
tempesttouch_API_KEYAPI key (overrides config file)
tempesttouch_BASE_URLCustom API URL

Payments API

Primary Use Case: Call this API from your backend when a customer wants to pay with cryptocurrency. Display the returned payment address and QR code to your customer.

Create Payment

Create a new payment

const result = await client.createPayment({
  businessId: 'your-business-id',  // Required: From your dashboard
  amount: 100,                      // Required: Amount in fiat
  currency: 'USD',                  // Optional: Fiat currency (default: USD)
  blockchain: 'BTC',                // Required: BTC, ETH, SOL, POL, BCH, USDC_ETH, USDC_POL, USDC_SOL
  description: 'Order #12345',      // Optional: Shown to customer
  metadata: {                       // Optional: Your custom data
    orderId: '12345',
    customerEmail: 'customer@example.com'
  }
});

// Response structure
console.log(result);
// {
//   success: true,
//   payment: {
//     id: 'pay_abc123',
//     payment_address: 'bc1q...',
//     crypto_amount: '0.00234567',
//     blockchain: 'BTC',
//     status: 'pending',
//     expires_at: '2024-01-01T13:00:00Z',
//     qr_code: 'data:image/png;base64,...'
//   },
//   usage: { current: 45, limit: 100, remaining: 55 }
// }

Check Payment Status

There are two ways to know when a payment is complete:

Option 1: Polling (Simple)

Poll for payment status

// Check status once
const result = await client.getPayment('pay_abc123');
console.log(result.payment.status); // 'pending', 'confirmed', 'forwarded', etc.

// Or wait for payment to complete (polls automatically)
const payment = await client.waitForPayment('pay_abc123', {
  interval: 5000,      // Check every 5 seconds
  timeout: 600000,     // Give up after 10 minutes
  onStatusChange: (status, payment) => {
    console.log(`Status changed to: ${status}`);
  }
});

if (payment.payment.status === 'confirmed' || payment.payment.status === 'forwarded') {
  console.log('Payment successful!');
} else {
  console.log('Payment failed or expired');
}

Option 2: Webhooks (Recommended)

Configure a webhook URL in your business settings to receive real-time notifications. See the Webhook Verification section below.

List Payments

List payments with filters

const payments = await client.listPayments({
  businessId: 'biz_123',
  status: 'completed', // optional filter
  limit: 20,           // optional, default 50
  offset: 0,           // optional, for pagination
});

console.log(`Found ${payments.length} payments`);

Get Payment QR Code

The QR code endpoint returns binary PNG image data that can be used directly in HTML.

QR code usage

// Get QR code URL for use in HTML <img> tags
const qrUrl = client.getPaymentQRUrl('pay_abc123');
// Returns: "https://tempesttouch.com/api/payments/pay_abc123/qr"

// Use directly in HTML:
// <img src={qrUrl} alt="Payment QR Code" />

// Or fetch as binary data (for server-side processing)
const imageData = await client.getPaymentQR('pay_abc123');

// Save to file (Node.js)
import fs from 'fs';
fs.writeFileSync('payment-qr.png', Buffer.from(imageData));

HTML usage

<!-- Use QR endpoint directly as image source -->
<img src="https://tempesttouch.com/api/payments/pay_abc123/qr" alt="Payment QR Code" />

Credit Card Payments

Accept credit and debit card payments via Stripe Connect. Merchants must complete Stripe onboarding before accepting card payments. Supports both direct payments (gateway mode) and escrow mode for holding funds until release.

🔗 Merchant Onboarding Required

Before accepting card payments, merchants must complete Stripe Connect onboarding. Use createStripeOnboardingLink()to generate the onboarding URL. The merchant's country must be supplied on first onboarding and is locked at Stripe account creation — all Stripe Connect supported countries (US, CA, GB, AU, DE, FR, JP, SG, and ~45 more) work.

Customer Payment Choice Example

Let customers choose: Crypto OR Card

import { TempestTouchClient } from 'tempesttouch';

const client = new TempestTouchClient({ apiKey: 'your-api-key' });

// Check what payment methods are available
const support = await client.getPaymentMethodSupport('business-id');

if (support.cards) {
  // Customer can choose crypto OR card
  console.log('✅ Crypto payments available');
  console.log('✅ Card payments available');
  
  // Create card payment
  const cardPayment = await client.createCardPayment({
    businessId: 'biz_123',
    amount: 5000, // $50.00 in cents
    currency: 'usd',
    description: 'Order #12345',
    successUrl: 'https://yourstore.com/success',
    cancelUrl: 'https://yourstore.com/cancel'
  });
  
  // Redirect customer to: cardPayment.checkout_url
  
} else {
  console.log('✅ Crypto payments available');
  console.log('❌ Card payments require Stripe onboarding');
  
  // Only crypto payments available
  const cryptoPayment = await client.createPayment({
    businessId: 'biz_123',
    amount: 50.00,
    currency: 'USD',
    blockchain: 'BTC',
    description: 'Order #12345'
  });
}

Merchant Stripe Onboarding

Create Stripe Connect onboarding link

// Generate onboarding link for merchant.
// 'country' is an ISO-3166-1 alpha-2 code (US, CA, GB, AU, DE, FR, JP, SG, ...).
// Required on first onboarding; cannot be changed once Stripe creates the account.
const onboarding = await client.createStripeOnboardingLink('business-id', {
  email: 'merchant@example.com',
  country: 'CA'
});

console.log('Onboarding URL:', onboarding.onboarding_url);
// Redirect merchant to complete Stripe onboarding

// Check onboarding status
const status = await client.getStripeAccountStatus('business-id');
console.log('Can accept cards:', status.onboarding_complete);

Create Card Payment

Create credit card payment

// Gateway Mode - Direct payment to merchant
const payment = await client.createCardPayment({
  businessId: 'biz_123',
  amount: 5000, // $50.00 in cents
  currency: 'usd',
  description: 'Order #12345',
  metadata: { orderId: '12345', customerId: 'cust_456' },
  successUrl: 'https://yourstore.com/success',
  cancelUrl: 'https://yourstore.com/cancel',
  escrowMode: false // Direct payment (default)
});

// Redirect customer to payment.checkout_url for card entry

Card Escrow Mode

Create card payment with escrow

// Escrow Mode - Hold funds until release
const escrowPayment = await client.createCardPayment({
  businessId: 'biz_123',
  amount: 10000, // $100.00 in cents
  currency: 'usd',
  description: 'Freelance Work - Logo Design',
  escrowMode: true, // Hold funds in escrow
  metadata: { projectId: 'proj_789' }
});

// Customer pays via payment.checkout_url
// Funds are held until release

// Later, release funds to merchant
const release = await client.releaseCardEscrow(escrowPayment.escrow_id, 'Work completed successfully');
console.log(`Released $${release.amount_transferred / 100} to merchant`);

Card Payment Convenience Functions

Using card-payments convenience module

import {
  createQuickCardPayment,
  formatCardAmount,
  calculateCardPaymentFees
} from 'tempesttouch/card-payments';

// Quick payment with USD amount (auto-converts to cents)
const payment = await createQuickCardPayment(client, 'biz_123', 50.0, 'Order #123', {
  metadata: { orderId: '123' },
  escrowMode: true
});

// Format amounts for display
console.log(formatCardAmount(5000)); // "$50.00"
console.log(formatCardAmount(5050, 'EUR')); // "€50.50"

// Calculate platform fees
const fees = calculateCardPaymentFees(5000, 'free'); // free tier = 1%
console.log(`Platform fee: $${fees.platformFee / 100}`); // "$0.50"
console.log(`Merchant receives: $${fees.merchantReceives / 100}`); // "$49.50"

Webhook Events for Card Payments

Handle card payment webhooks

// Webhook events you'll receive for card payments:
// - card_payment_success: Customer paid successfully
// - card_dispute_created: Customer disputed the charge
// - card_refund: Payment was refunded
// - card_escrow_release: Escrow funds were released to merchant

app.post('/webhook', (req, res) => {
  const { event_type, data } = req.body;
  
  switch (event_type) {
    case 'card_payment_success':
      console.log('Card payment received:', data.amount / 100);
      // Update order status, send confirmation email, etc.
      break;
      
    case 'card_dispute_created':
      console.log('Dispute created for payment:', data.stripe_payment_intent_id);
      // Alert merchant, gather evidence
      break;
      
    case 'card_escrow_release':
      console.log('Escrow released:', data.amount / 100);
      // Mark project as completed, notify freelancer
      break;
  }
  
  res.status(200).send('OK');
});

Platform Fees

Platform Fee Structure

Free Tier: 1.0% platform fee
Pro Tier: 0.5% platform fee
Plus Stripe processing fees (2.9% + 30¢ for US cards)

Refunds

Refund card payments

// Full refund
const refund = await client.refundCardPayment('payment-intent-id');

// Partial refund ($25 out of $50 payment)
const partialRefund = await client.refundCardPayment('payment-intent-id', {
  amount: 2500, // $25.00 in cents
  reason: 'Customer complaint - partial refund'
});

console.log('Refund status:', refund.status);

Card Escrow — Release & Refund

Release and refund card escrow

// Release card escrow funds to merchant
const release = await client.releaseCardEscrow('escrow-id', 'Work completed successfully');
console.log(`Transfer ID: ${release.transfer_id}`);
console.log(`Amount released: $${(release.amount_transferred / 100).toFixed(2)}`);

// Refund card escrow — full refund
const refund = await client.refundCardPayment('escrow-id');
console.log(`Refund ID: ${refund.refund_id}`);

// Refund card escrow — partial refund
const partialRefund = await client.refundCardPayment('escrow-id', {
  amount: 2500, // $25.00 in cents
  reason: 'Partial refund — item returned'
});
console.log(`Refunded: $${(partialRefund.amount_refunded / 100).toFixed(2)}`);
console.log(`Escrow status: ${partialRefund.escrow_status}`); // 'partially_refunded'

CLI Card Commands

Card payment CLI

# Create a card payment ($50.00 = 5000 cents)
tempesttouch card create --business-id biz_123 --amount 5000 --description "Order #123"

# Create card payment with escrow mode
tempesttouch card create --business-id biz_123 --amount 10000 --escrow --description "Freelance work"

# Get card payment details
tempesttouch card get pay_abc123

# List card payments for a business
tempesttouch card list --business-id biz_123

# Stripe Connect — onboard a merchant
tempesttouch card connect onboard merch_123 --email merchant@example.com --country US

# Stripe Connect — check onboarding status
tempesttouch card connect status merch_123

# Release card escrow funds
tempesttouch card escrow release esc_123 --reason "Work completed"

# Refund card escrow (full)
tempesttouch card escrow refund esc_123

# Refund card escrow (partial, $25)
tempesttouch card escrow refund esc_123 --amount 2500 --reason "Partial refund"

Stripe Webhook Events

The platform processes these Stripe webhook events automatically:

payment_intent.succeededCard payment completed — updates transaction record, funds escrow if applicable, creates DID reputation event
charge.dispute.createdCustomer disputed a charge — creates dispute record, negative DID reputation impact (-50 weight)
payout.createdStripe payout initiated to merchant bank account
payout.paidPayout arrived in merchant bank account
account.updatedStripe Connect account capabilities changed (charges_enabled, payouts_enabled, etc.)

Businesses API

Create Business

Create a new business

const business = await client.createBusiness({
  name: 'My Store',
  webhookUrl: 'https://your-site.com/webhook',
  walletAddresses: {
    BTC: 'bc1q...',
    ETH: '0x...',
    SOL: '...',
  },
});

console.log(`Business ID: ${business.id}`);
console.log(`API Key: ${business.apiKey}`);

Get Business

Retrieve business details

const business = await client.getBusiness('biz_123');

console.log(business.name);
console.log(business.walletAddresses);

List Businesses

List all businesses

const businesses = await client.listBusinesses();

businesses.forEach(biz => {
  console.log(`${biz.name}: ${biz.id}`);
});

Update Business

Update business settings

const updated = await client.updateBusiness('biz_123', {
  name: 'Updated Store Name',
  webhookUrl: 'https://new-webhook-url.com/webhook',
});

Escrow API

Create and manage trustless crypto escrows. No accounts required — authentication uses unique tokens returned at creation.

Create Escrow

Create a new escrow (crypto amount)

const escrow = await client.createEscrow({
  chain: 'ETH',
  amount: 0.5,
  depositorAddress: '0xAlice...',
  beneficiaryAddress: '0xBob...',
  expiresInHours: 48,  // optional (default: 24, max: 720)
  metadata: { order_id: '12345' },  // optional
});

console.log('Deposit to:', escrow.escrowAddress);
console.log('Release token:', escrow.releaseToken);      // Save this! Given to depositor
console.log('Beneficiary token:', escrow.beneficiaryToken); // Save this! Given to beneficiary

Fiat Conversion Support

Convert fiat to crypto amount

// Convert fiat to crypto
const conversion = await client.convertFiatToCrypto(50, 'USD', 'SOL');
console.log(`$50 USD = ${conversion.cryptoAmount} SOL`);
console.log(`Rate: 1 SOL = $${conversion.rate}`);

Create escrow with fiat amount

// Create escrow with fiat amount (auto-converts internally)
const escrow = await client.createEscrow({
  chain: 'SOL',
  amountFiat: 50,
  fiatCurrency: 'USD',
  depositorAddress: '...',
  beneficiaryAddress: '...',
});

console.log(`Escrow created for $50 USD (${escrow.amount} SOL)`);

Get & List Escrows

Get escrow by ID

const escrow = await client.getEscrow('a1b2c3d4-...');
console.log(escrow.status);  // 'created' | 'funded' | 'released' | 'settled' | ...

List escrows with filters

const { escrows, total } = await client.listEscrows({
  status: 'funded',
  depositor: '0xAlice...',   // optional
  beneficiary: '0xBob...',   // optional
  limit: 20,
  offset: 0,
});

Release, Refund & Dispute

Release funds to beneficiary (depositor only)

await client.releaseEscrow('a1b2c3d4-...', 'esc_release_token...');
// Triggers on-chain settlement: funds → beneficiary minus fee

Refund to depositor (depositor only, no fee)

await client.refundEscrow('a1b2c3d4-...', 'esc_release_token...');
// Full amount returned — no platform fee on refunds

Open a dispute (either party)

await client.disputeEscrow('a1b2c3d4-...', 'esc_any_token...', 
  'Work was not delivered as agreed'
);

Events & Polling

Get audit log

const { events } = await client.getEscrowEvents('a1b2c3d4-...');
events.forEach(e => console.log(e.event_type, e.actor, e.created_at));

Wait for a specific status

// Poll until escrow reaches target status (or timeout)
const settled = await client.waitForEscrow('a1b2c3d4-...', 'settled', {
  intervalMs: 5000,   // check every 5s
  timeoutMs: 300000,  // timeout after 5min
});

Escrow Management

Authenticate with escrow tokens to manage escrows and determine available actions based on your role.

Authenticate and manage escrow

// Authenticate with escrow token
const { escrow, role } = await client.authenticateEscrow('escrow-id', 'token');
console.log(`Your role: ${role}`); // 'depositor' or 'beneficiary'

// Check available actions based on role and status
if (escrow.status === 'funded') {
  if (role === 'depositor') {
    console.log('Available actions: release, refund, dispute');
  } else if (role === 'beneficiary') {
    console.log('Available actions: dispute');
  }
}

Depositor workflow

// Depositor can release or refund
const auth = await client.authenticateEscrow(escrowId, releaseToken);
if (auth.role === 'depositor') {
  // Release to beneficiary
  await client.releaseEscrow(escrowId, releaseToken);
  
  // Or refund to self (if needed)
  // await client.refundEscrow(escrowId, releaseToken);
}

Beneficiary workflow

// Beneficiary can check status and dispute if needed
const auth = await client.authenticateEscrow(escrowId, beneficiaryToken);
if (auth.role === 'beneficiary') {
  console.log(`Escrow status: ${auth.escrow.status}`);
  
  // Open dispute if work not delivered
  if (auth.escrow.status === 'funded' && workNotDelivered) {
    await client.disputeEscrow(escrowId, beneficiaryToken, 
      'Work was not delivered as agreed upon'
    );
  }
}

Web Management: Both parties can also manage escrows through the web interface at /escrow/manage?id=xxx&token=yyy. Share the escrow ID and appropriate token for easy access.

Recurring Escrow Series

Create and manage automated periodic escrow payments. Supports both crypto and card payment methods.

Create Escrow Series

Create a recurring escrow series

const series = await client.createEscrowSeries({
  business_id: 'biz_123',
  payment_method: 'crypto',             // 'crypto' or 'card'
  customer_email: 'client@example.com',
  description: 'Weekly retainer — frontend dev',
  amount: 500,
  currency: 'USD',
  coin: 'USDC_SOL',                     // Required for crypto
  interval: 'weekly',                   // 'weekly' | 'biweekly' | 'monthly'
  max_periods: 12,                      // Optional: stop after N periods
  beneficiary_address: 'Bob...',        // Required for crypto
  // stripe_account_id: 'acct_...',     // Required for card method
});

console.log('Series ID:', series.id);
console.log('Next charge:', series.next_charge_at);

List Escrow Series

List series for a business

// List all active series
const { series, total } = await client.listEscrowSeries('biz_123', 'active');

// List all series (no status filter)
const all = await client.listEscrowSeries('biz_123');

Get Series Details

Get series with child escrows

const { series, escrows } = await client.getEscrowSeries('series_abc123');

console.log('Status:', series.status);
console.log('Periods completed:', series.periods_completed);
escrows.forEach(e => {
  console.log(`  Period ${e.period}: ${e.status} — ${e.amount} ${series.currency}`);
});

Update Series

Pause, resume, or change amount

// Pause a series
await client.updateEscrowSeries('series_abc123', { status: 'paused' });

// Resume a series
await client.updateEscrowSeries('series_abc123', { status: 'active' });

// Change amount for future periods
await client.updateEscrowSeries('series_abc123', { amount: 750 });

Cancel Series

Permanently cancel a series

await client.cancelEscrowSeries('series_abc123');
// In-flight escrows are not affected — release or refund them individually

CLI Commands

Recurring escrow CLI

# Create a recurring escrow series
tempesttouch escrow series create \
  --business-id biz_123 \
  --payment-method crypto \
  --email client@example.com \
  --amount 500 --currency USD --coin USDC_SOL \
  --interval weekly --max-periods 12 \
  --beneficiary Bob...

# List series for a business
tempesttouch escrow series list --business-id biz_123
tempesttouch escrow series list --business-id biz_123 --status active

# Get series details (includes child escrows)
tempesttouch escrow series get series_abc123

# Pause a series
tempesttouch escrow series pause series_abc123

# Resume a series
tempesttouch escrow series resume series_abc123

# Cancel a series permanently
tempesttouch escrow series cancel series_abc123

Exchange Rates

Get real-time cryptocurrency exchange rates in multiple fiat currencies. Supports fiat conversions for payments and escrows.

Get Single Rate

Get exchange rate for one cryptocurrency

// Get rate in USD (default)
const rate = await client.getExchangeRate('BTC');
console.log(`1 BTC = $${rate.price} USD`);

// Get rate in specific fiat currency
const eurRate = await client.getExchangeRate('SOL', 'EUR');
console.log(`1 SOL = €${eurRate.price} EUR`);

Get Multiple Rates

Get rates for multiple cryptocurrencies

// Get multiple rates in USD (default)
const rates = await client.getExchangeRates(['BTC', 'ETH', 'SOL']);

// Get multiple rates in specific fiat currency
const gbpRates = await client.getExchangeRates(['BTC', 'ETH', 'SOL'], 'GBP');
console.log(`BTC: £${gbpRates.rates.BTC}`);

Fiat Conversion

Convert fiat amounts to crypto

// Convert $100 USD to BTC
const conversion = await client.convertFiatToCrypto(100, 'USD', 'BTC');
console.log(`$100 USD = ${conversion.cryptoAmount.toFixed(8)} BTC`);

// Convert €50 EUR to SOL
const eurConversion = await client.convertFiatToCrypto(50, 'EUR', 'SOL');
console.log(`€50 EUR = ${eurConversion.cryptoAmount.toFixed(6)} SOL`);

Supported Fiat Currencies

USD
EUR
GBP
CAD
AUD
JPY
CHF
CNY
INR
BRL

Supported Blockchains

Bitcoin
BTC
Bitcoin Cash
BCH
Ethereum
ETH
Polygon
POL
Solana
SOL
USDC (Ethereum)
USDC_ETH
USDC (Polygon)
USDC_POL
USDC (Solana)
USDC_SOL

Webhook Verification

Verify webhook signatures to ensure requests are from Tempest Touch:

Manual Verification

Verify webhook signature

import { verifyWebhookSignature } from 'tempesttouch';

// In your webhook handler
const isValid = verifyWebhookSignature({
  payload: rawBody,  // Raw request body as string
  signature: req.headers['x-tempesttouch-signature'],
  secret: 'your-webhook-secret',
});

if (!isValid) {
  return res.status(401).json({ error: 'Invalid signature' });
}

// Process the webhook...

Express Middleware

Use the webhook handler middleware

import express from 'express';
import { createWebhookHandler } from 'tempesttouch';

const app = express();

// Use raw body parser for webhook route
app.post('/webhook', 
  express.raw({ type: 'application/json' }),
  createWebhookHandler({
    secret: 'your-webhook-secret',
    onEvent: async (event) => {
      console.log('Received event:', event.type);
      
      switch (event.type) {
        case 'payment.completed':
          // Handle completed payment
          await fulfillOrder(event.payment_id);
          break;
        case 'payment.expired':
          // Handle expired payment
          await cancelOrder(event.payment_id);
          break;
        case 'payment.failed':
          // Handle failed payment
          await notifyCustomer(event.payment_id);
          break;
      }
    },
    onError: (error) => {
      console.error('Webhook error:', error);
    },
  })
);

Webhook Events

payment.createdPayment was created
payment.pendingPayment is pending confirmation
payment.confirmingPayment is being confirmed on blockchain
payment.completedPayment completed successfully
payment.expiredPayment expired without completion
payment.failedPayment failed
payment.refundedPayment was refunded

Webhook Logs

Get webhook delivery logs

// Get recent webhook logs for a business
const logs = await client.getWebhookLogs('biz_123', 50);

logs.forEach(log => {
  console.log(`${log.event}: ${log.status} (${log.statusCode})`);
});

// Test webhook endpoint
const result = await client.testWebhook('biz_123', 'payment.completed');
console.log(`Test delivery: ${result.success ? 'OK' : 'Failed'}`);

CLI Commands

The Tempest Touch CLI provides command-line access to all API features:

Configuration

Configure CLI

# Set your API key
tempesttouch config set-key sk_live_xxxxx

# Set custom API URL (optional)
tempesttouch config set-url https://custom-api.example.com

# Show current configuration
tempesttouch config show

Payment Commands

Payment operations

# Create a Bitcoin payment
tempesttouch payment create \
  --business-id biz_123 \
  --amount 100 \
  --blockchain BTC \
  --description "Order #12345"

# Create a USDC payment on Polygon
tempesttouch payment create \
  --business-id biz_123 \
  --amount 50 \
  --blockchain USDC_POL

# Get payment details
tempesttouch payment get pay_abc123

# List payments
tempesttouch payment list --business-id biz_123 --status completed --limit 20

# Generate QR code
tempesttouch payment qr pay_abc123 --format png > payment-qr.png

Business Commands

Business operations

# Create a business
tempesttouch business create --name "My Store" --webhook-url https://example.com/webhook

# Get business details
tempesttouch business get biz_123

# List all businesses
tempesttouch business list

# Update business
tempesttouch business update biz_123 --name "New Name" --webhook-url https://new-url.com/webhook

Exchange Rate Commands

Rate operations

# Get rate for single cryptocurrency in USD (default)
tempesttouch rates get BTC

# Get rate in specific fiat currency
tempesttouch rates get SOL --fiat EUR

# List all supported rates in USD
tempesttouch rates list

# List all supported rates in EUR
tempesttouch rates list --fiat EUR

Escrow Commands

Escrow operations

# Create escrow with crypto amount
tempesttouch escrow create --chain ETH --amount 0.5 \
  --depositor 0xAlice... --beneficiary 0xBob...

# Create escrow with fiat amount
tempesttouch escrow create --chain SOL --amount-fiat 50 --fiat USD \
  --depositor abc... --beneficiary def...

# Create escrow with EUR amount
tempesttouch escrow create --chain SOL --amount-fiat 45 --fiat EUR \
  --depositor abc... --beneficiary def...

# Authenticate and manage escrow with token
tempesttouch escrow auth <id> --token <token>

# Get escrow details
tempesttouch escrow get a1b2c3d4-...

# List escrows by status
tempesttouch escrow list --status funded

# Release funds (depositor)
tempesttouch escrow release a1b2c3d4-... --token esc_abc123...

# Refund (depositor, no fee)
tempesttouch escrow refund a1b2c3d4-... --token esc_abc123...

# Open dispute (either party)
tempesttouch escrow dispute a1b2c3d4-... --token esc_def456... \
  --reason "Work not delivered as agreed"

# View audit log
tempesttouch escrow events a1b2c3d4-...

Webhook Commands

Webhook operations

# View webhook logs
tempesttouch webhook logs biz_123 --limit 50

# Test webhook endpoint
tempesttouch webhook test biz_123 --event payment.completed

OAuth Client Management

Register and manage OAuth applications for third-party integrations. Create OAuth clients to allow external apps to authenticate users via your Tempest Touch merchant account.

SDK Methods

List OAuth Clients

const result = await tempesttouch.listOAuthClients();
for (const app of result.clients) {
  console.log(app.client_id, app.name);
}

Create an OAuth Client

const app = await tempesttouch.createOAuthClient({
  name: 'My App',
  redirectUris: ['https://myapp.com/callback'],
  scopes: ['openid', 'profile'],
  description: 'My awesome application',
});

console.log('Client ID:', app.client_id);
console.log('Client Secret:', app.client_secret);
// ⚠️ Store the client_secret securely — it is only shown once!

Get OAuth Client Details

const app = await tempesttouch.getOAuthClient('oac_abc123');
console.log(app.name, app.redirect_uris);

Delete an OAuth Client

await tempesttouch.deleteOAuthClient('oac_abc123');

CLI Commands

OAuth CLI

# List all OAuth clients
tempesttouch oauth list

# Create a new OAuth client
tempesttouch oauth create --name "My App" --redirect-uri https://myapp.com/callback --scope openid,profile

# Get client details
tempesttouch oauth get <client-id>

# Delete a client
tempesttouch oauth delete <client-id>

⚠️ Important: The client_secret is only returned when the client is first created. Store it securely — you cannot retrieve it later.

Lightning Network (Custodial)

☝️ Custodial wallet:Lightning wallets are custodial — funds are held on Tempest Touch's LNbits server. This enables instant payments without channel management, but means Tempest Touch holds the keys. Keep balances small and withdraw regularly.

Enable Lightning

Provision a Lightning wallet

// Enable Lightning for a wallet (provisions LNbits custodial wallet)
const result = await client.lightning.enableWallet({
  wallet_id: 'your-wallet-uuid',
  mnemonic: 'your bip39 mnemonic words...',
});

console.log('Lightning enabled!', result);

Lightning Address

Register and manage Lightning Addresses

// Register a Lightning Address (username@tempesttouch.com)
const addr = await client.lightning.registerAddress({
  wallet_id: 'your-wallet-uuid',
  username: 'alice',  // 3-32 chars, lowercase alphanumeric
});
console.log('Address:', addr.lightning_address);
// → alice@tempesttouch.com

// Get current Lightning Address
const current = await client.lightning.getAddress('your-wallet-uuid');
console.log(current.lightning_address);

// Check if a username is available
const check = await client.lightning.checkAddressAvailable('alice');
console.log(check.available ? 'Available!' : 'Taken');

Create Invoice

Create a BOLT11 invoice to receive sats

const invoice = await client.lightning.createInvoice({
  wallet_id: 'your-wallet-uuid',
  amount_sats: 1000,
  description: 'Coffee payment',
});

console.log('Payment request:', invoice.payment_request);
console.log('Payment hash:', invoice.payment_hash);
// Share the payment_request (BOLT11 string) with the sender

Send Payment

Send sats to a Lightning Address or BOLT11 invoice

// Send to a Lightning Address
const payment = await client.lightning.sendPayment({
  wallet_id: 'your-wallet-uuid',
  destination: 'bob@tempesttouch.com',
  amount_sats: 100,
});
console.log('Sent!', payment.payment_hash);

// Send to a BOLT11 invoice (amount encoded in invoice)
const payment2 = await client.lightning.sendPayment({
  wallet_id: 'your-wallet-uuid',
  destination: 'lnbc1000n1p...',
});

Payment History

List Lightning payments

// List all payments
const result = await client.lightning.listPayments({
  wallet_id: 'your-wallet-uuid',
});

// Filter by direction
const incoming = await client.lightning.listPayments({
  wallet_id: 'your-wallet-uuid',
  direction: 'incoming',
});

// Get specific payment by hash
const payment = await client.lightning.getPayment('abc123...');

CLI Commands

Lightning CLI

# Enable Lightning for a wallet
tempesttouch ln enable --wallet-id <uuid>

# Register a Lightning Address
tempesttouch ln address --wallet-id <uuid> --username alice

# Check current Lightning Address
tempesttouch ln address --wallet-id <uuid>

# Check username availability
tempesttouch ln address-check --username alice

# Create an invoice
tempesttouch ln invoice --wallet-id <uuid> --amount 1000 --description "Coffee"

# Send a payment
tempesttouch ln send --wallet-id <uuid> --to bob@tempesttouch.com --amount 100

# Send to a BOLT11 invoice
tempesttouch ln send --wallet-id <uuid> --to lnbc1000n1p...

# List payment history
tempesttouch ln payments --wallet-id <uuid>
tempesttouch ln payments --wallet-id <uuid> --direction incoming

# Check Lightning balance
tempesttouch ln balance --wallet-id <uuid>

Error Handling

Handle errors gracefully in your integration:

Error handling example

import { TempestTouchClient } from 'tempesttouch';

const client = new TempestTouchClient({ apiKey: 'cp_live_your_api_key' });

try {
  const result = await client.createPayment({
    businessId: 'your-business-id',
    amount: 100,
    blockchain: 'BTC',
  });
  
  console.log('Payment created:', result.payment.id);
  console.log('Address:', result.payment.payment_address);
} catch (error) {
  if (error.status === 401) {
    console.error('Invalid API key');
  } else if (error.status === 400) {
    console.error('Invalid request:', error.response?.error);
  } else if (error.status === 429) {
    // Transaction limit exceeded or rate limit
    console.error('Limit exceeded:', error.response?.error);
    console.error('Usage:', error.response?.usage);
  } else {
    console.error('Unexpected error:', error.message);
  }
}

Error Codes

400
Bad Request
Invalid parameters or missing required fields
401
Unauthorized
Invalid or missing API key
403
Forbidden
Access denied to resource
404
Not Found
Resource not found
429
Too Many Requests
Rate limit exceeded
500
Server Error
Internal server error

Account & Auth

Create merchant accounts, authenticate, and manage sessions — all from the CLI or SDK.

CLI Commands

Account management

# Register a new merchant account
tempesttouch auth register --email you@example.com --password yourpassword --name "Your Name"

# Login to get a JWT token (saved to config)
tempesttouch auth login --email you@example.com --password yourpassword

# Check who you're logged in as
tempesttouch auth me

SDK Methods

Authentication

import { TempestTouchClient, registerMerchant, loginMerchant, getMe } from 'tempesttouch';

// Create a client (no API key needed for registration)
const client = new tempesttouchClient({ apiKey: 'unused', baseUrl: 'https://tempesttouch.com' });

// Register a new merchant
const { token, merchant } = await registerMerchant(client, {
  email: 'agent@example.com',
  password: 'securepassword',
  name: 'My Agent'
});
console.log('JWT:', token);
console.log('Merchant ID:', merchant.id);

// Login
const login = await loginMerchant(client, {
  email: 'agent@example.com',
  password: 'securepassword'
});
console.log('JWT:', login.token);

// Get current merchant info (requires JWT auth)
const me = await getMe(client);
console.log('Logged in as:', me.email);

Full Onboarding Flow

Register → Create Business → Claim DID

# 1. Register your account
tempesttouch auth register --email agent@example.com --password mypass123

# 2. Create a business (generates API key)
tempesttouch business create --name "My Agency" --chain ETH,SOL,BTC

# 3. Set your API key
tempesttouch config set-key cp_live_your_key_here

# 4. Claim your DID
tempesttouch reputation did claim

# 5. Check your reputation
tempesttouch reputation did

Reputation & DID

Track agent reputation, manage DIDs, and work with verifiable credentials.

SDK Methods

DID Management

import { TempestTouchClient } from 'tempesttouch';

const client = new TempestTouchClient({ apiKey: 'cp_live_your_api_key' });

// Claim a DID
const did = await client.claimDid({ displayName: 'Agent Smith' });
console.log('DID:', did.did);

// Get your DID
const myDid = await client.getMyDid();
console.log('My DID:', myDid.did);

// Link an external DID
await client.linkDid({ externalDid: 'did:web:example.com' });

Reputation & Receipts

// Submit a task receipt (after escrow settlement)
const receipt = await client.submitReceipt({
  escrowId: 'esc_abc123',
  taskDescription: 'Frontend bug fix',
  rating: 5,
  counterpartyDid: 'did:tempesttouch:xyz789...',
});
console.log('Receipt:', receipt.receiptId);

// Query reputation for a DID
const rep = await client.queryReputation('did:tempesttouch:abc123...');
console.log('Score:', rep.score, 'Tasks:', rep.totalTasks);

Verifiable Credentials

// Get a credential
const cred = await client.getCredential('cred_ghi789');
console.log('Credential:', cred.credential);

// Verify a credential
const result = await client.verifyCredential('cred_ghi789');
console.log('Valid:', result.valid, 'Revoked:', result.revoked);

// Get revocation list
const revocations = await client.getRevocations();
console.log('Revoked credentials:', revocations.revocations.length);

// List all credentials for a DID
const creds = await client.getCredentials('did:key:z6Mk...');
console.log('Credentials:', creds.credentials.length);

// List all task receipts for a DID
const receipts = await client.getReceipts('did:key:z6Mk...');
console.log('Receipts:', receipts.receipts.length);

// Get embeddable reputation badge URL
import { getBadgeUrl } from 'tempesttouch';
const badgeUrl = getBadgeUrl('https://tempesttouch.com', 'did:key:z6Mk...');
// Use in markdown: ![Reputation](badgeUrl)

CLI Commands

DID commands

# Claim a DID
tempesttouch reputation did claim --name "Agent Smith"

# Get your DID
tempesttouch reputation did

# Link an external DID
tempesttouch reputation did link --did "did:web:example.com"

Reputation commands

# Submit a receipt
tempesttouch reputation submit --escrow esc_abc123 --rating 5 --description "Bug fix"

# Query reputation
tempesttouch reputation query did:key:z6Mk...

# Get a credential
tempesttouch reputation credential cred_ghi789

# List all your credentials
tempesttouch reputation credentials

# List credentials for another DID
tempesttouch reputation credentials did:key:z6Mk...

# List your task receipts
tempesttouch reputation receipts

# List receipts for another DID
tempesttouch reputation receipts did:key:z6Mk...

# Get your embeddable reputation badge URL
tempesttouch reputation badge

# Get badge for another DID
tempesttouch reputation badge did:key:z6Mk...

# Verify a credential
tempesttouch reputation verify cred_ghi789

# List revocations
tempesttouch reputation revocations

TypeScript Support

The SDK is written in JavaScript (ESM) but includes JSDoc type annotations for IDE support:

Type hints in VS Code

import { tempesttouchClient, Blockchain, PaymentStatus } from 'tempesttouch';

// Use Blockchain constants for type safety
const result = await client.createPayment({
  businessId: 'biz_123',
  amount: 100,
  blockchain: Blockchain.BTC,  // BTC, BCH, ETH, POL, SOL, DOGE, XRP, ADA, BNB, USDT, USDC, USDC_ETH, USDC_POL, USDC_SOL
});

// result.payment.status: 'pending' | 'detected' | 'confirmed' | 'forwarding' | 'forwarded' | 'expired' | 'failed'
// result.payment.payment_address: string
// result.payment.crypto_amount: string

Trust Profile & Action Receipts (CPTL v2)

Phase 2 adds multi-dimensional trust scoring with categorized action receipts.

Submit Action Receipt

import { submitActionReceipt } from 'tempesttouch/reputation';

const result = await submitActionReceipt(client, {
  receipt_id: '550e8400-...',
  task_id: '550e8400-...',
  agent_did: 'did:key:z6Mk...',
  buyer_did: 'did:key:z6Mk...',
  action_category: 'productivity.completion', // canonical category
  action_type: 'code_review',                 // custom action type
  amount: 250,
  currency: 'USD',
  outcome: 'accepted',
  signatures: { escrow_sig: '...' },
});

Get Trust Profile

import { getTrustProfile } from 'tempesttouch/reputation';

const profile = await getTrustProfile(client, 'did:key:z6Mk...');
// profile.trust_vector = { E: 42.5, P: 12.3, B: 9.1, D: 2.08, R: 0.87, A: 0, C: 0 }
// profile.reputation = { windows: { ... }, anti_gaming: { ... } }
// profile.computed_at = "2026-02-13T..."

Valid action categories: economic.transaction, economic.dispute,economic.refund, productivity.task, productivity.application,productivity.completion, identity.profile_update,identity.verification, social.post, social.comment,social.endorsement, compliance.incident, compliance.violation

Invoices

Create, send, and manage invoices. Supports both crypto and card payments when the merchant has Stripe Connect configured.

Create Invoice

Create a new invoice

const invoice = await client.invoices.create({
  business_id: 'your-business-id',
  amount: 500.00,
  currency: 'USD',
  crypto_currency: 'SOL',          // optional
  client_id: 'client-uuid',        // optional
  due_date: '2026-04-15',          // optional
  notes: 'Web development work',   // optional
});

console.log('Invoice:', invoice.invoiceNumber); // INV-001
console.log('Status:', invoice.status);         // draft

Send Invoice

Send invoice to client (generates payment link)

const result = await client.invoices.send(invoice.id);

// Payment link for the client:
console.log('Pay URL:', result.payUrl);
// If merchant has Stripe Connect, card payment is also available
console.log('Stripe URL:', result.stripeCheckoutUrl);

List & Filter Invoices

List invoices with filters

// All invoices
const all = await client.invoices.list();

// Filter by status and business
const sent = await client.invoices.list({
  status: 'sent',
  business_id: 'your-business-id',
});

// Filter by date range
const recent = await client.invoices.list({
  date_from: '2026-03-01',
  date_to: '2026-03-31',
});

Update & Delete

Update or delete draft invoices

// Update a draft invoice
await client.invoices.update(invoice.id, {
  amount: 750.00,
  notes: 'Updated scope',
  due_date: '2026-05-01',
});

// Delete a draft invoice
await client.invoices.delete(invoice.id);

Get Payment Data (Public)

Get payment data for an invoice (no auth required)

// This endpoint is public — used by the pay page
const payData = await client.invoices.getPaymentData(invoiceId);

console.log('Amount:', payData.amount);
console.log('Crypto address:', payData.paymentAddress);
console.log('Card checkout:', payData.stripeCheckoutUrl);

Invoice Statuses

draftsentpaid | overdue | cancelled

Invoices can be paid via crypto (monitored automatically) or card (via Stripe Checkout). Platform fee: 0.5% (Professional) or 1% (Starter) — applied to both payment methods.