npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

torque-checkout

v3.1.0

Published

Official Torque checkout SDK for seamless eCommerce integrations with Next.js

Readme

Torque Checkout SDK

Official Torque checkout SDK for seamless eCommerce integrations with Next.js

The easiest way to integrate Torque checkout into your Next.js eCommerce application. Accept crypto payments with just a few lines of code.

npm version npm downloads License: MIT TypeScript

Table of Contents

Features

  • Lightweight & Fast - Minimal bundle size (~40KB), optimized for performance
  • Zero Configuration - Works out of the box with environment variables
  • TypeScript First - Full TypeScript support with comprehensive types and IntelliSense
  • React Hooks - Built-in React hooks for seamless client-side integration
  • Next.js Optimized - Server-side utilities for App Router and Pages Router
  • Production Ready - Comprehensive error handling, validation, and retry logic
  • Multi-Product Support - Handle complex carts with multiple items and variants
  • Subscription Support - Built-in subscription and recurring payment management
  • Universal - Works in browser, Node.js, and edge environments

Installation

npm install torque-checkout
# or
yarn add torque-checkout
# or
pnpm add torque-checkout

Requirements

  • Node.js: >= 16.0.0
  • Next.js: >= 13.0.0 (for Next.js utilities)
  • React: >= 16.8.0 (for React hooks, optional)

Quick Start

Get Checkout Working in 4 Steps

1. Install & Get Credentials

npm install torque-checkout
# or
yarn add torque-checkout
# or
pnpm add torque-checkout
  • Visit https://app.torque.fi/business/settings
  • Connect wallet, complete profile, set payment wallet
  • Copy Business ID and API Key

2. Upload Products to Torque

  • Visit https://app.torque.fi/business/products
  • Add your products (name, price, description, images, etc.)
  • Copy the Torque Product ID for each product (e.g., j1234567890abcdef)
  • Store these IDs in your ecommerce database (e.g., product.torqueProductId)

Important: Products must be uploaded to Torque first. The SDK validates that all product IDs exist in your Torque product catalog.

3. Add Environment Variables Create .env.local:

TORQUE_BUSINESS_ID=your_business_id
TORQUE_API_KEY=your_api_key

4. Add Checkout Button

'use client'
import { useTorqueCheckout } from 'torque-checkout/react'

export default function CheckoutButton({ torqueProductId }: { torqueProductId: string }) {
  const { generateProductCheckout, isLoading } = useTorqueCheckout({
    autoRedirect: true
  })

  return (
    <button
      onClick={() => generateProductCheckout(torqueProductId, 1, {
        email: '[email protected]'
      })}
      disabled={isLoading}
    >
      {isLoading ? 'Loading...' : 'Buy Now'}
    </button>
  )
}

Done! Customer clicks → Redirects to checkout → Payment goes to your wallet.


Detailed Setup

Step 1: Get Your API Credentials

  1. Visit Torque Business Dashboard
  2. Connect your wallet (MetaMask, WalletConnect, etc.)
  3. Complete your business profile:
    • Business name, email, website
    • Payment wallet address (where payments will be sent)
  4. Save your profile - API credentials are generated automatically
  5. Copy your credentials from the API Integration section:
    • Business ID
    • API Key

Tip: Your payment wallet address is set once in business settings. All successful payments automatically go to this wallet - no code needed!

Step 1.5: Upload Products to Torque

Before using the SDK, you must upload your products to Torque:

  1. Visit Products Page
  2. Add your products with:
    • Product name, description, price
    • Product images
    • Shipping settings, tax rates
    • Inventory (if applicable)
  3. Copy the Torque Product ID for each product
    • Product IDs look like: j1234567890abcdef
    • These are generated automatically when you create products
  4. Store Product IDs in your database
    • Link your ecommerce products to Torque products
    • Example: product.torqueProductId = "j1234567890abcdef"

Why? Torque products are the source of truth for prices, names, and product data. This ensures consistency and prevents price manipulation. Similar to how Stripe requires Products/Prices to be created before using Payment Links.

