Shopify Integration
Integrate Torque's multi-product checkout with your Shopify store to provide seamless checkout experiences for your customers.
Quick Start
1. Install Torque App
- Visit Shopify App Store: Go to apps.shopify.com
- Search for Torque: Find "Torque Checkout" app
- Install App: Click "Add app" and follow the installation process
- Connect Account: Link your Torque business account
2. Configure Settings
- API Credentials: Enter your Torque Business ID and API Key
- Checkout Options: Configure checkout appearance and behavior
- Webhook Setup: Enable real-time order updates
- Test Mode: Verify integration in sandbox environment
3. Go Live
- Production Mode: Switch from test to live mode
- Monitor Orders: Track checkout performance
- Customer Support: Provide seamless customer experience
Manual Integration
App Installation
If you prefer manual integration, follow these steps:
Step 1: Create Torque Business Account
- Sign Up: Visit torque.fi/business
- Complete Profile: Fill out business information
- Get Credentials: Note your Business ID and API Key
Step 2: Install Torque Package
npm install torque-checkout
# or
yarn add torque-checkout
Step 3: Configure Shopify App
Create a new Shopify app in your partner dashboard:
// config/shopify.js
const shopifyConfig = {
apiKey: process.env.SHOPIFY_API_KEY,
apiSecret: process.env.SHOPIFY_API_SECRET,
scopes: ['read_products', 'read_orders', 'write_orders'],
redirectUrl: 'https://yourdomain.com/auth/callback'
};
export default shopifyConfig;
Cart Integration
Convert Shopify Cart to Torque Format
// utils/cartConverter.js
export function convertShopifyCartToTorque(shopifyCart) {
return {
items: shopifyCart.line_items.map(item => ({
productId: item.product_id.toString(),
quantity: item.quantity,
price: parseFloat(item.price),
variant: item.variant_title || null,
metadata: {
sku: item.sku,
variantId: item.variant_id,
productTitle: item.title
}
})),
currency: shopifyCart.currency,
discounts: shopifyCart.discount_codes.map(discount => ({
code: discount.code,
amount: parseFloat(discount.amount),
type: discount.type === 'percentage' ? 'percentage' : 'fixed'
}))
};
}
// Usage
const torqueCart = convertShopifyCartToTorque(shopifyCart);
Generate Checkout Link
// services/torqueService.js
import { TorqueCheckout } from 'torque-checkout';
class TorqueService {
constructor() {
this.torque = new TorqueCheckout({
businessId: process.env.TORQUE_BUSINESS_ID,
apiKey: process.env.TORQUE_API_KEY
});
}
async generateCheckoutLink(shopifyCart, customerData) {
try {
const torqueCart = convertShopifyCartToTorque(shopifyCart);
const { checkoutUrl } = await this.torque.generateCheckoutLink(
torqueCart,
customerData,
{
expiresIn: 3600,
redirectUrl: `${process.env.SHOP_URL}/thank-you`,
webhookUrl: `${process.env.APP_URL}/webhooks/torque`
}
);
return checkoutUrl;
} catch (error) {
console.error('Failed to generate checkout link:', error);
throw error;
}
}
}
export default new TorqueService();
Order Management
Handle Order Updates
// controllers/orderController.js
export async function handleOrderUpdate(req, res) {
try {
const { event, data } = req.body;
switch (event) {
case 'order.paid':
await updateShopifyOrder(data.orderId, 'paid');
break;
case 'order.completed':
await fulfillShopifyOrder(data.orderId);
break;
case 'order.cancelled':
await cancelShopifyOrder(data.orderId);
break;
}
res.json({ success: true });
} catch (error) {
console.error('Order update failed:', error);
res.status(500).json({ error: 'Processing failed' });
}
}
async function updateShopifyOrder(orderId, status) {
// Update Shopify order status
const shopifyOrder = await getShopifyOrderByTorqueId(orderId);
if (shopifyOrder) {
await shopifyApi.order.update(shopifyOrder.id, {
order: {
id: shopifyOrder.id,
financial_status: status === 'paid' ? 'paid' : 'pending'
}
});
}
}
Frontend Integration
Add Checkout Button
Liquid Template
<!-- templates/cart.liquid -->
<div class="cart-checkout-buttons">
<!-- Standard Shopify checkout -->
<button class="btn btn-primary" onclick="window.location.href='/checkout'">
Checkout with Shopify
</button>
<!-- Torque checkout -->
<button class="btn btn-secondary" onclick="initiateTorqueCheckout()">
Checkout with Torque
</button>
</div>
<script>
async function initiateTorqueCheckout() {
try {
// Get cart data
const cartData = await getCartData();
// Generate Torque checkout link
const response = await fetch('/api/torque/checkout', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(cartData)
});
if (response.ok) {
const { checkoutUrl } = await response.json();
window.location.href = checkoutUrl;
} else {
console.error('Failed to generate checkout link');
}
} catch (error) {
console.error('Checkout error:', error);
}
}
async function getCartData() {
const response = await fetch('/cart.js');
const cart = await response.json();
return {
cart: cart,
customer: {
email: '{{ customer.email }}',
firstName: '{{ customer.first_name }}',
lastName: '{{ customer.last_name }}'
}
};
}
</script>
React Component
// components/TorqueCheckout.jsx
import React, { useState } from 'react';
import { useCart } from '../hooks/useCart';
export function TorqueCheckout() {
const { cart, customer } = useCart();
const [isLoading, setIsLoading] = useState(false);
const handleTorqueCheckout = async () => {
setIsLoading(true);
try {
const response = await fetch('/api/torque/checkout', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
cart: convertCartToTorque(cart),
customerData: customer
})
});
if (response.ok) {
const { checkoutUrl } = await response.json();
window.location.href = checkoutUrl;
} else {
throw new Error('Failed to generate checkout link');
}
} catch (error) {
console.error('Checkout error:', error);
// Handle error (show notification, etc.)
} finally {
setIsLoading(false);
}
};
return (
<button
className="torque-checkout-btn"
onClick={handleTorqueCheckout}
disabled={isLoading || !cart.items.length}
>
{isLoading ? 'Preparing Checkout...' : 'Checkout with Torque'}
</button>
);
}
function convertCartToTorque(shopifyCart) {
return {
items: shopifyCart.line_items.map(item => ({
productId: item.product_id.toString(),
quantity: item.quantity,
price: parseFloat(item.price),
variant: item.variant_title,
metadata: {
sku: item.sku,
variantId: item.variant_id
}
})),
currency: shopifyCart.currency
};
}
Webhook Integration
Shopify Webhooks
Order Creation
// webhooks/shopify/orders/create.js
export async function handleOrderCreate(req, res) {
try {
const order = req.body;
// Create Torque order record
await createTorqueOrder({
shopifyOrderId: order.id,
customerData: {
email: order.email,
firstName: order.billing_address.first_name,
lastName: order.billing_address.last_name,
phone: order.billing_address.phone,
address: {
street: order.billing_address.address1,
city: order.billing_address.city,
state: order.billing_address.province,
postalCode: order.billing_address.zip,
country: order.billing_address.country_code
}
},
cart: convertShopifyOrderToTorque(order),
status: 'pending'
});
res.json({ success: true });
} catch (error) {
console.error('Order creation failed:', error);
res.status(500).json({ error: 'Processing failed' });
}
}
Order Updates
// webhooks/shopify/orders/updated.js
export async function handleOrderUpdate(req, res) {
try {
const order = req.body;
// Update Torque order
await updateTorqueOrder(order.id, {
status: mapShopifyStatusToTorque(order.financial_status),
updatedAt: new Date().toISOString()
});
res.json({ success: true });
} catch (error) {
console.error('Order update failed:', error);
res.status(500).json({ error: 'Processing failed' });
}
}
function mapShopifyStatusToTorque(shopifyStatus) {
const statusMap = {
'pending': 'pending',
'paid': 'processing',
'refunded': 'refunded',
'cancelled': 'cancelled'
};
return statusMap[shopifyStatus] || 'pending';
}
Torque Webhooks
Handle Torque Events
// webhooks/torque/order-update.js
export async function handleTorqueWebhook(req, res) {
try {
const { event, data } = req.body;
switch (event) {
case 'order.paid':
await handleOrderPaid(data);
break;
case 'order.completed':
await handleOrderCompleted(data);
break;
case 'order.cancelled':
await handleOrderCancelled(data);
break;
}
res.json({ success: true });
} catch (error) {
console.error('Torque webhook failed:', error);
res.status(500).json({ error: 'Processing failed' });
}
}
async function handleOrderPaid(data) {
const shopifyOrder = await getShopifyOrderByTorqueId(data.orderId);
if (shopifyOrder) {
// Update Shopify order status
await shopifyApi.order.update(shopifyOrder.id, {
order: {
id: shopifyOrder.id,
financial_status: 'paid',
note: `Payment confirmed via Torque. Transaction: ${data.payment.transactionId}`
}
});
}
}
📱 Complete Example
Full Integration App
// app.js
import express from 'express';
import { Shopify } from '@shopify/shopify-api';
import { TorqueCheckout } from 'torque-checkout';
import { convertShopifyCartToTorque } from './utils/cartConverter.js';
const app = express();
app.use(express.json());
// Initialize services
const shopify = new Shopify({
apiKey: process.env.SHOPIFY_API_KEY,
apiSecret: process.env.SHOPIFY_API_SECRET,
scopes: ['read_products', 'read_orders', 'write_orders']
});
const torque = new TorqueCheckout({
businessId: process.env.TORQUE_BUSINESS_ID,
apiKey: process.env.TORQUE_API_KEY
});
// Generate checkout link
app.post('/api/torque/checkout', async (req, res) => {
try {
const { cart, customerData } = req.body;
// Convert Shopify cart to Torque format
const torqueCart = convertShopifyCartToTorque(cart);
// Generate checkout link
const { checkoutUrl } = await torque.generateCheckoutLink(
torqueCart,
customerData,
{
expiresIn: 3600,
redirectUrl: `${process.env.SHOP_URL}/thank-you`,
webhookUrl: `${process.env.APP_URL}/webhooks/torque`
}
);
res.json({ checkoutUrl });
} catch (error) {
console.error('Checkout generation failed:', error);
res.status(500).json({ error: 'Failed to generate checkout link' });
}
});
// Torque webhook endpoint
app.post('/webhooks/torque', async (req, res) => {
try {
const { event, data } = req.body;
switch (event) {
case 'order.paid':
await handleOrderPaid(data);
break;
case 'order.completed':
await handleOrderCompleted(data);
break;
}
res.json({ success: true });
} catch (error) {
console.error('Webhook processing failed:', error);
res.status(500).json({ error: 'Processing failed' });
}
});
// Shopify webhook endpoints
app.post('/webhooks/shopify/orders/create', async (req, res) => {
try {
const order = req.body;
await createTorqueOrder(order);
res.json({ success: true });
} catch (error) {
console.error('Order creation failed:', error);
res.status(500).json({ error: 'Processing failed' });
}
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Torque Shopify app running on port ${PORT}`);
});
Testing
Test Mode
- Enable Test Mode: Use test API keys and sandbox environment
- Create Test Orders: Generate test checkout links
- Verify Webhooks: Test webhook delivery and processing
- Check Integration: Ensure data flows correctly between systems
Test Scenarios
- Cart Conversion: Verify Shopify cart converts to Torque format
- Checkout Flow: Test complete checkout process
- Order Sync: Confirm orders sync between platforms
- Webhook Delivery: Test real-time updates
- Error Handling: Test various error scenarios
Troubleshooting
Common Issues
Checkout Link Generation Fails
Problem: API returns error when generating checkout link
Solutions:
- Verify API credentials are correct
- Check cart data format
- Ensure all required fields are present
- Review API error logs
Orders Not Syncing
Problem: Orders created in Torque don't appear in Shopify
Solutions:
- Verify webhook endpoints are accessible
- Check webhook signature verification
- Review webhook processing logs
- Ensure proper error handling
Cart Data Mismatch
Problem: Cart items don't match between platforms
Solutions:
- Verify cart conversion logic
- Check product ID mapping
- Ensure price and quantity accuracy
- Test with simple cart items first
Debug Tools
Logging
// Enable detailed logging
const torque = new TorqueCheckout({
businessId: process.env.TORQUE_BUSINESS_ID,
apiKey: process.env.TORQUE_API_KEY,
debug: true // Enable debug logging
});
Webhook Testing
# Test webhook endpoint
curl -X POST https://yourdomain.com/webhooks/torque \
-H "Content-Type: application/json" \
-d '{
"event": "order.created",
"data": {"orderId": "test_123"}
}'
Next Steps
- WooCommerce Integration: WordPress integration guide
- Magento Integration: Enterprise ecommerce integration
- Business Dashboard: Manage your integration
- API Reference: Complete API documentation
Need help with Shopify integration? Contact our support team at hello@torque.fi or check our integration troubleshooting guide.