Shopify Integration
Accept crypto payments on Shopify using Plaidly as a custom payment provider
Shopify Integration
Plaidly integrates with Shopify via the Payments App API, allowing you to offer cryptocurrency as a payment option alongside credit cards and PayPal at checkout.
Prerequisites
- A Shopify Partner account
- A Shopify app with the
payment_gatewayspermission - Your Plaidly API key and webhook secret
Overview
Shopify's Payments App API calls your backend when a customer selects your payment option. Your backend:
- Creates a Plaidly payment session
- Redirects the customer to a payment page showing the crypto address
- Receives a webhook from Plaidly when payment is confirmed
- Resolves the Shopify payment session as complete
1. Register as a payment provider
In your Shopify app's GraphQL mutation, register your payment provider:
mutation {
paymentsAppConfigure(
externalHandle: "plaidly-crypto"
ready: true
) {
paymentsAppConfiguration {
externalHandle
ready
}
userErrors {
field
message
}
}
}2. Handle payment session creation
Shopify sends a POST request to your payment_session_create endpoint when a customer checks out:
// app/api/shopify/payment-session/route.ts
import { PlaidlyClient } from '@plaidly/node';
import { NextRequest } from 'next/server';
import { verifyShopifyHmac } from '@/lib/shopify';
const plaidly = new PlaidlyClient({
apiKey: process.env.PLAIDLY_API_KEY!,
});
export async function POST(req: NextRequest) {
const body = await req.json();
// Verify the request is from Shopify
const hmac = req.headers.get('x-shopify-hmac-sha256') ?? '';
if (!verifyShopifyHmac(JSON.stringify(body), hmac)) {
return new Response('Unauthorized', { status: 401 });
}
const { id: shopifySessionId, amount, currency, customer } = body;
// Create a Plaidly payment session
const session = await plaidly.sessions.create({
amount: amount.amount,
currency: 'USDC',
chain: 'solana',
network: 'mainnet',
callbackUrl: `${process.env.BASE_URL}/api/shopify/webhook`,
metadata: {
shopifySessionId,
shopifyOrderId: body.kind,
customerEmail: customer?.email,
},
});
// Return redirect URL to your payment page
return Response.json({
redirect_url: `${process.env.BASE_URL}/pay/${session.id}`,
});
}3. Create the payment page
Show the customer the crypto address and payment details:
// app/pay/[sessionId]/page.tsx
import { PlaidlyClient } from '@plaidly/node';
const plaidly = new PlaidlyClient({
apiKey: process.env.PLAIDLY_API_KEY!,
});
export default async function PayPage({
params,
}: {
params: Promise<{ sessionId: string }>;
}) {
const { sessionId } = await params;
const session = await plaidly.sessions.get(sessionId);
return (
<div>
<h1>Send {session.amount} {session.currency}</h1>
<p>To address: {session.walletAddress}</p>
<p>On network: {session.chain}</p>
<p>Session expires: {session.expiresAt}</p>
{/* Add QR code component here */}
</div>
);
}4. Handle Plaidly webhooks
When Plaidly confirms a payment, resolve the Shopify payment session:
// app/api/shopify/webhook/route.ts
import { verifyWebhookSignature } from '@plaidly/node/webhooks';
import { NextRequest } from 'next/server';
import { resolveShopifyPayment } from '@/lib/shopify';
export async function POST(req: NextRequest) {
const body = await req.text();
const sig = req.headers.get('x-plaidly-signature') ?? '';
let event;
try {
event = verifyWebhookSignature(
body,
sig,
process.env.PLAIDLY_WEBHOOK_SECRET!,
);
} catch {
return new Response('Invalid signature', { status: 400 });
}
if (event.event === 'payment.confirmed') {
const { shopifySessionId } = event.metadata;
// Resolve the Shopify payment session
await resolveShopifyPayment(shopifySessionId, {
status: 'resolve',
transactionId: event.session.id,
});
}
return new Response('OK');
}5. Resolve a Shopify payment session
// lib/shopify.ts
export async function resolveShopifyPayment(
sessionId: string,
resolution: { status: 'resolve' | 'reject'; transactionId?: string },
) {
const mutation = `
mutation PaymentSessionResolve($id: ID!) {
paymentSessionResolve(id: $id) {
paymentSession {
id
state { ... on PaymentSessionStateResolved { code } }
}
userErrors { field message }
}
}
`;
const response = await fetch(
`https://${process.env.SHOPIFY_SHOP}/admin/api/2024-01/graphql.json`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Shopify-Access-Token': process.env.SHOPIFY_ACCESS_TOKEN!,
},
body: JSON.stringify({
query: mutation,
variables: { id: `gid://shopify/PaymentSession/${sessionId}` },
}),
},
);
return response.json();
}Testing
Use Shopify's Payments App simulator and set network: 'testnet' in Plaidly to test the full flow without real funds.
Supported currencies
You can let customers choose their preferred chain/token on your payment page. The Shopify order currency is the fiat reference — Plaidly handles the crypto equivalent calculation.