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

Encrypted transport and hosted checkout that keeps raw card data off merchant servers.

Simple Integration

Clean REST API with comprehensive documentation.

Multiple Payment Methods

Accept cards, Open Banking, and Asia local payments (HKD, JPY, KRW) 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.

HTML
<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)

JavaScript
// 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)

JavaScript
// 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/integrity

Browser Usage

Important: API keys must never appear in client-side code. Create payments on your server and return the 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)

Express.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)

HTML + JavaScript
<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.

Express.js
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:

TypeScript
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.statusCode ?? 'network'}]: ${err.message}`);
    }
    throw err;
  }
}

Quick Start (cURL)

No SDK? Use any HTTP client to integrate with FluxPay via the REST API directly.

cURL / REST API
# 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 MODE

Use for development and testing. Routes to DEMO provider (no real money).

sk_live_*LIVE MODE

Use for production payments. Routes to real payment providers.

How to Generate

  1. 1Login to your FluxPay Dashboard
  2. 2Navigate to Settings → API Keys
  3. 3Toggle Test Mode or Live Mode
  4. 4Click "Rotate API Key" to generate a new key
  5. !Copy immediately — you can't view it again!

Security Best Practices

Store in Environment VariablesNever hardcode API keys in your source code. Use .env files:FLUXPAY_API_KEY=sk_live_your_key_here
Use Server-Side OnlyAPI keys should NEVER be exposed in client-side code or public repositories.
Rotate Keys RegularlyRotate your API keys periodically, especially if you suspect they may have been compromised.
Separate Test and LiveAlways use test keys during development and only switch to live keys in production.

Note: No rate limiting is currently enforced on the FluxPay API. Please still apply sensible client-side throttling and retry/back-off logic on your side.

Test Cards

Use these test card numbers with your test API key (sk_test_*) to simulate different payment outcomes. Any future expiry date and any 3-digit CVV will work.

Card NumberBrandOutcomeDescription
4111 1111 1111 0000VisaSuccessPayment completes instantly
4111 1111 1111 1111VisaDeclineCard declined by provider
4111 1111 1111 2222Visa3DS RedirectTriggers 3D Secure authentication flow
4111 1111 1111 3333VisaPendingStays pending, webhook arrives later
5555 5555 5555 0000MastercardSuccessMastercard success
5555 5555 5555 1111MastercardDeclineMastercard decline

Pattern Rule

The last 4 digits of the card number determine the outcome. Any card number ending in 0000 succeeds, 1111 declines, 2222 triggers 3DS, and 3333 stays pending. All other endings return success.

The table above is representative, not exhaustive — the same outcomes are also triggered by 1234/9999 (decline), 2233/2244 (3DS), and 3344/3355 (pending) endings.

Testing 3DS

  1. 1Create a payment or S2S charge using a card ending in 2222 (e.g. 4111111111112222)
  2. 2The API response returns requires3DS: true with a redirectUrl
  3. 3Redirect the customer (or navigate in your test) to the redirectUrl — this opens the 3DS simulator page
  4. 4On the simulator, click "Approve" to complete the payment or "Reject" to fail it
  5. 5The customer is redirected back to your returnUrl and a webhook is sent with the final status

Test Mode Only

The 3DS simulator and test card outcomes only work with test API keys (sk_test_*). Live API keys route to real payment providers and real 3D Secure authentication.

Create a Payment

Send a POST request to create a payment link. The response includes a payment URL to redirect your customer.

Onboarding gate: in live mode (sk_live_*), merchants whose onboarding status is SUSPENDED, PENDING, KYB_IN_PROGRESS, or KYB_SUBMITTED get 403 { "error": "merchant_not_active" } instead of a payment. Test mode (sk_test_*) bypasses this gate.

Payment Parameters

Required Parameters

amountnumber

Payment amount in decimal format (e.g., 99.99). Must be greater than 0.

customer.emailstring

Customer email address. Used for payment receipts and customer identification.

Optional Parameters

currencystring

Currency code (USD, EUR, GBP, CAD, AUD, HKD, JPY, KRW, etc.). Defaults to USD. Must be supported by at least one of your assigned payment providers.

descriptionstring

Payment description. Helps you and your customer identify the payment purpose.

customer.firstNamestring

Customer first name. Recommended — required by most payment providers for compliance.

customer.lastNamestring

Customer last name. Recommended — required by most payment providers for compliance.

customer.phonestring

Customer phone number. Pre-fills the phone field on the payment form.

customer.ipstring

Customer 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.billingobject

Billing address object. Pre-fills billing address fields on the payment form.
Fields: address, city, state, country, postalCode
billing.country (ISO 2, e.g. BG) drives provider routing — send it whenever you can. If omitted, we derive the country from the card's issuing BIN; if that is unknown too, routing falls back to your account's aggregators. Call GET /api/v1/config to see which countries your providers cover.

languagestring

Payment form language. Defaults to en. Supported: en (English), fr (French)

Webhook & Tracking

webhookUrlstring

Custom webhook URL for this specific payment. Overrides your default webhook URL configured in the dashboard.

metadataobject

Custom data object attached to the payment. Store any custom information (order IDs, user IDs, etc.) — returned in webhooks and API responses.

returnUrlstring

General redirect URL for both success and failure outcomes.

successUrlstring

Success-specific redirect. Overrides returnUrl for successful payments.

failureUrlstring

Failure-specific redirect. Overrides returnUrl for failed payments.

SDK (JavaScript)

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
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": "cm4h1abc123def456",
#     "status": "PENDING",
#     "amount": 99.99,
#     "currency": "USD",
#     "paymentUrl": "https://fluxpay.online/payment/generic/cm4h1abc123def456",
#     "customer": { ... },
#     "createdAt": "2025-01-23T10:30:00Z"
#   }
# }

What Happens After Creation?

1
Payment Link CreatedYou receive a unique payment URL.
2
Send to CustomerShare this URL via email, SMS, or redirect them directly.
3
Customer Opens LinkCustomer is redirected to the payment page where they enter card details.
4
Intelligent RoutingFluxPay automatically selects the best payment provider based on amount, currency, and success rates.
5
Automatic FailoverIf payment fails, system automatically tries different providers (cascade).
6
Webhook NotificationYou receive real-time webhook when payment completes, fails, or requires action.

How cascade/routing works: a single charge can try many providers before it resolves — up to 20 attempts total, 2 attempts per provider, card cascade first (2D), then 3D fallback if needed. This is why one charge can show up in the logs of several providers, and why processing time varies per attempt rather than being a fixed, single round-trip.

Supported Currencies & Countries

Before you charge, call this endpoint to see what your account can process — the currencies and customer countries covered by your active providers, plus the card brands accepted. Use it to validate a currency/country up front instead of hitting NO_ROUTE_AVAILABLE.

cURL
curl https://fluxpay.online/api/v1/config \
  -H "Authorization: Bearer sk_live_xxx"

Response

JSON
{
  "methods": [
    {
      "method": "CREDIT_CARD",
      "currencies": ["*"],                       // "*" = any currency (converted to the provider's currency)
      "countries": ["AT", "BE", "BG", "DE", "FR", "..."],  // card coverage — NOT necessarily every country
      "fxConversion": true                       // this method auto-converts currencies
    },
    {
      "method": "APM",
      "currencies": ["USD", "EUR", "BRL", "..."],
      "countries": ["*"],                        // this method may cover all countries
      "fxConversion": false
    }
  ],
  "cardBrands": ["VISA", "MASTERCARD", "AMEX", "DISCOVER", "JCB", "DINERS", "UNIONPAY"]
}

Per payment method. Coverage is broken out by method (e.g. CREDIT_CARD, APM) because they differ — cards may be limited to specific countries while an alternative method covers more. Check the entry for the method you intend to use.

Currency conversion. When a method's fxConversion is true (or its currencies is ["*"]), you may charge in any currency — we convert it to a currency the selected provider accepts and settle the difference. Routing is still gated by that method's countries: send customer.billing.country, or we infer it from the card BIN. ["*"] means all countries.

Payment Methods

Multiple ways for your customers to pay.

Credit & Debit Cards

Default Method

Accept all major credit and debit cards with 3D Secure authentication support.

Visa, Mastercard, Amex, Discover
3D Secure 2.0 authentication
Multi-provider cascade for higher approval
Global coverage in 100+ countries

New acquirer: PacePay card acquiring (hosted 3DS) has joined the cascade. Routing is automatic — no integration change is required on your side.

Open Banking

Bank Transfers

Instant bank-to-bank payments via Open Banking. Lower fees than cards with direct settlement.

Lower transaction fees than cards
Instant bank authentication
No chargebacks
EU/EEA bank coverage (PSD2 compliant)

Asia Payments

Regional Methods

Accept local payment methods across Asia — bank transfers, virtual accounts, and credit cards in local currencies.

HKD Bank Transfer (Hong Kong)
JPY Credit Card / JCB (Japan)
KRW Virtual Account (South Korea)
Hosted payment page — no PCI scope

How It Works

1
Customer Opens Payment LinkThe payment page automatically displays available payment methods based on your configuration.
2
Customer Selects Payment MethodCard: enters card details directly. Open Banking: selects their bank and authenticates via their banking app.
3
FluxPay Processes PaymentOur intelligent routing selects the optimal provider. For cards, we use cascade logic for higher approval rates.
4
You Receive WebhookYou receive a payment.success or payment.failed webhook with the transaction details.

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.

Supported Regions
  • EU (27 countries) — EUR payments
  • United Kingdom (GB) — GBP payments
  • Australia (AU) — AUD payments
  • Canada (CA) — CAD payments
How It Works
  • 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.

Asia Payments — Supported Currencies & Methods

Accept payments in local Asian currencies via bank transfers, virtual accounts, and credit cards. Customers are redirected to a secure hosted payment page to complete the transaction.

CurrencyCountryPayment MethodLimits
HKDHong Kong (HK)Bank Transfer100 – 100,000 HKD
JPYJapan (JP)Credit Card (JCB)100 – 1,000,000 JPY
KRWSouth Korea (KR)Virtual Account1,000 – 500,000 KRW
How It Works
  • 1. Create a payment link with HKD, JPY, or KRW currency
  • 2. Customer opens the payment page and fills their details
  • 3. Customer is redirected to a secure hosted payment page
  • 4. Payment is confirmed via webhook — no card data touches your server
API Example — HKD Bank Transfer
curl -X POST https://fluxpay.online/api/v1/payments \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 500,
    "currency": "HKD",
    "customer": {
      "email": "customer@example.com",
      "firstName": "Wing",
      "lastName": "Chan",
      "phone": "+852-9123-4567",
      "billing": {
        "address": "88 Queensway",
        "city": "Hong Kong",
        "state": "HK",
        "country": "HK",
        "postalCode": "000000"
      }
    }
  }'
API Example — JPY Credit Card
curl -X POST https://fluxpay.online/api/v1/payments \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 5000,
    "currency": "JPY",
    "customer": {
      "email": "tanaka@example.jp",
      "firstName": "Yuki",
      "lastName": "Tanaka",
      "phone": "+81-90-1234-5678",
      "billing": {
        "address": "1-1 Marunouchi",
        "city": "Tokyo",
        "state": "TK",
        "country": "JP",
        "postalCode": "1000005"
      }
    }
  }'
API Example — KRW Virtual Account
curl -X POST https://fluxpay.online/api/v1/payments \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 50000,
    "currency": "KRW",
    "customer": {
      "email": "kim@example.kr",
      "firstName": "Minjun",
      "lastName": "Kim",
      "phone": "+82-10-1234-5678",
      "billing": {
        "address": "123 Gangnam-daero",
        "city": "Seoul",
        "state": "SE",
        "country": "KR",
        "postalCode": "06164"
      }
    }
  }'

Note: JPY and KRW do not support decimal amounts — use whole numbers only (e.g., 5000 not 50.00). The response includes a paymentUrl — redirect the customer there to complete payment.

Configure Webhooks

Receive real-time payment notifications.

Two Ways to Configure

Option 1: Dashboard (Default)

Set a default webhook URL in your dashboard:

  1. 1. Go to Settings → Webhooks
  2. 2. Enter your webhook URL
  3. 3. Select events to receive
  4. 4. Copy webhook secret for signature verification
Option 2: Per-Payment Override

Include webhookUrl in your API request:

webhookUrl: "https://your-app.com/webhooks"

Webhook Events

payment.success

Payment completed successfully — fulfill order and send confirmation

payment.failed

Payment failed after all retry attempts — notify customer

payment.pending

Payment processing — update order status to "processing"

payment.refunded

Full refund processed — update order to refunded

payment.partially_refunded

Partial refund processed — amount field reflects the refunded amount

payment.disputed

Chargeback or dispute opened on this payment

dispute.won

Dispute resolved in your favour

dispute.lost

Dispute resolved against you — funds returned to customer

dispute.evidence_required

You must submit evidence to defend this dispute

Retry Policy

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. The X-Test-Mode header is sent on the initial delivery attempt only — it is not resent on retries.

Webhook Payload Example
# WEBHOOK PAYLOAD EXAMPLE (payment.failed)
# 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.failed         ← event type is here
#   X-Transaction-Id: cm4h1abc123def456
#   X-Test-Mode: false                      ← only sent on the initial delivery, NOT on retries
#   X-Retry-Attempt: 2                      ← only present on retries (attempt 2, 3, 4)

# The request body IS the payload — no wrapper object:
{
  "transactionId": "cm4h1abc123def456",
  "reference": "cm4h1def456ghi789",
  "amount": 99.99,
  "currency": "USD",
  "status": "FAILED",
  "failureReason": "Card declined by issuer.",
  "supportReference": "POL-9F3K2A1B7C",
  "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 seconds

failureReason is included whenever the payment failed. supportReference is included only when a policy/fraud rule (not a plain provider decline) blocked the payment — quote it when contacting support. Both fields are omitted entirely on payment.success payloads.

Affiliate Tracking

New

Attribute payment links and transactions to your own affiliates or sub-partners, then see a full-financials breakdown per affiliate over any time period — in your dashboard and over the API. Tags are free-form and auto-register on first use, so there is no setup step.

Enabling affiliate tracking

Affiliate tracking is enabled per account by the FluxPay team. Contact your account manager or support@fluxpay.online to switch it on. Once enabled, the Affiliates page appears in your dashboard and the affiliate fields below become active on the API.

While disabled, any affiliate parameter returns 403 — Affiliate tracking is not enabled for this merchant rather than failing silently.

Affiliate breakdown in the FluxPay merchant dashboard — per-affiliate volume, transactions, success rate, fees, net, refunds and chargebacks with an Untagged row and totals.
The Affiliates page (Dashboard → Affiliates) — breakdown per affiliate with a period selector and management controls.

1. Tag a payment or link via the API

Add an optional affiliateTag when you create a payment, a payment link, or an S2S charge. Any string works — an unknown tag auto-creates the affiliate. Tags are normalized (lowercased, trimmed), so "Partner A" and "partner-a" are the same affiliate.

SDK (JavaScript)

JavaScript
const { payment } = await fluxpay.createPayment({
  amount: 149.99,
  currency: 'USD',
  customer: {
    email: 'customer@example.com',
    firstName: 'Jane',
    lastName: 'Smith',
  },
  affiliateTag: 'partner-a', // attribute to this affiliate
});

cURL (HTTP API)

cURL
curl -X POST https://fluxpay.online/api/v1/payments \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 149.99,
    "currency": "USD",
    "customer": { "email": "customer@example.com" },
    "affiliateTag": "partner-a"
  }'

The same affiliateTag field is accepted on POST /api/v1/payments, POST /api/v1/payments/charge (S2S), and POST /api/merchant/payment-links.

2. Read the breakdown via the API

Pull the same numbers the dashboard shows. Group by day, week (Monday-start), or month, over any range up to 366 days.

cURL
curl "https://fluxpay.online/api/v1/affiliates/breakdown?from=2026-07-01&to=2026-07-31&groupBy=day" \
  -H "Authorization: Bearer sk_live_xxx"

Response

JSON
{
  "rows": [
    {
      "affiliateId": "aff_...",
      "tag": "partner-a",
      "displayName": "Partner A",
      "summary": {
        "grossVolume": 150.00,
        "transactionCount": 2,
        "successfulCount": 1,
        "failedCount": 1,
        "successRate": 0.5,
        "averageTicket": 150.00,
        "totalFees": 7.50,
        "netAmount": 117.50,
        "refundCount": 1,  "refundVolume": 25.00,
        "chargebackCount": 0, "chargebackVolume": 0.00
      },
      "buckets": [ { "period": "2026-07-28", "grossVolume": 150.00, "...": "..." } ]
    }
  ],
  "totals": { "grossVolume": 350.00, "...": "..." }
  // an "Untagged" row (affiliateId: null) is always included so totals reconcile
}

3. Manage affiliates via the API

Full CRUD is available. Deactivating is soft — it blocks new tagging with that tag but keeps all history in reports.

GET/api/v1/affiliates— list affiliates
POST/api/v1/affiliates— create { tag, displayName? }
PATCH/api/v1/affiliates/{id}— rename / toggle isActive
DELETE/api/v1/affiliates/{id}— soft-deactivate

Prefer the dashboard? Everything above is also on the Affiliates page — pick a period, sort the breakdown table, expand a row for its time-series, and create/rename/deactivate affiliates inline. The affiliate field also appears on the payment-link form as a combobox.

Redirect 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_idUnique transaction identifier
amountPayment amount
currencyCurrency code (USD, EUR, etc.)
referenceExternal reference ID

Tip: Always verify payment status via webhook or API — do not rely solely on redirect URL parameters.

cURL Example
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

HTML / iFrame Example
<!-- OPTION 1: Inline iFrame -->
<iframe
  src="https://fluxpay.online/payment/generic/cm4h1abc123def456"
  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 Example
// 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-muted-foreground 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

Always Create Payments Server-SideNever expose your API key in frontend code. Create payments on your backend and pass the payment URL to the frontend.
Use Webhooks for VerificationAlways verify payment completion via webhooks — do not rely solely on redirect parameters or iframe events.
Mobile ConsiderationsiFrames work on mobile but may have limited space. Consider using redirect method for mobile users.
3D Secure CompatibilitySome banks open 3DS authentication in a popup. Ensure your site allows popups from fluxpay.online.

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 puts raw card data in your environment, so you must meet the PCI DSS obligations applicable to that environment. If you are not approved for direct card handling, use the Hosted Checkout integration instead.

Hosted Checkout

  • Customer redirected to FluxPay form
  • FluxPay handles card data
  • Lower PCI scope; complete the PCI validation applicable to your integration
  • 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

Card-acquiring gate: this endpoint requires cardAcquiringEnabled on your merchant account. If it is not enabled you get 403 "Card acquiring is not enabled for this merchant" instead of a charge attempt. Contact support to enable it.

SDK (JavaScript)

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
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

amountnumber

Transaction amount (e.g., 99.99)

currencystring

ISO 4217 currency code (default: USD)

card.numberstring

Card number (13-19 digits)

card.holderNamestring

Cardholder name as on card

card.expiryMonthstring

Expiry month (01-12)

card.expiryYearstring

Expiry year — must be 2-digit (e.g., 25, not 2025). A 4-digit year returns 400 "Invalid expiry year. Must be 2-digit year (e.g., 25)".

card.cvvstring

CVV/CVC (3-4 digits)

customer.emailstring

Customer email address

customer.firstNamestring

Customer first name

customer.lastNamestring

Customer last name

customer.phonestring

Phone with country code

customer.ipstring

Customer IP for fraud/geo checks

customer.billingobject

Billing address (address, city, state, postalCode, country)

descriptionstring

Payment description

metadataobject

Custom key-value metadata

webhookUrlstring

Override webhook URL for this payment

returnUrlstring

Return URL after 3DS redirect

affiliateTagstring

Attribute this charge to an affiliate/sub-partner tag (see Affiliate Tracking)

Response — Success (2D)

200 OK
{
  "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

200 OK
{
  "success": true,
  "payment": {
    "id": "cm4h1abc123",
    "status": "PENDING",
    "requires3DS": true,
    "redirectUrl": "https://provider.com/3ds?session=xxx",
    "amount": 99.99,
    "currency": "USD"
  }
}

Response — Declined

200 OK
{
  "success": false,
  "error": "Payment declined",
  "payment": {
    "id": "cm4h1abc123",
    "status": "FAILED",
    "failureReason": "Card declined by issuer."
  }
}

Response — Declined (policy/fraud block)

When a business-rule or fraud/risk policy — not the card issuer — blocks the charge, the response carries extra fields so you can show the customer a clear reason and a support reference:

200 OK
{
  "success": false,
  "error": "This transaction was blocked by a risk policy.",
  "code": "POLICY_BLOCKED",
  "action": "BLOCK",
  "supportReference": "POL-9F3K2A1B7C",
  "payment": {
    "id": "cm4h1abc123",
    "status": "FAILED",
    "failureReason": "This transaction was blocked by a risk policy."
  }
}

code and action come from the policy that fired; supportReference is safe to show to the customer and quote when contacting support. Ordinary provider declines (above) do not include these fields.

Idempotency

Send an Idempotency-Key header on POST /api/v1/payments/charge to safely retry a request (e.g. after a network timeout) without double-charging the customer.

cURL — Idempotent charge
curl -X POST https://fluxpay.online/api/v1/payments/charge \
  -H "Authorization: Bearer sk_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-1234-attempt-1" \
  -d '{
    "amount": 99.99,
    "currency": "USD",
    "card": { "number": "4111111111111111", "holderName": "JOHN DOE", "expiryMonth": "12", "expiryYear": "25", "cvv": "123" },
    "customer": { "email": "john@example.com" }
  }'

# Replaying the same key while the original request is still resolving
# (or after it already resolved) returns, without charging again:
# HTTP 409
# {
#   "error": "Duplicate request for this Idempotency-Key",
#   "code": "IDEMPOTENCY_REPLAY"
# }

Key lifecycle: a decline releases the key — the same key can be retried with a corrected request. A success, a pending status, or a 3DS redirect in flight all keep the key claimed, so retrying with that key while the original charge is still resolving (or already succeeded) is rejected with 409 rather than firing a second charge.

3DS Handling

Some transactions require 3D Secure authentication. When this happens, the response will includerequires3DS: true and aredirectUrl.

3DS Flow

  1. 1Call POST /api/v1/payments/charge with card details
  2. 2Check response — if requires3DS is true, redirect the customer to redirectUrl
  3. 3Customer completes 3DS on the provider's page
  4. 4Customer returns to your returnUrl (if provided)
  5. 5Poll GET /api/v1/payments?id={id} or listen for the webhook to get final status
Node.js — 3DS Handling
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

Node.js SDK
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. The outcome is driven by the test card number (see the Test Cards table): …0000 completes, …1111 declines, …2222 triggers 3DS, and …3333 stays pending.

Test Mode cURL
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" }
  }'

Refunds

POST /api/v1/refunds initiates a full or partial refund on an existing transaction, using the same Bearer sk_live_* / sk_test_* API key as the endpoints above.

Request

cURL
curl -X POST https://fluxpay.online/api/v1/refunds \
  -H "Authorization: Bearer sk_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "transactionId": "cm4h1abc123def456",
    "amount": 25.00,
    "reason": "Customer requested partial refund"
  }'

Response (201)

JSON
{
  "success": true,
  "refund": {
    "id": "cm4h1ref789ghi012",
    "status": "PENDING",
    "amount": 25.00,
    "currency": "USD",
    "type": "PARTIAL",
    "createdAt": "2026-03-24T10:05:00.000Z"
  }
}
transactionIdstring

The FluxPay transaction ID to refund

amountnumber

Refund amount. Omit for a full refund; a smaller value issues a partial refund

reasonstring

Free-text reason, stored for your records

In test mode, the refund is auto-processed to a final status. In live mode, it is created as PENDING and requires admin approval before funds move. A payment.refunded or payment.partially_refunded webhook is sent once the refund is finalized. GET /api/v1/refunds lists refunds (filterable by status/transactionId, cursor-paginated).

WooCommerce Integration

Accept payments in your WooCommerce store with the official FluxPay plugin. No code required.

Requirements

WordPress
5.8+
WooCommerce
7.0+
PHP
7.4+
SSL
HTTPS required

Installation

1

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.

2

Enter Your API Key

Go to WooCommerce > Settings > Payments > FluxPay. Enter the API key from your FluxPay Dashboard (Settings > API Keys).

3

Enable the Gateway

Toggle the Enable/Disable switch to On. Optionally set a custom title and description shown at checkout.

4

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

SettingDescriptionDefault
Enable/DisableShow FluxPay at checkoutDisabled
TitlePayment method name shown to customersCredit / Debit Card
DescriptionPayment method description at checkoutPay securely via FluxPay
API KeyYour FluxPay API key (sk_live_... or sk_test_...)--
Test ModeUse test API key for sandbox transactionsOff

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. Configure this webhook URL and its secret in FluxPay before accepting orders. The plugin rejects unsigned webhooks 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 Webhook Verification Example
<?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);
}

Shopify Integration

Coming soon. Get notified when it launches.

Notify Me
    FluxPay — Documentation