NewVerification layer for wallet payments. DPay can now apply a small adjustment to the amount wallet payers are asked to send, so same-amount payments verify automatically instead of waiting for manual review. Recommended — enable it in Settings. amount_paid reports what was received.Read more

DPay for WooCommerce

Take Easypaisa, JazzCash, NayaPay and bank-transfer payments on a WordPress shop, verified automatically, straight into your own account. No code: install the plugin, paste one key, done.

Download: dpay-for-woocommerce.zip · version 1.2.1 · GPL-2.0 · needs WordPress 6.2+, WooCommerce 7.6+, PHP 7.4+.

What it does

  • Adds Bank transfer / Easypaisa / JazzCash as a payment method, with the DPay logo, in both the classic checkout and the block checkout.
  • Sends the customer to DPay's hosted checkout for the order total. Paisa is rounded up to whole rupees (PKR 1,850.50 becomes PKR 1,851), because no Pakistani transfer carries paisa; the order note records what was paid.
  • Marks the order paid the moment DPay verifies the transfer: three ways, so it works even where webhooks cannot reach: the signed webhook, the customer coming back to the order page (which then refreshes itself until confirmed), and a sync every five minutes for any order still pending.
  • Puts the DPay reference, the customer's bank and the status on the order, with a Check with DPay now button and a link to the payment in your DPay dashboard.
  • Registers its webhook with DPay by itself when you save the key, and rotates the secret if the site is reinstalled.
  • Supports High-Performance Order Storage (HPOS) and the block cart and checkout.

Nothing about the money passes through the plugin or through DPay: the customer transfers into your own NayaPay, Raqami or Meezan account, DPay only proves it arrived.

Before you start

  1. A DPay account at dpay.com.pk with a receiving account (NayaPay or Raqami recommended: payments confirm in seconds) and your bank alerts forwarded to DPay under Integrations.
  2. An API key from Developers. A test key (dpay_test_sk_…) is for integration testing, but normal test checkouts can verify real transfers. A live key (dpay_live_sk_…) needs an eligible active trial or plan and a verified identity.
  3. The shop's currency set to PKR (WooCommerce → Settings → General). DPay is not offered at checkout in any other currency.

Install

  1. Download dpay-for-woocommerce.zip.
  2. In WordPress: Plugins → Add New → Upload Plugin, choose the zip, Install Now, then Activate.
  3. WooCommerce → Settings → Payments → DPay (or the *Settings* link under the plugin on the Plugins screen).
  4. Keep Offer DPay at checkout enabled, paste the API key and Save changes. The status panel at the top should now read Connected · your business name, and Webhook · Registered with your site's address.
  5. On Developers → Webhooks, press Send test event next to your site. The settings page shows *Last event received* once it lands.

That is the whole setup. The title and description shown to customers, how long a checkout waits for the transfer (15 minutes by default, up to 24 hours), and the checkout popup are on the same page.

The checkout popup

On a desktop browser the DPay payment page opens in a window over your checkout, so the customer never leaves your shop: pick a bank, see the account to pay into, and the moment the transfer is verified the popup closes onto your order-received page. On a phone the customer is taken to the payment page itself — that is where switching to Easypaisa or a banking app and back works best. Closing the popup lands on the order-received page too, which keeps checking for the transfer and offers a way back to the payment page or to another method. Untick *Checkout popup* in the gateway settings to always redirect instead.

The popup loads the payment page at ?embed=1; it only renders inside a page on the site that created the session, and the messages it sends your page carry the session id and status alone — the order is still confirmed by asking DPay, never by the popup.

Try it before going live

With a test key, place an order on your own shop. You land on DPay's checkout with the order total and a reference like DPAY-8F4K29. A normal test checkout still uses your real receiving account: test mode is not automatically a fake-money sandbox. First check the connection and Send test event; then perform a controlled end-to-end test with a small real transfer of your own and check the resulting order status. No-money simulation is restricted to specially enabled DPay demo environments and is not available to every merchant. Switch to an eligible live key only after completing your checks.

How an order moves