Step 2: Configure Environment Variables

Create a .env.local file in your Next.js project root:

# Required
TORQUE_BUSINESS_ID=your_business_id_here
TORQUE_API_KEY=your_api_key_here

# Optional (defaults to production)
TORQUE_BASE_URL=https://app.torque.fi

Security: Never commit .env.local to version control. Add it to .gitignore.

Step 3: Choose Your Integration Method

Option A: React Hook (Client-Side) - Recommended for Most Cases

'use client'

import { useTorqueCheckout } from 'torque-checkout/react'

export default function CheckoutButton() {
  const { generateProductCheckout, isLoading } = useTorqueCheckout({
    autoRedirect: true // Automatically redirects to checkout
  })

  return (
    <button
      onClick={() => generateProductCheckout('prod_123', 1, {
        email: '[email protected]'
      })}
      disabled={isLoading}
    >
      {isLoading ? 'Loading...' : 'Buy Now'}
    </button>
  )
}

Option B: Server-Side API Route (Most Secure)

// app/api/checkout/route.ts
import { handleCheckoutRequest } from 'torque-checkout/nextjs'

export const POST = handleCheckoutRequest()

Then call from your frontend:

const response = await fetch('/api/checkout', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    items: [{ productId: 'prod_123', quantity: 1 }],
    customer: { email: '[email protected]' }
  })
})

const { checkoutUrl } = await response.json()
window.location.href = checkoutUrl

Option C: Direct SDK Usage

import { createTorqueCheckoutFromEnv } from 'torque-checkout'

const torque = createTorqueCheckoutFromEnv()

const checkoutUrl = await torque.generateCartCheckoutUrl({
  items: [{ productId: 'prod_123', quantity: 1 }],
  customer: { email: '[email protected]' }
})

window.location.href = checkoutUrl

Documentation

Core SDK

Initialization

import { createTorqueCheckout, createTorqueCheckoutFromEnv } from 'torque-checkout'

// Method 1: From environment variables (recommended)
const torque = createTorqueCheckoutFromEnv()

// Method 2: Explicit configuration
const torque = createTorqueCheckout({
  businessId: process.env.TORQUE_BUSINESS_ID!,
  apiKey: process.env.TORQUE_API_KEY!,
  baseUrl: 'https://app.torque.fi', // Optional
  timeout: 30000 // Optional, default: 30000ms
})

Methods

generateCartCheckoutUrl(cart: CartData): Promise<string>

Generate a checkout URL for a multi-product cart.

const checkoutUrl = await torque.generateCartCheckoutUrl({
  items: [
    { 
      productId: 'j1234567890abcdef', // Torque product ID (required)
      quantity: 2, 
      variant: 'large', // Optional: product variant ID
      metadata: { customField: 'value' } // Optional: custom data
      // Note: price is NOT included - prices come from Torque product database
    },
    { productId: 'j0987654321fedcba', quantity: 1 } // Another Torque product ID
  ],
  customer: {
    email: '[email protected]', // Required
    firstName: 'John', // Optional
    lastName: 'Doe', // Optional
    phone: '+1234567890', // Optional
    shippingAddress: { // Optional: pre-fill shipping
      street: '123 Main St',
      city: 'New York',
      state: 'NY',
      zipCode: '10001',
      country: 'US'
    }
  },
  options: {
    metadata: { orderId: 'order_123', source: 'website' }, // Optional
    expiresIn: 24 * 60 * 60 * 1000, // Optional: 24 hours
    redirectUrl: 'https://yoursite.com/thank-you' // Optional
  }
})
generateProductCheckoutUrl(productId, quantity?, customer?, options?): Promise<string>

Quick method for single product checkout.

const checkoutUrl = await torque.generateProductCheckoutUrl(
  'j1234567890abcdef', // Torque product ID (must exist in your Torque product catalog)
  2, // Quantity (default: 1)
  { email: '[email protected]' }, // Customer data (optional)
  { redirectUrl: 'https://yoursite.com/success' } // Options (optional)
)
generateSubscriptionCheckoutUrl(productId, paymentPlanId, customer?, options?): Promise<string>

