What is FluxPay?
FluxPay is a modern payment platform built to facilitate simple, fast, and secure payments. Our platform provides a single integration point for merchants to accept payments with intelligent routing, automatic failover, and multi-provider support.
Intelligent Routing
Automatic provider selection and failover for maximum approval rates.
Secure Payments
Bank-grade encryption, PCI DSS compliant infrastructure.
Simple Integration
Clean REST API with comprehensive documentation.
Multiple Payment Methods
Accept cards, Open Banking, and more through a single API.
SDK Installation
Load the FluxPay SDK directly from our CDN. No npm install needed — just add a script tag.
Browser (Script Tag)
Add this to your HTML — works on any website. The integrity attribute ensures the file hasn't been tampered with.
<script src="https://fluxpay.online/sdk/v1/fluxpay.min.js"
integrity="sha384-..."
crossorigin="anonymous"></script>
<!-- FluxPay is now available as window.FluxPay -->
<!-- Create payments server-side, then redirect: -->
<script>
// Call YOUR backend to create a payment (never expose API keys here)
fetch('/api/create-payment', { method: 'POST', body: JSON.stringify({ amount: 99.99 }) })
.then(r => r.json())
.then(({ paymentUrl }) => window.location.href = paymentUrl);
</script>Node.js (CommonJS)
// Download the SDK bundle
// curl -o fluxpay.cjs.js https://fluxpay.online/sdk/v1/fluxpay.cjs.js
const { FluxPayClient } = require('./fluxpay.cjs.js');
const fluxpay = new FluxPayClient({
apiKey: process.env.FLUXPAY_API_KEY, // sk_live_* or sk_test_*
});Node.js (ESM)
// Download: curl -o fluxpay.esm.mjs https://fluxpay.online/sdk/v1/fluxpay.esm.mjs
import { FluxPayClient } from './fluxpay.esm.mjs';
const fluxpay = new FluxPayClient({
apiKey: process.env.FLUXPAY_API_KEY, // sk_live_* or sk_test_*
});SRI Integrity Verification
Get the latest integrity hashes for all SDK files:
GET https://fluxpay.online/api/v1/sdk/integrityBrowser Usage
paymentUrl to the browser.Recommended pattern: your frontend calls your backend, which creates the payment server-side and returns the checkout URL.
Your Backend (Node.js)
// POST /api/create-payment
app.post('/api/create-payment', async (req, res) => {
const { payment } = await fluxpay.createPayment({
amount: req.body.amount,
currency: 'USD',
customer: req.body.customer,
description: req.body.description,
});
res.json({ paymentUrl: payment.paymentUrl });
});Your Frontend (HTML)
<button id="pay-btn">Pay $99.99</button>
<script>
document.getElementById('pay-btn')
.addEventListener('click', async () => {
const res = await fetch('/api/create-payment', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
amount: 99.99,
customer: {
email: 'customer@example.com',
firstName: 'John',
lastName: 'Doe',
},
description: 'Order #1234',
}),
});
const { paymentUrl } = await res.json();
window.location.href = paymentUrl;
});
</script>Node.js Usage
Use the SDK in your Express.js or Node.js backend to create payments server-side.
const express = require('express');
const { FluxPayClient } = require('./fluxpay.cjs.js');
const app = express();
app.use(express.json());
const fluxpay = new FluxPayClient({
apiKey: process.env.FLUXPAY_API_KEY,
});
// Create a payment
app.post('/checkout', async (req, res) => {
const { amount, email, firstName, lastName, description } = req.body;
// Basic validation
if (!amount || amount <= 0 || amount > 50000) {
return res.status(400).json({ error: 'Invalid amount' });
}
if (!email || !firstName || !lastName) {
return res.status(400).json({ error: 'Missing customer details' });
}
try {
const { payment } = await fluxpay.createPayment({
amount,
currency: 'USD',
customer: { email, firstName, lastName },
description: description || 'Payment',
returnUrl: 'https://yoursite.com/payment/callback',
successUrl: 'https://yoursite.com/payment/success',
failureUrl: 'https://yoursite.com/payment/failure',
});
res.json({ paymentUrl: payment.paymentUrl });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// Check payment status
app.get('/payment-status/:id', async (req, res) => {
try {
const { payment } = await fluxpay.getPayment(req.params.id);
res.json({ status: payment.status });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
app.listen(3000);TypeScript Support
The SDK supports TypeScript with type definitions. Import types directly:
import { FluxPayClient, FluxPayError } from './fluxpay.esm.mjs';
import type { CreatePaymentRequest, Payment, ChargePaymentRequest } from './fluxpay.esm.mjs';
const fluxpay = new FluxPayClient({ apiKey: process.env.FLUXPAY_API_KEY! });
// Hosted checkout flow
async function createOrder(req: CreatePaymentRequest): Promise<Payment> {
const { payment } = await fluxpay.createPayment(req);
return payment;
}
// S2S charge with error handling
async function chargeCard(charge: ChargePaymentRequest): Promise<Payment> {
try {
const { payment } = await fluxpay.chargePayment(charge);
if (payment.requires3DS && payment.redirectUrl) {
// Redirect customer for 3DS verification
return payment;
}
return payment;
} catch (err) {
if (err instanceof FluxPayError) {
console.error(`FluxPay error [${err.code}]: ${err.message}`);
}
throw err;
}
}Quick Start (cURL)
No SDK? Use any HTTP client to integrate with FluxPay via the REST API directly.
# No installation needed - cURL is pre-installed on most systems
# Your API key from Dashboard → Settings → API Keys
# Test mode: sk_test_* | Live mode: sk_live_*API Keys
Generate your authentication credentials to start making API calls.
Test vs Live Keys
sk_test_*TEST MODEUse for development and testing. Routes to DEMO provider (no real money).
sk_live_*LIVE MODEUse for production payments. Routes to real payment providers.
How to Generate
- 1Login to your FluxPay Dashboard
- 2Navigate to Settings → API Keys
- 3Toggle Test Mode or Live Mode
- 4Click "Rotate API Key" to generate a new key
- !Copy immediately — you can't view it again!
Security Best Practices
FLUXPAY_API_KEY=sk_live_your_key_hereCreate a Payment
Send a POST request to create a payment link. The response includes a payment URL to redirect your customer.
Payment Parameters
Required Parameters
amountnumberPayment amount in decimal format (e.g., 99.99). Must be greater than 0.
customer.emailstringCustomer email address. Used for payment receipts and customer identification.
Optional Parameters
currencystringCurrency code (USD, EUR, GBP, CAD, AUD, etc.). Defaults to USD. Must be supported by at least one of your assigned payment providers.
descriptionstringPayment description. Helps you and your customer identify the payment purpose.
customer.firstNamestringCustomer first name. Recommended — required by most payment providers for compliance.
customer.lastNamestringCustomer last name. Recommended — required by most payment providers for compliance.
customer.phonestringCustomer phone number. Pre-fills the phone field on the payment form.
customer.ipstringCustomer IP address. Used by payment providers for fraud detection and geo-validation. If omitted, extracted from request headers or defaults to a safe European IP.
customer.billingobjectBilling address object. Pre-fills billing address fields on the payment form.
Fields: address, city, state, country, postalCode
languagestringPayment form language. Defaults to en. Supported: en (English), fr (French)
Webhook & Tracking
webhookUrlstringCustom webhook URL for this specific payment. Overrides your default webhook URL configured in the dashboard.
metadataobjectCustom data object attached to the payment. Store any custom information (order IDs, user IDs, etc.) — returned in webhooks and API responses.
returnUrlstringGeneral redirect URL for both success and failure outcomes.
successUrlstringSuccess-specific redirect. Overrides returnUrl for successful payments.
failureUrlstringFailure-specific redirect. Overrides returnUrl for failed payments.
SDK (JavaScript)
const fluxpay = new FluxPayClient({
apiKey: process.env.FLUXPAY_API_KEY, // sk_live_* or sk_test_*
});
const { payment } = await fluxpay.createPayment({
amount: 99.99,
currency: 'USD',
customer: {
email: 'customer@example.com',
firstName: 'John',
lastName: 'Doe',
},
description: 'Order #1234',
metadata: {
orderId: 'ORD-2024-001',
},
});
// Redirect customer to payment page
window.location.href = payment.paymentUrl;cURL (HTTP API)
curl -X POST https://fluxpay.online/api/v1/payments \
-H "Authorization: Bearer sk_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"amount": 99.99,
"currency": "USD",
"customer": {
"email": "customer@example.com",
"firstName": "John",
"lastName": "Doe",
"phone": "+1-212-555-1234",
"ip": "203.0.113.42",
"billing": {
"address": "123 Main Street",
"city": "New York",
"state": "NY",
"country": "US",
"postalCode": "10001"
}
},
"description": "Order #1234",
"language": "fr",
"webhookUrl": "https://yoursite.com/webhooks/fluxpay",
"metadata": {
"orderId": "ORD-2024-001",
"userId": "user_12345"
}
}'
# Response:
# {
# "success": true,
# "payment": {
# "id": "pay_abc123",
# "status": "PENDING",
# "amount": 99.99,
# "currency": "USD",
# "paymentUrl": "https://fluxpay.online/payment/generic/pay_abc123",
# "customer": { ... },
# "createdAt": "2025-01-23T10:30:00Z"
# }
# }What Happens After Creation?
Payment Methods
Multiple ways for your customers to pay.
Credit & Debit Cards
Default MethodAccept all major credit and debit cards with 3D Secure authentication support.
Open Banking
Bank TransfersInstant bank-to-bank payments via Open Banking. Lower fees than cards with direct settlement.
How It Works
Open Banking Availability
Open Banking enables bank-to-bank transfers — customers pay directly from their bank account without entering card details. When available, the payment page automatically shows a Bank Transfer tab alongside the card form.
- • EU (27 countries) — EUR payments
- • United Kingdom (GB) — GBP payments
- • Australia (AU) — AUD payments
- • Canada (CA) — CAD payments
- 1. Customer selects Bank Transfer tab
- 2. Redirected to bank's secure login page
- 3. Authorises payment in their banking app
- 4. Redirected back — payment confirmed instantly
Note: Open Banking is enabled per-account based on your assigned providers and the customer's country. The Bank Transfer tab only appears when the customer's country is supported by your active providers. Contact support to enable Open Banking for your account.
Configure Webhooks
Receive real-time payment notifications.
Two Ways to Configure
Set a default webhook URL in your dashboard:
- 1. Go to Settings → Webhooks
- 2. Enter your webhook URL
- 3. Select events to receive
- 4. Copy webhook secret for signature verification
Include webhookUrl in your API request:
webhookUrl: "https://your-app.com/webhooks"Webhook Events
payment.successPayment completed successfully — fulfill order and send confirmation
payment.failedPayment failed after all retry attempts — notify customer
payment.pendingPayment processing — update order status to "processing"
payment.refundedFull refund processed — update order to refunded
payment.partially_refundedPartial refund processed — amount field reflects the refunded amount
payment.disputedChargeback or dispute opened on this payment
dispute.wonDispute resolved in your favour
dispute.lostDispute resolved against you — funds returned to customer
dispute.evidence_requiredYou must submit evidence to defend this dispute
Failed webhooks are automatically retried: after 1 min, 5 min, 15 min. Maximum 3 retry attempts. Retried requests include an X-Retry-Attempt header with the attempt number.
# WEBHOOK PAYLOAD EXAMPLE
# POST https://yoursite.com/webhooks/fluxpay
# Headers:
# Content-Type: application/json
# X-Webhook-Signature: <64-char lowercase hex, HMAC-SHA256 of raw body>
# X-Webhook-Event: payment.success ← event type is here
# X-Transaction-Id: pay_abc123
# X-Test-Mode: false
# X-Retry-Attempt: 2 ← only present on retries (attempt 2, 3, 4)
# The request body IS the payload — no wrapper object:
{
"transactionId": "pay_abc123",
"reference": "pl_xyz789",
"amount": 99.99,
"currency": "USD",
"status": "COMPLETED",
"customerEmail": "customer@example.com",
"testMode": false,
"metadata": {
"orderId": "ORD-2024-001",
"userId": "user_12345"
},
"timestamp": "2025-01-23T10:35:00Z"
}
# YOUR WEBHOOK ENDPOINT MUST:
# 1. Read the raw request body (before JSON parsing) for signature verification
# 2. Verify the X-Webhook-Signature header (HMAC-SHA256 of raw body bytes, hex digest)
# 3. Read the event type from X-Webhook-Event header (NOT from the body)
# 4. Process the event (fulfill order, send email, etc.)
# 5. Return 200 OK within 10 secondsRedirect URLs
Return customers to your site after payment completion.
Redirect URL Options
returnUrlstring (optional)General redirect URL for both success and failure.
successUrlstring (optional)Success-specific redirect. Overrides returnUrl for successful payments.
failureUrlstring (optional)Failure-specific redirect. Overrides returnUrl for failed payments.
Query Parameters Received
These query parameters are appended to your redirect URL:
status— "success" or "failed"transaction_id— Unique transaction identifieramount— Payment amountcurrency— Currency code (USD, EUR, etc.)reference— External reference IDmetadata[key]— Your custom metadata fieldsTip: Always verify payment status via webhook or API — do not rely solely on redirect URL parameters.
curl -X POST https://fluxpay.online/api/v1/payments \
-H "Authorization: Bearer sk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"amount": 99.99,
"currency": "USD",
"customer": {
"email": "customer@example.com",
"firstName": "John",
"lastName": "Doe"
},
"description": "Order #1234",
"metadata": {
"orderId": "ORD-2024-001"
},
"returnUrl": "https://yoursite.com/payment/callback",
"successUrl": "https://yoursite.com/payment/success",
"failureUrl": "https://yoursite.com/payment/failure"
}'
# After payment, customer is redirected to:
# SUCCESS: https://yoursite.com/payment/success?status=success&transaction_id=...
# FAILURE: https://yoursite.com/payment/failure?status=failed&transaction_id=...Embed Payment Page
Embed FluxPay checkout directly in your website.
Redirect (Recommended)
Redirect customer to FluxPay hosted page. Best for security and compliance.
Best for: Most use cases
Modal iFrame
Embed payment page in a popup modal. Keeps customer on your site during checkout.
Best for: SaaS, subscriptions
Inline iFrame
Embed payment form directly in your page layout. Seamless checkout experience.
Best for: Single-page apps
<!-- OPTION 1: Inline iFrame -->
<iframe
src="https://fluxpay.online/payment/generic/pay_abc123"
width="100%"
height="600"
frameborder="0"
allow="payment"
style="border: none; border-radius: 12px;"
></iframe>
<!-- OPTION 2: Modal/Popup iFrame -->
<div id="payment-modal" style="
display: none;
position: fixed;
top: 0; left: 0;
width: 100vw; height: 100vh;
background: rgba(0,0,0,0.5);
z-index: 9999;
">
<div style="
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
width: 90%; max-width: 500px;
background: white;
border-radius: 16px;
overflow: hidden;
">
<iframe id="payment-iframe" width="100%" height="600" frameborder="0"></iframe>
</div>
</div>
<script>
function openPayment(paymentUrl) {
document.getElementById('payment-iframe').src = paymentUrl;
document.getElementById('payment-modal').style.display = 'block';
}
</script>// React Component for Embedded Payment
import { useState } from 'react';
function PaymentModal({ paymentUrl, onClose }) {
return (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
<div className="bg-white rounded-2xl w-full max-w-lg overflow-hidden">
<div className="flex justify-between items-center p-4 border-b">
<h3 className="font-semibold">Complete Payment</h3>
<button onClick={onClose} className="text-gray-500 hover:text-gray-700">✕</button>
</div>
<iframe
src={paymentUrl}
className="w-full h-[600px] border-0"
allow="payment"
/>
</div>
</div>
);
}
// Usage in your checkout page
function CheckoutPage() {
const [paymentUrl, setPaymentUrl] = useState(null);
const handleCheckout = async () => {
const res = await fetch('/api/create-payment', { method: 'POST' });
const { paymentUrl } = await res.json();
setPaymentUrl(paymentUrl);
};
return (
<div>
<button onClick={handleCheckout}>Pay Now</button>
{paymentUrl && (
<PaymentModal
paymentUrl={paymentUrl}
onClose={() => setPaymentUrl(null)}
/>
)}
</div>
);
}Important Notes for Embedding
S2S (Server-to-Server) Payments
For PCI-compliant merchants who collect card details on their own checkout form. Send card data directly via API — no hosted page redirect needed.
PCI Compliance Required
S2S integration requires your servers to handle raw card data. You must be PCI DSS Level 1 or Level 2 compliant. If you are not PCI compliant, use the Hosted Checkout integration instead.
Hosted Checkout
- Customer redirected to FluxPay form
- FluxPay handles card data
- No PCI requirements for merchant
- Best for most merchants
S2S (Direct Charge)
- Merchant collects card on own form
- Card data sent via API
- PCI DSS compliance required
- Best for high-volume merchants
Charge Payment
POST /api/v1/payments/charge
SDK (JavaScript)
const { payment } = await fluxpay.chargePayment({
amount: 99.99,
currency: 'USD',
card: {
number: '4111111111111111',
holderName: 'JOHN DOE',
expiryMonth: '12',
expiryYear: '25',
cvv: '123',
},
customer: {
email: 'john@example.com',
firstName: 'John',
lastName: 'Doe',
phone: '+1234567890',
ip: '203.0.113.42',
billing: {
address: '123 Main St',
city: 'New York',
state: 'NY',
postalCode: '10001',
country: 'US',
},
},
description: 'Order #1234',
metadata: { orderId: 'ORD-001' },
});
if (payment.requires3DS) {
// Redirect for 3DS authentication
window.location.href = payment.redirectUrl;
} else {
console.log('Payment:', payment.status);
}cURL (HTTP API)
curl -X POST https://fluxpay.online/api/v1/payments/charge \
-H "Authorization: Bearer sk_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"amount": 99.99,
"currency": "USD",
"card": {
"number": "4111111111111111",
"holderName": "JOHN DOE",
"expiryMonth": "12",
"expiryYear": "25",
"cvv": "123"
},
"customer": {
"email": "john@example.com",
"firstName": "John",
"lastName": "Doe",
"phone": "+1234567890",
"ip": "203.0.113.42",
"billing": {
"address": "123 Main St",
"city": "New York",
"state": "NY",
"postalCode": "10001",
"country": "US"
}
},
"description": "Order #1234",
"metadata": { "orderId": "ORD-001" }
}'Request Parameters
amountnumberTransaction amount (e.g., 99.99)
currencystringISO 4217 currency code (default: USD)
card.numberstringCard number (13-19 digits)
card.holderNamestringCardholder name as on card
card.expiryMonthstringExpiry month (01-12)
card.expiryYearstringExpiry year (2-digit, e.g., 25)
card.cvvstringCVV/CVC (3-4 digits)
customer.emailstringCustomer email address
customer.firstNamestringCustomer first name
customer.lastNamestringCustomer last name
customer.phonestringPhone with country code
customer.ipstringCustomer IP for fraud/geo checks
customer.billingobjectBilling address (address, city, state, postalCode, country)
descriptionstringPayment description
metadataobjectCustom key-value metadata
webhookUrlstringOverride webhook URL for this payment
returnUrlstringReturn URL after 3DS redirect
Response — Success (2D)
{
"success": true,
"payment": {
"id": "cm4h1abc123",
"status": "COMPLETED",
"amount": 99.99,
"currency": "USD",
"provider": "XSPEND",
"customer": {
"email": "john@example.com",
"firstName": "John",
"lastName": "Doe"
},
"metadata": { "orderId": "ORD-001" },
"createdAt": "2026-03-24T10:00:00.000Z",
"processedAt": "2026-03-24T10:00:02.000Z"
}
}Response — 3DS Required
{
"success": true,
"payment": {
"id": "cm4h1abc123",
"status": "PENDING",
"requires3DS": true,
"redirectUrl": "https://provider.com/3ds?session=xxx",
"amount": 99.99,
"currency": "USD"
}
}Response — Declined
{
"success": false,
"error": "Payment declined",
"payment": {
"id": "cm4h1abc123",
"status": "FAILED",
"failureReason": "Card declined by issuer."
}
}3DS Handling
Some transactions require 3D Secure authentication. When this happens, the response will includerequires3DS: true and aredirectUrl.
3DS Flow
- 1Call
POST /api/v1/payments/chargewith card details - 2Check response — if
requires3DSis true, redirect the customer toredirectUrl - 3Customer completes 3DS on the provider's page
- 4Customer returns to your
returnUrl(if provided) - 5Poll
GET /api/v1/payments?id={id}or listen for the webhook to get final status
const result = await fluxpay.chargePayment({
amount: 99.99,
card: { number: '4111111111111111', holderName: 'JOHN DOE',
expiryMonth: '12', expiryYear: '25', cvv: '123' },
customer: { email: 'john@example.com' }
});
if (result.payment.requires3DS) {
// Redirect customer to 3DS page
res.redirect(result.payment.redirectUrl);
// Then poll for final status
const final = await fluxpay.waitForPayment(result.payment.id);
console.log('Final status:', final.payment.status);
} else if (result.success) {
console.log('Payment completed:', result.payment.id);
} else {
console.log('Payment failed:', result.error);
}Complete Example
const { FluxPayClient } = require('./fluxpay.cjs.js');
// Or ESM: import { FluxPayClient } from './fluxpay.esm.mjs';
const fluxpay = new FluxPayClient({
apiKey: process.env.FLUXPAY_API_KEY, // sk_live_xxx or sk_test_xxx
});
async function chargeCustomer(order) {
try {
const result = await fluxpay.chargePayment({
amount: order.total,
currency: 'USD',
description: `Order #${order.id}`,
card: {
number: order.cardNumber,
holderName: order.cardName,
expiryMonth: order.expMonth,
expiryYear: order.expYear,
cvv: order.cvv,
},
customer: {
email: order.email,
firstName: order.firstName,
lastName: order.lastName,
phone: order.phone,
billing: {
address: order.address,
city: order.city,
state: order.state,
postalCode: order.zip,
country: order.country,
},
},
metadata: { orderId: order.id },
webhookUrl: 'https://yoursite.com/webhooks/fluxpay',
});
if (result.payment.requires3DS) {
// Store payment ID, redirect customer
return { redirect: result.payment.redirectUrl, paymentId: result.payment.id };
}
if (result.success && result.payment.status === 'COMPLETED') {
return { success: true, paymentId: result.payment.id };
}
// PENDING — wait for webhook or poll
if (result.payment.status === 'PENDING') {
const final = await fluxpay.waitForPayment(result.payment.id);
return { success: final.payment.status === 'COMPLETED', paymentId: final.payment.id };
}
return { success: false, error: result.error };
} catch (err) {
console.error('Charge failed:', err.message);
return { success: false, error: err.message };
}
}Test Mode
Use an API key starting with sk_test_ to test without processing real payments. Test mode charges auto-complete with the DEMO provider.
curl -X POST https://fluxpay.online/api/v1/payments/charge \
-H "Authorization: Bearer sk_test_your_test_key" \
-H "Content-Type: application/json" \
-d '{
"amount": 1.00,
"card": {
"number": "4111111111111111",
"holderName": "TEST USER",
"expiryMonth": "12",
"expiryYear": "25",
"cvv": "123"
},
"customer": { "email": "test@example.com" }
}'WooCommerce Integration
Accept payments in your WooCommerce store with the official FluxPay plugin. No code required.
Requirements
Installation
Download & Install the Plugin
Download the zip above, then in your WordPress admin go to Plugins > Add New > Upload Plugin. Select the zip file and click Install Now, then Activate.
Enter Your API Key
Go to WooCommerce > Settings > Payments > FluxPay. Enter the API key from your FluxPay Dashboard (Settings > API Keys).
Enable the Gateway
Toggle the Enable/Disable switch to On. Optionally set a custom title and description shown at checkout.
Test a Payment
Place a test order in your store. You will be redirected to the FluxPay payment page, then back to your order confirmation.
Configuration Settings
| Setting | Description | Default |
|---|---|---|
| Enable/Disable | Show FluxPay at checkout | Disabled |
| Title | Payment method name shown to customers | Credit / Debit Card |
| Description | Payment method description at checkout | Pay securely via FluxPay |
| API Key | Your FluxPay API key (sk_live_... or sk_test_...) | -- |
| Test Mode | Use test API key for sandbox transactions | Off |
Payment Flow
1. Customer clicks "Place Order" in WooCommerce checkout
2. Plugin calls FluxPay API to create a payment
3. Customer is redirected to FluxPay hosted payment page
4. Customer enters card details and completes payment
5. FluxPay sends webhook to your site to confirm the result
6. Plugin updates WooCommerce order status automatically
7. Customer is redirected back to your order confirmation page
Webhooks
The plugin automatically registers a webhook endpoint at yoursite.com/wc-api/fluxpay. No manual webhook configuration is needed. The plugin verifies webhook signatures and updates order status (Processing, Failed, or Refunded) based on the event received.
Test Mode
Enable Test Mode in the plugin settings and use a sk_test_... API key. Test payments are processed in sandbox mode and automatically marked as completed. Use test card 4111 1111 1111 0000 for successful test payments.
Troubleshooting
Payment redirects to a blank page
Ensure your API key is correct and your FluxPay account is active. Check WooCommerce > Status > Logs for errors from the fluxpay gateway.
Order status not updating after payment
Verify that your site is accessible over HTTPS and not blocked by a firewall. The webhook URL must be reachable from FluxPay servers.
Plugin not appearing at checkout
Go to WooCommerce > Settings > Payments and make sure FluxPay is enabled. Also confirm your store currency is supported (USD, EUR, GBP, CAD, AUD).
<?php
// Example: Verifying FluxPay webhook in your custom plugin or theme
// (The WooCommerce plugin handles this automatically)
add_action('rest_api_init', function () {
register_rest_route('my-shop/v1', '/fluxpay-webhook', [
'methods' => 'POST',
'callback' => 'handle_fluxpay_webhook',
]);
});
function handle_fluxpay_webhook(WP_REST_Request $request) {
// IMPORTANT: read the raw body BEFORE any JSON parsing.
// The signature is HMAC-SHA256 over the exact bytes that were sent.
// Re-encoding parsed JSON (e.g. wp_json_encode) will NOT match.
$body = file_get_contents('php://input');
$signature = $request->get_header('X-Webhook-Signature');
$event = $request->get_header('X-Webhook-Event'); // e.g. "payment.success"
$secret = get_option('fluxpay_webhook_secret');
$computed = hash_hmac('sha256', $body, $secret);
if (!hash_equals($computed, $signature)) {
return new WP_REST_Response(['error' => 'Invalid signature'], 401);
}
// The body IS the payload — a flat object, no "data" wrapper.
$payload = json_decode($body, true);
$order_id = $payload['metadata']['orderId'] ?? null;
$order = wc_get_order($order_id);
if ($order && $event === 'payment.success' && $payload['status'] === 'COMPLETED') {
$order->payment_complete($payload['transactionId']);
}
return new WP_REST_Response(['success' => true], 200);
}