torque-checkout
v3.1.0
Published
Official Torque checkout SDK for seamless eCommerce integrations with Next.js
Maintainers
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.
Table of Contents
- Features
- Installation
- Quick Start
- Documentation
- Examples
- TypeScript
- Error Handling
- Security
- Troubleshooting
- Migration Guide
- Support
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-checkoutRequirements
- 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_key4. 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
- Visit Torque Business Dashboard
- Connect your wallet (MetaMask, WalletConnect, etc.)
- Complete your business profile:
- Business name, email, website
- Payment wallet address (where payments will be sent)
- Save your profile - API credentials are generated automatically
- Copy your credentials from the API Integration section:
Business IDAPI 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:
- Visit Products Page
- Add your products with:
- Product name, description, price
- Product images
- Shipping settings, tax rates
- Inventory (if applicable)
- Copy the Torque Product ID for each product
- Product IDs look like:
j1234567890abcdef - These are generated automatically when you create products
- Product IDs look like:
- 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.fiSecurity: Never commit
.env.localto 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 = checkoutUrlOption 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 = checkoutUrlDocumentation
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
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()Use environment variables
# .env.local (never commit) TORQUE_BUSINESS_ID=your_business_id TORQUE_API_KEY=your_api_keyValidate user input
// Always validate before sending to API if (!cart.items || cart.items.length === 0) { throw new Error('Cart is empty') }Use HTTPS in production
- Always use HTTPS for checkout URLs
- Never send sensitive data over HTTP
Verify webhook signatures
export const POST = handleWebhook({ secret: process.env.TORQUE_WEBHOOK_SECRET })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_KEYOr 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:
- Verify business ID in Business Settings
- Check environment variable is correct
- Ensure business profile is saved and active
Issue: "Products not found" or "Invalid products"
Solution:
- Upload products to Torque first at Products Page
- Ensure products have status "active"
- Verify product IDs in your cart match Torque product IDs
- Check that products belong to your business
Issue: "Invalid API key" or "Unauthorized"
Solution:
- Verify API key in Business Settings
- Ensure API key is included in
Authorization: Bearer YOUR_API_KEYheader - Check that API key matches the business ID you're using
- 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 varsAPI Reference
For complete API documentation, visit:
- Full API Docs: https://docs.torque.fi/api
- Integration Guide: https://docs.torque.fi/integrations
Support
- Documentation: https://docs.torque.fi
- Email: [email protected]
- GitHub Issues: https://github.com/torque-fi/torque-checkout/issues
- Business Dashboard: https://app.torque.fi/business/settings
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:
- Upload products to Torque at
/business/products - Get Torque product IDs (manually or programmatically)
- Store Torque product IDs in your ecommerce database
- Use Torque product IDs in cart items when calling the SDK
- Torque validates all products exist and are active
- 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:
- Visit Products Page
- Copy each product ID (e.g.,
j1234567890abcdef) - 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:
- Manual trigger: Call sync API endpoint when needed
- Scheduled: Set up a cron job to sync daily
- Webhook (coming soon): Auto-sync when products change in Torque
- 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
