Shopify Integration
Connect BINKPAY to your Shopify store to accept credit cards, Apple Pay, and Google Pay at checkout. The integration uses a certified Shopify Checkout Extension and supports both Shopify Online Store 2.0 and headless storefronts. All orders, refunds, and disputes sync bidirectionally between BINKPAY and your Shopify Admin.
Hosted Checkout
Cards · Apple Pay · Google Pay
Refunds sync
No code changes
Prerequisites
Before you begin, make sure you have the following:
Installation
BINKPAY connects to Shopify via OAuth. The entire flow takes under two minutes and requires no code changes to your theme.
Open the Integrations tab in BINKPAY Dashboard
Log in to dashboard.binkpay.net and navigate to Integrations → E-commerce Platforms. You will see a card for Shopify alongside other supported platforms.
Click "Connect Shopify"
Click the Connect Shopify button on the Shopify card. A modal will appear asking for your store URL.
Enter your Shopify store URL
Enter your store's myshopify.com URL in the format your-store.myshopify.com. Do not include https://. Click Continue.
Authorize the OAuth connection
You will be redirected to your Shopify Admin to authorize the BINKPAY app. Review the requested permissions — BINKPAY requires access to Orders, Payments, and Script Tags — then click Install app. You must be logged in as a Shopify store owner or a staff member with the Manage payments permission.
Confirm installation and select payment methods
After authorization, you will be redirected back to the BINKPAY Dashboard. Select which payment methods to enable at checkout (Cards, Apple Pay, Google Pay), then click Save configuration. BINKPAY automatically installs the Checkout Extension into your Shopify store — no theme edits required.
Checkout Configuration
BINKPAY installs a Shopify Checkout Extension that renders the payment UI inside the native Shopify checkout flow. The extension is configured via a JSON file committed to your Shopify app's extension directory. If you are self-hosting the extension, use the configuration below as your starting point.
extensions/binkpay-checkout/shopify.extension.toml
[extensions.checkout_ui]
name = "BINKPAY Checkout"
handle = "binkpay-checkout"
type = "ui_extension"[[extensions.checkout_ui.targeting]]
module = "./src/index.tsx"
target = "purchase.checkout.payment-method-list.render-before"[extensions.checkout_ui.settings]
[extensions.checkout_ui.settings.fields.publishable_key]
type = "single_line_text_field"
name = "BINKPAY Publishable Key"
description = "Your pk_live_... or pk_test_... key from the BINKPAY Dashboard"[extensions.checkout_ui.settings.fields.enable_apple_pay]
type = "boolean"
name = "Enable Apple Pay"
default = true[extensions.checkout_ui.settings.fields.enable_google_pay]
type = "boolean"
name = "Enable Google Pay"
default = true[extensions.checkout_ui.settings.fields.statement_descriptor]
type = "single_line_text_field"
name = "Statement Descriptor"
description = "Appears on the customer's bank statement. Max 22 characters."[extensions.checkout_ui.settings.fields.capture_method]
type = "single_line_text_field"
name = "Capture Method"
description = "Use 'automatic' to capture immediately or 'manual' to authorize and capture later."
default = "automatic"After saving this configuration, deploy the extension with the Shopify CLI:
shopify app deploy --forceApple Pay & Google Pay
Both Apple Pay and Google Pay require domain verification before they will display at checkout. BINKPAY automates most of this process, but you must ensure your domain is correctly registered.
Apple Pay Domain Verification
Apple requires a domain association file to be hosted at a well-known path on your domain. BINKPAY generates this file automatically for your registered domains. Run the following command to verify all domains associated with your BINKPAY account:
# Register your Shopify custom domain with BINKPAY
curl-X POST https://api.binkpay.net/v1/apple-pay/domains \
-H "Authorization: Bearer sk_live_YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"domain_name": "www.your-store.com"}'
# Verify the domain association file is reachable
curlhttps://www.your-store.com/.well-known/apple-developer-merchantid-domain-associationGoogle Pay Domain Verification
Google Pay does not require a static file. Instead, BINKPAY registers your Shopify domain with the Google Pay Business Console automatically during the OAuth install step. To verify the registration succeeded:
curlhttps://api.binkpay.net/v1/google-pay/domains \
-H "Authorization: Bearer sk_live_YOUR_SECRET_KEY"
# Expected response
# {
# "domains": [
# { "domain": "www.your-store.com", "status": "verified", "verified_at": "2025-11-03T14:22:00Z" }
# ]
# }Shopify-managed domains
If your store uses a *.myshopify.com domain instead of a custom domain, Apple Pay and Google Pay are pre-verified by Shopify and BINKPAY. No additional steps are required.
Webhook Setup
During installation, BINKPAY automatically registers the following webhook topics with your Shopify store via the Shopify Admin API:
orders/paid— marks the corresponding BINKPAY payment as capturedorders/cancelled— triggers a BINKPAY void or refund depending on capture staterefunds/create— creates a BINKPAY refund for the matching chargeapp/uninstalled— cleanly disconnects the integration
BINKPAY also sends webhooks to your own server for payment events. All BINKPAY webhook payloads are signed with HMAC-SHA256. Verify signatures before processing any event:
app/api/binkpay-webhook/route.ts
import{ NextRequest, NextResponse } from 'next/server';
import crypto from 'crypto';
constBINKPAY_WEBHOOK_SECRET = process.env.BINKPAY_WEBHOOK_SECRET!; export async functionPOST(req: NextRequest) { const rawBody = await req.text();
constsignature = req.headers.get( 'binkpay-signature') ?? '';
// Verify HMAC-SHA256 signature
constexpectedSig = crypto
.createHmac( 'sha256', BINKPAY_WEBHOOK_SECRET)
.update(rawBody, 'utf8')
.digest( 'hex');
const sigBuffer = Buffer. from(signature, 'hex');
constexpectedBuffer = Buffer. from(expectedSig, 'hex');
if(
sigBuffer.length !== expectedBuffer.length ||
!crypto.timingSafeEqual(sigBuffer, expectedBuffer)
) {
console.error( '[BINKPAY] Webhook signature mismatch');
returnNextResponse.json({ error: 'Invalid signature' }, { status: 401 });
}
constevent = JSON.parse(rawBody);
switch (event.type) {
case 'payment.succeeded':
awaithandlePaymentSucceeded(event.data);
break;
case 'payment.failed':
awaithandlePaymentFailed(event.data);
break;
case 'refund.created':
awaithandleRefundCreated(event.data);
break;
case 'dispute.created':
awaithandleDisputeCreated(event.data);
break; default:
console.log( `[BINKPAY] Unhandled event type: ${event.type}`);
}
returnNextResponse.json({ received: true });
}
async functionhandlePaymentSucceeded(data: Record<string, unknown>) { // Fulfill the Shopify order linked to this payment
constshopifyOrderId = data.metadata?.shopify_order_id as string; if (shopifyOrderId) {
awaitfulfillShopifyOrder(shopifyOrderId);
}
} async functionhandlePaymentFailed(data: Record<string, unknown>) {
console.warn( `[BINKPAY] Payment failed: ${data.id}`, data.failure_reason);
} async functionhandleRefundCreated(data: Record<string, unknown>) {
console.log( `[BINKPAY] Refund created: ${data.id} for ${data.amount} ${data.currency}`);
}
async functionhandleDisputeCreated(data: Record<string, unknown>) { // Notify your team via Slack, email, etc.
console.warn( `[BINKPAY] Dispute opened on payment ${data.payment_id}`);
}
async functionfulfillShopifyOrder(orderId: string) { // Call Shopify Admin API to create a fulfillment
const res = await fetch(
`https://${process.env.SHOPIFY_STORE_DOMAIN}/admin/api/2024-10/orders/${orderId}/fulfillments.json`,
{
method: 'POST',
headers: {
'X-Shopify-Access-Token': process.env.SHOPIFY_ADMIN_TOKEN!, 'Content-Type': 'application/json',
},
body: JSON.stringify({ fulfillment: { notify_customer: true } }),
}
);
if (!res.ok) {
throw new Error( `Shopify fulfillment failed: ${res.status}`);
}
}Order Sync
BINKPAY maintains a bidirectional sync between payment records and Shopify orders. Here is how data flows in each direction:
| Event source | Action | Result |
|---|---|---|
BINKPAY payment.succeeded | Payment captured | Shopify order marked as Paid |
BINKPAY refund.created | Full or partial refund | Shopify refund record created, inventory restocked |
Shopify orders/cancelled | Order cancelled in Admin | BINKPAY voids authorization (if not captured) or issues refund |
Shopify refunds/create | Manual refund in Shopify Admin | BINKPAY creates corresponding refund on the charge |
Below is a sample payment.succeeded webhook payload. The metadata.shopify_order_id field ties the BINKPAY payment to the Shopify order.
Webhook payload — payment.succeeded
{
"id": "evt_01HXKP9N4VWZQ3M8JRTB2YCDS",
"type": "payment.succeeded",
"created_at": "2025-11-03T14:22:37Z",
"data": {
"id": "pay_01HXKN2F8DQZM4YWCPVR9LSTK",
"object": "payment",
"amount": 14900,
"currency": "USD",
"status": "succeeded",
"capture_method": "automatic",
"payment_method": {
"type": "card",
"card": {
"brand": "visa",
"last4": "4242",
"exp_month": 12,
"exp_year": 2027,
"funding": "credit"
}
},
"metadata": {
"shopify_order_id": "5678901234567",
"shopify_order_number": "#1042",
"shopify_store": "your-store.myshopify.com"
},
"receipt_url": "https://pay.binkpay.net/receipts/pay_01HXKN2F8DQZM4YWCPVR9LSTK"
},
"livemode": true
}Sandbox Testing
Switch to test mode before testing
In your BINKPAY Dashboard, toggle the environment switch in the top-right corner to Test. Your Shopify extension will automatically use your pk_test_... key when test mode is active. No live payments will be processed.
Use the following test card numbers at your Shopify checkout to simulate different payment outcomes:
| Card number | Brand | Outcome | Notes |
|---|---|---|---|
| 4242 4242 4242 4242 | Visa | Succeeded | Any future expiry, any 3-digit CVV |
| 4000 0000 0000 0002 | Visa | Declined | Generic card declined error |
| 4000 0000 0000 9995 | Visa | Declined | Insufficient funds |
| 4000 0027 6000 3184 | Visa | 3DS Required | Triggers 3D Secure authentication flow |
| 5555 5555 5555 4444 | Mastercard | Succeeded | Any future expiry, any 3-digit CVV |
| 3782 822463 10005 | Amex | Succeeded | Any future expiry, 4-digit CVV |
Production Deployment Checklist
Complete each step before switching your Shopify store to live payment processing.
Switch BINKPAY to Live mode
In your BINKPAY Dashboard, toggle the environment to Live. Update the BINKPAY Publishable Key in your Shopify Checkout Extension settings (Shopify Admin → Apps → BINKPAY → Extension settings) to your pk_live_... key.
Rotate and store secret keys securely
Generate a live secret key in Dashboard → Developers → API Keys. Store it as an environment variable — never hard-code it. Set BINKPAY_SECRET_KEY and BINKPAY_WEBHOOK_SECRET in your hosting provider's secrets manager.
Verify Apple Pay and Google Pay domain registration
Confirm all storefront domains (including any custom domains) return a 200 OK for the Apple Pay domain association file. Use the BINKPAY API or Dashboard (Integrations → Shopify → Domain Verification) to confirm Google Pay status shows Verified.
Place a live test transaction
Using a real credit card, complete a small purchase (e.g., $1.00) on your live store. Verify the order appears in both Shopify Admin and the BINKPAY Dashboard with status Succeeded. Then issue a full refund from Shopify Admin and confirm it propagates to BINKPAY within 60 seconds.
Enable webhook failure alerts
In Dashboard → Developers → Webhooks, set an alert email for webhook delivery failures. BINKPAY retries failed webhooks with exponential backoff for up to 72 hours, but you should be notified immediately if your endpoint returns 5xx errors.
Troubleshooting
BINKPAY does not appear as a payment option at checkout
This is almost always caused by the Checkout Extension not being published. In Shopify Admin, go to Online Store → Themes → Customize, then open Checkout → App blocks and confirm the BINKPAY block is toggled on. Also verify that your Shopify plan supports third-party payment providers — the Starter plan does not.
Apple Pay button is not showing at checkout
Apple Pay only renders in Safari on Apple devices and when the domain is verified. Check that your custom domain is registered via the BINKPAY API (see the Apple Pay section above) and that the domain association file is publicly accessible. Note that Apple Pay will not appear in Chrome on macOS — this is expected browser behavior, not a BINKPAY issue.
Webhook signature verification is failing in production
Signature verification fails when the raw request body is modified before hashing. Body-parsing middleware (e.g., express.json()) must not run before the signature check. Read the raw buffer using req.text() in Next.js App Router or express.raw({ type: '*/*' }) in Express, then parse JSON only after computing the HMAC.
Refunds initiated in Shopify Admin are not being applied in BINKPAY
BINKPAY listens to the Shopify refunds/create webhook topic to trigger corresponding refunds. If this webhook is missing, re-install the BINKPAY app from your Dashboard (Integrations → Shopify → Reconnect). You can also manually verify registered webhooks by running:
curlhttps://your-store.myshopify.com/admin/api/ 2024- 10/webhooks.json \
-H "X-Shopify-Access-Token: YOUR_SHOPIFY_ACCESS_TOKEN"Was this page helpful?