Generate checkout for subscription products.

const checkoutUrl = await torque.generateSubscriptionCheckoutUrl(
  'prod_subscription_123', // Subscription product ID
  'plan_monthly_123', // Payment plan ID
  { email: '[email protected]' },
  { redirectUrl: 'https://yoursite.com/subscription-success' }
)
validateCart(cart: CartData): Promise<CartValidation>

Validate cart before checkout to catch errors early.

const validation = await torque.validateCart({
  items: [{ productId: 'prod_123', quantity: 2 }]
})

if (validation.valid) {
  console.log('Cart is valid')
  console.log('Estimated total:', validation.estimatedTotal)
} else {
  console.error('Validation errors:', validation.errors)
  console.warn('Warnings:', validation.warnings)
}
getOrderStatus(orderId: string): Promise<OrderStatus>

Check order status after checkout.

const order = await torque.getOrderStatus('order_123')

console.log('Status:', order.status) // e.g., 'completed', 'pending', 'failed'
console.log('Total:', order.totals.total)
console.log('Payment status:', order.paymentStatus)
console.log('Items:', order.items)
getProducts(businessId?, status?): Promise<Product[]>

Get all products for a business. Use this to sync your ecommerce catalog with Torque products.

// Get all active products
const products = await torque.getProducts(undefined, 'active')

// Get all products (any status)
const allProducts = await torque.getProducts()

// Get products for specific business
const businessProducts = await torque.getProducts('business_123', 'active')

// Sync with your database
products.forEach(product => {
  console.log(`Product: ${product.name} (ID: ${product.id})`)
  // Store product.id in your database as torqueProductId
})
getProduct(productId: string): Promise<Product>

Get a single product by ID.

const product = await torque.getProduct('j1234567890abcdef')

console.log('Product:', product.name)
console.log('Price:', product.price)
console.log('Status:', product.status)
getSubscriptionProducts(businessId?): Promise<SubscriptionProduct[]>

Get all subscription products for a business.

const subscriptions = await torque.getSubscriptionProducts()

subscriptions.forEach(sub => {
  console.log(`Subscription: ${sub.name}`)
  console.log('Payment plans:', sub.paymentPlans)
})

React Hooks

useTorqueCheckout(options?)

React hook for client-side checkout with built-in state management.

import { useTorqueCheckout } from 'torque-checkout/react'

function CheckoutButton() {
  const {
    generateCheckout,
    generateProductCheckout,
    generateSubscriptionCheckout,
    validateCart,
    getOrderStatus,
    isLoading,
    error,
    checkoutUrl
  } = useTorqueCheckout({
    // Optional: explicit config (or use env vars)
    // config: {
    //   businessId: 'your_business_id',
    //   apiKey: 'your_api_key'
    // },
    autoRedirect: true, // Auto-redirect to checkout URL
    onSuccess: (url) => {
      console.log('Checkout URL generated:', url)
      // Optional: track analytics
    },
    onError: (error) => {
      console.error('Checkout error:', error)
      // Optional: show error toast
    }
  })

  const handleCheckout = async () => {
    const url = await generateProductCheckout('prod_123', 1, {
      email: '[email protected]'
    })
    // If autoRedirect is false, you can handle the URL manually
    if (url && !autoRedirect) {
      window.location.href = url
    }
  }

  return (
    <div>
      <button onClick={handleCheckout} disabled={isLoading}>
        {isLoading ? 'Processing...' : 'Checkout'}
      </button>
      {error && <p className="error">{error.message}</p>}
      {checkoutUrl && <p>Checkout URL: {checkoutUrl}</p>}
    </div>
  )
}

useCart()

Shopping cart state management hook.

import { useCart } from 'torque-checkout/react'

