Skip to Content
WooCommerce

WooCommerce Custom Payment Gateway: 2026 Build Guide

WooCommerce Custom Payment Gateway: 2026 Build Guide

WooCommerce custom payment gateway work is the right path when your store needs a payment processor WooCommerce does not officially support — regional gateways, niche industry processors (cannabis, firearms, adult), or proprietary corporate payment systems. Building a payment gateway is more work than most clients expect because it touches PCI compliance, webhook reliability, refund accounting, and edge cases like partial captures.

This guide covers the custom payment gateway patterns I run on every WC payment integration in 2026. The class architecture, webhook handling, refund flow, PCI scope reduction, and the testing patterns that catch real production issues before they hit live customers.

Quick verdict: extend WC_Payment_Gateway, use hosted fields or redirect flow to keep PCI scope minimal, handle webhooks for async confirmations, implement refund support, and test with the processor’s sandbox environment before shipping. Skipping any of these creates real production failures with real refund risk.

When to build vs use existing gateway plugin

For supported processors, the official WooCommerce plugins are usually better than custom:

  • Stripe, PayPal, Square, Authorize.Net — official WC plugins exist; build custom only for niche features
  • Regional gateways (PayU, Razorpay, Rapyd, dLocal, Adyen) — usually have community/official plugins; check first
  • Niche industry (high-risk processors, crypto) — often need custom because mainstream plugins do not exist
  • Corporate ERP/payment systems (SAP, Oracle internal) — always custom
  • Subscription-only processors (Recurly, Chargify) — combine with WC Subscriptions; custom integration is non-trivial

The WC_Payment_Gateway architecture

Every custom WooCommerce payment gateway extends WC_Payment_Gateway and implements a known interface:

  • __construct() — set id, method_title, method_description
  • init_form_fields() — admin settings (API keys, sandbox mode, etc.)
  • process_payment($order_id) — main entry; return [‘result’ => ‘success|failure’, ‘redirect’ => $url]
  • process_refund($order_id, $amount, $reason) — refund handler
  • webhook() — handle incoming webhook (custom method)
  • payment_fields() — render form fields on checkout
  • validate_fields() — validate user input before submission

PCI scope — keep it minimal

PCI DSS compliance applies to any system that touches cardholder data. Two architectures minimize PCI scope dramatically:

Avoid direct card processing: NEVER accept card data directly into your server. PCI scope expands to SAQ D — annual audits, quarterly scans, dramatically higher compliance burden. Even if your processor supports it, avoid this architecture. The few percent of conversion lift from “no redirect” is not worth the compliance cost.

Hosted fields (iframe)

Card data is entered in an iframe served from the payment processor’s domain. Your server never sees card numbers. PCI scope is SAQ A or SAQ A-EP. Most modern gateways (Stripe Elements, Braintree Hosted Fields, Square Web SDK) work this way.

Redirect flow

User redirects to processor’s checkout page, completes payment, redirects back. PCI scope is SAQ A. Common with PayPal, regional gateways. Friction is higher than hosted fields but PCI burden is lowest.

Webhook handling for async confirmations

Most payments are NOT confirmed synchronously — the processor returns a “pending” status and confirms later via webhook. Build robust webhook handling:

  • Register webhook endpoint at my-plugin/v1/webhooks/[gateway]
  • Verify webhook signature (HMAC-SHA256 or processor-specific)
  • Idempotency — store webhook IDs to prevent double-processing on retries
  • Update WooCommerce order status based on webhook event (paid, failed, refunded, disputed)
  • Queue heavy work via Action Scheduler — webhook senders expect fast 200 responses
  • Log every webhook to audit table for compliance + debugging

Refund flow

Implement process_refund() properly so admins can refund from the WC admin without touching the processor dashboard:

  • Accept partial refunds — $amount may be less than order total
  • Call processor’s refund API; handle their idempotency keys
  • Update order with refund record via wc_create_refund()
  • Handle refund failures gracefully — return WP_Error with reason
  • Update payment ledger / accounting integration if connected

Order status mapping

Map processor statuses to WooCommerce order statuses correctly:

Processor statusWC statusWhen
Authorized (not captured)on-holdManual capture pending
Captured / PaidprocessingStandard physical product order
Captured / Paid (digital)completedDigital product, no fulfillment needed
FailedfailedPayment declined
Refunded (full)refundedFull refund processed
Refunded (partial)processingOrder remains active for partial
Disputed (chargeback)on-holdManual review needed

