Skip to main content

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

  1. Visit Shopify App Store: Go to apps.shopify.com
  2. Search for Torque: Find "Torque Checkout" app
  3. Install App: Click "Add app" and follow the installation process
  4. Connect Account: Link your Torque business account

2. Configure Settings

  1. API Credentials: Enter your Torque Business ID and API Key
  2. Checkout Options: Configure checkout appearance and behavior
  3. Webhook Setup: Enable real-time order updates
  4. Test Mode: Verify integration in sandbox environment

3. Go Live

  1. Production Mode: Switch from test to live mode
  2. Monitor Orders: Track checkout performance
  3. Customer Support: Provide seamless customer experience

Manual Integration

App Installation

If you prefer manual integration, follow these steps:

Step 1: Create Torque Business Account

  1. Sign Up: Visit torque.fi/business
  2. Complete Profile: Fill out business information
  3. 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);
// 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

  1. Enable Test Mode: Use test API keys and sandbox environment
  2. Create Test Orders: Generate test checkout links
  3. Verify Webhooks: Test webhook delivery and processing
  4. 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

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


Need help with Shopify integration? Contact our support team at hello@torque.fi or check our integration troubleshooting guide.