function ShoppingCart() {
  const {
    items,
    addItem,
    removeItem,
    updateQuantity,
    clearCart,
    getTotal,
    getItemCount
  } = useCart()

  return (
    <div>
      <h2>Shopping Cart ({getItemCount()} items)</h2>
      
      {items.map(item => (
        <div key={`${item.productId}-${item.variant || ''}`}>
          <span>Product {item.productId}</span>
          <span>Quantity: {item.quantity}</span>
          <button onClick={() => updateQuantity(item.productId, item.quantity + 1, item.variant)}>
            +
          </button>
          <button onClick={() => updateQuantity(item.productId, item.quantity - 1, item.variant)}>
            -
          </button>
          <button onClick={() => removeItem(item.productId, item.variant)}>
            Remove
          </button>
        </div>
      ))}
      
      <p>Total: ${getTotal().toFixed(2)}</p>
      <button onClick={clearCart}>Clear Cart</button>
    </div>
  )
}

Next.js Server Utilities

handleCheckoutRequest(options?)

Complete API route handler with error handling.

// app/api/checkout/route.ts
import { handleCheckoutRequest } from 'torque-checkout/nextjs'

export const POST = handleCheckoutRequest({
  onSuccess: async (checkoutUrl, cart) => {
    // Optional: Log, track analytics, send notifications
    console.log('Checkout generated:', checkoutUrl)
    await logCheckoutEvent(cart)
  },
  onError: async (error, cart) => {
    // Optional: Error logging, notifications
    console.error('Checkout error:', error)
    await logError(error, cart)
  }
})

handleWebhook(options?)

Webhook handler for order events.

// app/api/webhooks/torque/route.ts
import { handleWebhook } from 'torque-checkout/nextjs'

export const POST = handleWebhook({
  secret: process.env.TORQUE_WEBHOOK_SECRET, // Optional: verify signatures
  onOrderCompleted: async (event) => {
    // Fulfill order
    await fulfillOrder(event.orderId!)
    await sendConfirmationEmail(event.data.customerEmail)
  },
  onOrderFailed: async (event) => {
    // Handle failed payment
    await notifyCustomer(event.orderId!)
  },
  onSubscriptionCreated: async (event) => {
    // Activate subscription
    await activateSubscription(event.subscriptionId!)
  }
})

generateCheckoutUrl(cart, config?)

Server-side checkout URL generation.

// app/api/checkout/route.ts
import { generateCheckoutUrl } from 'torque-checkout/nextjs'

export async function POST(request: Request) {
  const cart = await request.json()
  
  try {
    const checkoutUrl = await generateCheckoutUrl(cart)
    return Response.json({ checkoutUrl })
  } catch (error: any) {
    return Response.json(
      { error: error.message, code: error.code },
      { status: error.statusCode || 500 }
    )
  }
}

Complete Examples

E-Commerce Product Page

// app/products/[id]/page.tsx
'use client'

import { useTorqueCheckout, useCart } from 'torque-checkout/react'
import { useState } from 'react'

// Example: Your product data from your database
interface Product {
  id: string
  name: string
  torqueProductId: string // Torque product ID (uploaded to Torque first)
  // ... other product fields
}

export default function ProductPage({ product }: { product: Product }) {
  const cart = useCart()
  const { generateProductCheckout, isLoading } = useTorqueCheckout({
    autoRedirect: true
  })
  const [quantity, setQuantity] = useState(1)

  const handleAddToCart = () => {
    cart.addItem({
      productId: product.torqueProductId, // Use Torque product ID
      quantity
      // Note: price is NOT included - prices come from Torque
    })
  }

  const handleBuyNow = async () => {
    await generateProductCheckout(
      product.torqueProductId, // Use Torque product ID
      quantity,
      {
        email: '[email protected]' // Get from auth/session
      }
    )
  }

  return (
    <div>
      <h1>{product.name}</h1>
      {/* Price displayed from your DB, but checkout uses Torque price */}
      
      <div>
        <label>Quantity:</label>
        <input
          type="number"
          value={quantity}
          onChange={(e) => setQuantity(Number(e.target.value))}
          min="1"
        />
      </div>
      
      <button onClick={handleAddToCart}>
        Add to Cart ({cart.getItemCount()} items)
      </button>
      
      <button onClick={handleBuyNow} disabled={isLoading}>
        {isLoading ? 'Processing...' : 'Buy Now'}
      </button>
    </div>
  )
}