Testing with sandbox environments

Every reputable processor offers a sandbox/test mode. Test thoroughly before going live:

  • Successful payment — happy path, order completes
  • Declined payment — error message displays correctly
  • 3D Secure challenge — flow handles authentication step
  • Async confirmation delay — order shows “processing” until webhook arrives
  • Refund (full and partial) — refund processes through processor and updates WC
  • Failed webhook delivery — processor retries; idempotency prevents double-processing
  • Network failure mid-payment — orphan payments handled correctly

Going live — the production checklist

Before flipping the gateway to live mode in production:

  • PCI compliance documented (SAQ A or A-EP signed)
  • Webhook endpoint signature verification tested
  • Sandbox-to-production credential rotation completed
  • Refund flow tested with live mode (one small real transaction)
  • Failure scenarios tested (decline, 3DS, async)
  • Monitoring + alerting configured for webhook failures
  • Customer-facing error messages reviewed for clarity
  • Refund SOP documented for support team

Common payment gateway mistakes

Patterns that cause real production issues:

  • No webhook signature verification — anyone can POST fake webhooks to mark orders paid
  • No idempotency on webhooks — duplicate webhooks process twice; double-shipped orders, double-counted revenue
  • Inline-processing in webhook handler — slow handlers cause webhook timeouts; processor retries; idempotency saves you
  • Hardcoded sandbox credentials — staging gets accidentally pushed to prod; payments go to wrong account
  • No refund support — admins must use processor dashboard; accounting drifts from WooCommerce

Architecture — FAQs

How long does a custom WooCommerce payment gateway take to build?

Realistic timeline: 4-10 weeks for a properly-scoped gateway with hosted fields, webhooks, refunds, full test suite. Add 2-4 weeks for 3D Secure if your audience requires it. Add 2-4 weeks if subscription support is needed. Add 4+ weeks if the processor has poor documentation or unstable sandbox. Anything quoted under 4 weeks is missing critical features.

Do I need to be PCI compliant to ship a custom payment gateway?

Yes, but the scope depends on architecture. With hosted fields or redirect flow, your scope is SAQ A or SAQ A-EP — self-attestation, no external audit. With direct card processing, scope expands to SAQ D — annual external audit, quarterly ASV scans, ~$15k-$50k/yr in compliance overhead. Choose hosted fields whenever possible.

Can I support 3D Secure / SCA on a custom gateway?

Yes, but it adds complexity. 3DS is a redirect/iframe challenge step between authorization and capture. Modern processors (Stripe, Braintree) handle 3DS flow automatically with hosted fields. For older processors that require manual 3DS integration, budget 2-4 extra weeks. SCA (PSD2) is mandatory for European cards — required, not optional.

Operations — FAQs

How do I monitor a payment gateway in production?

Track three metrics. (1) Authorization success rate — should be 92-97% for good gateways; below 90% indicates fraud rules too strict or technical issues. (2) Webhook delivery success rate — should be 99.9%+; failures mean orders stuck in pending. (3) Refund success rate. Alert via Slack or PagerDuty when any drops below threshold for 5+ minutes.

What happens when the processor has an outage?

Orders fail at checkout. Two mitigations. (1) Fallback gateway — register a second processor; route to it when primary errors. (2) Save abandoned cart and offer to retry payment via email when processor recovers. Most processors have 99.9%+ uptime, so outages are rare but real — design for graceful degradation.

How do I handle disputes / chargebacks?

Webhooks for dispute events should set order status to on-hold and trigger admin notification. Build admin UI for viewing dispute details + uploading evidence to processor. Most processors require evidence within 7-21 days. For high-volume stores, integrate with a dispute management service (Chargehound, Justt) — these automate evidence submission and have ~25-40% better win rates than manual handling.

Need a custom payment gateway built for production WooCommerce?

Custom WooCommerce gateways must handle idempotency, webhook signature verification, tokenization, and Cart/Checkout Blocks registration — none of which are negotiable in production. I build payment gateway extensions that stay PCI SAQ-A, handle 3DS/SCA correctly, and never leak money to refresh-double-charges or spoofed webhooks.

See my WooCommerce plugin customization service

Leave a Reply