What happensWooCommerce order
Customer presses *Pay by bank transfer*Pending payment, note with the DPay reference; customer is on DPay's checkout (in the popup on desktop)
Transfer verifiedProcessing (or *Completed* for virtual goods), payment_complete() with the DPay session id as transaction id
DPay finds two transfers that could both be this paymentOn hold, note asking you to pick one in the DPay dashboard; the order updates itself when you do
Customer transfers a little more than the orderOn hold for review in the DPay dashboard, with the extra flagged — accept it (and refund the difference) or reject; if the exact amount also arrives it settles on its own
Checkout window closed without a transferstays Pending with a note; the customer can pay again from *My account → Orders*, and a late transfer honoured in DPay still lands
Customer presses *cancel* on DPaystays Pending; they are returned to the order's pay page with a notice
Payment failed at DPayFailed
Refund or dispute recorded at DPaynote on the order (refunds are transfers you make from your own bank; record them in WooCommerce as usual)

A customer who comes back to pay a pending order gets the same DPay checkout and reference while it is still open; a new one only once it has closed.

Advance and cash on delivery

Many shops take a small advance and the rest in cash when the parcel arrives: it cuts fake orders, and the delivery charge is covered if a parcel comes back. Under Advance payment in the plugin's settings (version 1.2):

  • Offer an advance: Off (the default; customers pay the whole order), Customer chooses (the checkout offers the full amount or an advance with the rest on delivery), or Advance only.
  • Advance amount: a fixed amount (Rs 250 is common), a percentage of the order total, or the order's delivery charge. Whole rupees, rounded up. An order smaller than the advance is paid in full.

The customer pays the advance on DPay's checkout like any other payment; the page says it is an advance and what is left for delivery. Once DPay verifies it:

Order statusProcessing, ready to ship
Payment methodCash on delivery (cod), titled "Cash on delivery (Rs 250 advance paid via DPay)"
Order totalthe balance: a line Advance paid (DPay) takes the advance off, and the total is labelled To pay on delivery in emails and on the order page

Courier plugins decide whether to collect cash by checking for the cod payment method, and collect the order total. Both are now right, so the rider collects exactly the balance. Your sales reports show the advance as that negative line; the advance itself is in your bank account, with the DPay reference on the order. A customer who changes their mind between the full amount and the advance on the order's pay page gets a new DPay checkout, and the old one is closed so they cannot pay twice.

The received amount

With *Verification layer for wallet payments* on in your DPay Settings (recommended), DPay may apply a small adjustment to the amount a customer paying from a wallet is asked to send, so payments of the same amount verify automatically instead of waiting for your manual review. The order note and the _dpay_paid_amount meta record what DPay actually received; the order is still marked paid in full. Reconcile your bank statement against that figure. The setting is off until you enable it, and customers are never told how the amount is chosen.

If the webhook cannot reach your site

Some hosts block the WordPress REST API, some sites sit behind a login or a firewall. The plugin does not depend on the webhook: the customer's return to the order page checks with DPay at once, and every pending DPay order is checked every five minutes by WP-Cron. Orders confirm a little later, not never. The settings page tells you whether a webhook has ever arrived.

If WP-Cron is disabled on your host (DISABLE_WP_CRON), make sure a system cron hits wp-cron.php, as WooCommerce itself already needs.

Where things are

  • Logs: WooCommerce → Status → Logs → source dpay.
  • Order screen: the *DPay* box on the right shows the reference, status, bank and amount (and, for an advance, what was paid and what is left), with *Check with DPay now* and *Open in DPay*. It stays on an advance order after it turns cash on delivery.
  • Order meta for an advance: _dpay_plan (full or advance), _dpay_advance (asked for), _dpay_advance_paid (verified), _dpay_balance_due (left to collect).
  • Options: woocommerce_dpay_settings (the settings), dpay_wc_webhook (endpoint id, URL and signing secret), dpay_wc_account (who the key belongs to). Deleting the plugin removes all three; orders and their notes stay.
  • Filters: dpay_wc_payment_session_body (the session DPay is asked to create — add metadata, change the description), dpay_wc_webhook_url, dpay_wc_api_base_url.
  • Constant: DPAY_API_BASE_URL in wp-config.php points the plugin at a sandbox or self-hosted DPay.

Questions

Can customers pay by card? No. DPay is bank transfer and wallets, which is how 92% of Pakistani e-commerce pays. Run a card gateway alongside if you need one.

Is there a fee per order? No. DPay charges a flat plan price; the plugin is free.

Can customers pay part now and the rest on delivery? Yes, from version 1.2: see Advance and cash on delivery above. Separate deposits plugins are not supported; the plugin's own advance replaces them for cash-on-delivery shops.

Does it work with subscriptions? The plugin supports one-off orders (products). Recurring charges need a card on file, which bank transfer cannot do; DPay's own subscriptions bill by invoice instead.

Something is wrong. Write to support@dpay.com.pk with the order number and the DPay reference, or check the dpay log first.