Shopping Cart with Checkout

// app/cart/page.tsx
'use client'

import { useTorqueCheckout, useCart } from 'torque-checkout/react'

export default function CartPage() {
  const cart = useCart()
  const { generateCheckout, isLoading } = useTorqueCheckout()

  const handleCheckout = async () => {
    const url = await generateCheckout({
      items: cart.items.map(item => ({
        productId: item.productId, // Torque product ID
        quantity: item.quantity,
        variant: item.variant,
        metadata: item.metadata
        // Note: price is NOT included - prices come from Torque
      })),
      customer: {
        email: '[email protected]' // Get from auth
      },
      options: {
        redirectUrl: window.location.origin + '/thank-you'
      }
    })
    
    if (url) {
      window.location.href = url
    }
  }

  if (cart.items.length === 0) {
    return <p>Your cart is empty</p>
  }

  return (
    <div>
      <h1>Shopping Cart</h1>
      {cart.items.map(item => (
        <div key={`${item.productId}-${item.variant || ''}`}>
          <span>Product {item.productId}</span>
          <span>Qty: {item.quantity}</span>
          {/* Note: Prices shown here are estimates. Final prices come from Torque at checkout */}
          <button onClick={() => cart.removeItem(item.productId, item.variant)}>
            Remove
          </button>
        </div>
      ))}
      <button onClick={handleCheckout} disabled={isLoading}>
        {isLoading ? 'Processing...' : 'Proceed to Checkout'}
      </button>
    </div>
  )
}

Server Component Checkout (Next.js 13+)

// app/checkout/page.tsx
import { createTorqueCheckoutFromEnv } from 'torque-checkout'
import { redirect } from 'next/navigation'
import { cookies } from 'next/headers'

export default async function CheckoutPage({
  searchParams
}: {
  searchParams: { productId: string; quantity?: string }
}) {
  const torque = createTorqueCheckoutFromEnv()
  
  // Get customer email from session/cookies
  const customerEmail = cookies().get('user_email')?.value || '[email protected]'
  
  const checkoutUrl = await torque.generateProductCheckoutUrl(
    searchParams.productId,
    Number(searchParams.quantity) || 1,
    { email: customerEmail }
  )

  redirect(checkoutUrl)
}

Pages Router API Route

// pages/api/checkout.ts
import type { NextApiRequest, NextApiResponse } from 'next'
import { createTorqueCheckoutFromEnv } from 'torque-checkout'

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method not allowed' })
  }

  try {
    const torque = createTorqueCheckoutFromEnv()
    const checkoutUrl = await torque.generateCartCheckoutUrl(req.body)

    res.status(200).json({ checkoutUrl })
  } catch (error: any) {
    res.status(error.statusCode || 500).json({
      error: error.message,
      code: error.code
    })
  }
}

TypeScript

Full TypeScript support with comprehensive types:

import type {
  // Cart types
  CartItem,
  CartData,
  CartOptions,
  CartValidation,
  
  // Customer types
  CustomerData,
  
  // Product types
  Product,
  SubscriptionProduct,
  PaymentPlan,
  
  // Order types
  OrderStatus,
  CheckoutResponse,
  
  // Subscription types
  Subscription,
  CreateSubscriptionData,
  UpdateSubscriptionData,
  
  // Config types
  TorqueConfig,
  TorqueCheckoutError
} from 'torque-checkout'

Type-Safe Usage

import { createTorqueCheckout } from 'torque-checkout'
import type { CartData, CustomerData } from 'torque-checkout'

const torque = createTorqueCheckout({
  businessId: process.env.TORQUE_BUSINESS_ID!,
  apiKey: process.env.TORQUE_API_KEY!
})

const cart: CartData = {
  items: [
    { productId: 'j1234567890abcdef', quantity: 1 } // Torque product ID
  ],
  customer: {
    email: '[email protected]'
  } as CustomerData
}

const url: string = await torque.generateCartCheckoutUrl(cart)

Error Handling

The SDK uses custom error classes for better error handling:

import { TorqueCheckoutError } from 'torque-checkout'

try {
  const url = await torque.generateCartCheckoutUrl(cart)
} catch (error) {
  if (error instanceof TorqueCheckoutError) {
    console.error('Error code:', error.code)
    console.error('Status code:', error.statusCode)
    console.error('Details:', error.details)
    
    // Handle specific error codes
    switch (error.code) {
      case 'VALIDATION_ERROR':
        // Show validation errors to user
        showErrors(error.details?.errors)
        break
      case 'UNAUTHORIZED':
      case 'INVALID_API_KEY':
        // API key authentication failed
        console.error('Invalid API key. Check your TORQUE_API_KEY environment variable.')
        break
      case 'PRODUCTS_NOT_FOUND':
        // Products don't exist in Torque database
        console.error('Products not found:', error.details?.missingProductIds)
        console.error('Upload products to Torque first at /business/products')
        break
      case 'INVALID_PRODUCTS':
        // Products are inactive or belong to different business
        console.error('Invalid products:', error.details?.invalidProductIds)
        break
      case 'BUSINESS_NOT_FOUND':
        // Check business ID configuration
        console.error('Invalid business ID')
        break
      case 'TIMEOUT':
        // Retry or show timeout message
        retryCheckout()
        break
      case 'NETWORK_ERROR':
        // Check internet connection
        showNetworkError()
        break
      default:
        // Generic error handling
        showGenericError(error.message)
    }
  } else {
    // Unknown error
    console.error('Unexpected error:', error)
  }
}

Common Error Codes

| Code | Description | Solution | |------|-------------|----------| | VALIDATION_ERROR | Cart validation failed | Check cart items and customer data | | UNAUTHORIZED | Missing or invalid API key | Include Authorization: Bearer YOUR_API_KEY header | | INVALID_API_KEY | Invalid API key | Verify TORQUE_API_KEY in environment variables | | PRODUCTS_NOT_FOUND | Products don't exist in Torque | Upload products to Torque first at /business/products | | INVALID_PRODUCTS | Products inactive or wrong business | Ensure products are active and belong to your business | | BUSINESS_NOT_FOUND | Invalid business ID | Verify TORQUE_BUSINESS_ID | | BUSINESS_INACTIVE | Business is not active | Activate your business in settings | | TIMEOUT | Request timed out | Check network, increase timeout | | NETWORK_ERROR | Network request failed | Check internet connection | | ORDER_NOT_FOUND | Order doesn't exist | Verify order ID |

Security Best Practices

  1. Never expose API keys in client-side code

    // BAD - Don't do this
    const torque = createTorqueCheckout({
      businessId: 'business_123',
      apiKey: 'sk_live_...' // Exposed in browser!
    })
       
    // GOOD - Use server-side API routes
    // app/api/checkout/route.ts
    export const POST = handleCheckoutRequest()
  2. Use environment variables

    # .env.local (never commit)
    TORQUE_BUSINESS_ID=your_business_id
    TORQUE_API_KEY=your_api_key
  3. Validate user input

    // Always validate before sending to API
    if (!cart.items || cart.items.length === 0) {
      throw new Error('Cart is empty')
    }
  4. Use HTTPS in production

    • Always use HTTPS for checkout URLs
    • Never send sensitive data over HTTP
  5. Verify webhook signatures

    export const POST = handleWebhook({
      secret: process.env.TORQUE_WEBHOOK_SECRET
    })
  6. Set payment wallet in business settings

    • Payments automatically go to your configured wallet
    • No need to handle wallet addresses in code

Troubleshooting

Issue: "TorqueCheckout not initialized"

Solution: Make sure environment variables are set:

# Check if variables are loaded
echo $TORQUE_BUSINESS_ID
echo $TORQUE_API_KEY

Or provide explicit config:

const torque = createTorqueCheckout({
  businessId: 'your_business_id',
  apiKey: 'your_api_key'
})

Issue: "Request timeout"

Solution: Increase timeout or check network:

const torque = createTorqueCheckout({
  businessId: process.env.TORQUE_BUSINESS_ID!,
  apiKey: process.env.TORQUE_API_KEY!,
  timeout: 60000 // 60 seconds
})

Issue: "Business not found"

Solution:

  1. Verify business ID in Business Settings
  2. Check environment variable is correct
  3. Ensure business profile is saved and active

Issue: "Products not found" or "Invalid products"

Solution:

  1. Upload products to Torque first at Products Page
  2. Ensure products have status "active"
  3. Verify product IDs in your cart match Torque product IDs
  4. Check that products belong to your business

Issue: "Invalid API key" or "Unauthorized"

Solution:

  1. Verify API key in Business Settings
  2. Ensure API key is included in Authorization: Bearer YOUR_API_KEY header
  3. Check that API key matches the business ID you're using
  4. Regenerate API key if needed

Issue: React hooks not working

Solution: Make sure you're using the React entry point:

// Correct
import { useTorqueCheckout } from 'torque-checkout/react'

// Wrong
import { useTorqueCheckout } from 'torque-checkout'

Issue: TypeScript errors

Solution: Make sure TypeScript can find the types:

// tsconfig.json
{
  "compilerOptions": {
    "moduleResolution": "node",
    "esModuleInterop": true
  }
}

Migration Guide

From v1.x to v2.0.0

v2.0.0 is backward compatible with v1.x. No code changes required!

New features available (optional):

  • React hooks: useTorqueCheckout(), useCart()
  • Next.js utilities: handleCheckoutRequest(), handleWebhook()
  • Environment variable support: createTorqueCheckoutFromEnv()

Migration example:

// v1.x (still works)
import { TorqueCheckout } from 'torque-checkout'
const torque = new TorqueCheckout({ businessId, apiKey })

// v2.0.0 (new, optional)
import { createTorqueCheckoutFromEnv } from 'torque-checkout'
const torque = createTorqueCheckoutFromEnv() // Uses env vars

API Reference

For complete API documentation, visit:

Support

License

MIT © Torque

Product Sync Guide

How Product Sync Works

Torque products are the source of truth for checkout. Similar to Stripe's Products/Prices model:

  1. Upload products to Torque at /business/products
  2. Get Torque product IDs (manually or programmatically)
  3. Store Torque product IDs in your ecommerce database
  4. Use Torque product IDs in cart items when calling the SDK
  5. Torque validates all products exist and are active
  6. Checkout uses product data (prices, names) from Torque database

Step-by-Step Integration Flow

Step 1: Add Products to Torque

  • Visit Products Page
  • Add your products with name, price, description, images, etc.
  • Torque automatically generates a Product ID (e.g., j1234567890abcdef)

Step 2: Sync Product IDs to Your Database

You have two options:

Option A: Programmatic Sync (Recommended)

Use the SDK to fetch all products from Torque and sync them with your database:

import { createTorqueCheckoutFromEnv } from 'torque-checkout'

// Server-side: Sync products
async function syncProducts() {
  const torque = createTorqueCheckoutFromEnv()
  
  // Fetch all active products from Torque
  const torqueProducts = await torque.getProducts(undefined, 'active')
  
  // Sync with your database
  for (const torqueProduct of torqueProducts) {
    // Match by SKU, name, or your internal ID
    await db.product.upsert({
      where: { sku: torqueProduct.sku }, // or match by name/ID
      update: {
        torqueProductId: torqueProduct.id, // Store Torque product ID
        torquePrice: torqueProduct.price,
        torqueStatus: torqueProduct.status,
        // ... other fields
      },
      create: {
        sku: torqueProduct.sku || `torque_${torqueProduct.id}`,
        name: torqueProduct.name,
        torqueProductId: torqueProduct.id,
        torquePrice: torqueProduct.price,
        // ... other fields
      }
    })
  }
  
  console.log(`Synced ${torqueProducts.length} products`)
}

Run this sync:

  • On initial setup
  • Periodically (cron job, webhook, or scheduled task)
  • After adding new products in Torque

Option B: Manual Copy-Paste

For small catalogs, manually copy product IDs:

  1. Visit Products Page
  2. Copy each product ID (e.g., j1234567890abcdef)
  3. Store in your database: product.torqueProductId = "j1234567890abcdef"

Step 3: Use Torque Product IDs in Checkout

// Your ecommerce product
interface Product {
  id: string // Your internal product ID
  name: string
  price: number
  torqueProductId: string // Torque product ID (synced from Step 2)
  sku?: string
}

// When customer adds to cart
const cartItem = {
  productId: product.torqueProductId, // ✅ Use Torque ID
  quantity: 2
  // ❌ Don't include price - it comes from Torque
}

// Generate checkout
const checkoutUrl = await torque.generateCartCheckoutUrl({
  items: [cartItem],
  customer: { email: '[email protected]' }
})

Complete Sync Example

// app/api/sync-products/route.ts
import { createTorqueCheckoutFromEnv } from 'torque-checkout'
import { NextResponse } from 'next/server'

export async function POST() {
  try {
    const torque = createTorqueCheckoutFromEnv()
    
    // Get all active products from Torque
    const torqueProducts = await torque.getProducts(undefined, 'active')
    
    // Sync to your database
    const results = await Promise.all(
      torqueProducts.map(async (torqueProduct) => {
        // Match by SKU if available, otherwise by name
        const matchKey = torqueProduct.sku || torqueProduct.name
        
        return await db.product.upsert({
          where: { 
            OR: [
              { sku: matchKey },
              { name: torqueProduct.name },
              { torqueProductId: torqueProduct.id }
            ]
          },
          update: {
            torqueProductId: torqueProduct.id,
            torquePrice: torqueProduct.price,
            torqueStatus: torqueProduct.status,
            torqueUpdatedAt: new Date(torqueProduct.updatedAt)
          },
          create: {
            name: torqueProduct.name,
            description: torqueProduct.description,
            sku: torqueProduct.sku || `torque_${torqueProduct.id}`,
            torqueProductId: torqueProduct.id,
            torquePrice: torqueProduct.price,
            torqueStatus: torqueProduct.status,
            // ... other fields
          }
        })
      })
    )
    
    return NextResponse.json({
      success: true,
      synced: results.length,
      products: results
    })
  } catch (error) {
    return NextResponse.json(
      { error: error instanceof Error ? error.message : 'Sync failed' },
      { status: 500 }
    )
  }
}

Keeping Products in Sync

When to sync:

  • ✅ Initial setup
  • ✅ After adding products in Torque
  • ✅ Periodically (daily/weekly cron job)
  • ✅ After updating product prices in Torque

Sync strategies:

  1. Manual trigger: Call sync API endpoint when needed
  2. Scheduled: Set up a cron job to sync daily
  3. Webhook (coming soon): Auto-sync when products change in Torque
  4. On-demand: Sync before checkout to ensure latest prices

Matching Products

When syncing, match Torque products to your products by:

  • SKU (recommended): Most reliable if you use SKUs
  • Product name: If names are unique
  • Torque Product ID: If already synced before
  • Custom metadata: Store your internal ID in Torque product metadata

Getting Started Checklist

  • [ ] Install: npm install torque-checkout
  • [ ] Create business profile: app.torque.fi/business/settings
  • [ ] Set payment wallet address in business settings
  • [ ] Copy Business ID and API Key
  • [ ] Upload products to Torque: app.torque.fi/business/products
  • [ ] Store Torque product IDs in your database
  • [ ] Add environment variables to .env.local
  • [ ] Import and use the SDK with Torque product IDs
  • [ ] Test checkout flow
  • [ ] Deploy to production!

Made with love by Torque