WooCommerce
Install and configure the Qasimha Payment Gateway plugin for WooCommerce, including webhooks, refunds and fulfilment.
The Qasimha Payment Gateway plugin adds "Qasimha — pay in instalments" to a WooCommerce store. It uses the Qasimha PHP SDK for every API call, keeps your secret key encrypted in the WordPress database, and loads only the instalment widget (with your publishable key) in the shopper's browser.
Requirements
| Item | Requirement |
|---|---|
| PHP | 8.1 or later |
| WordPress | 6.4 or later |
| WooCommerce | 8.0 or later; HPOS and cart/checkout Blocks compatible |
| Store currency | SAR (the method hides itself otherwise) |
| HTTPS | Required (plain http works only on localhost) |
| Plugin slug | qasimha-payment-gateway |
| License | GPL-2.0-or-later |
Install
- In WordPress admin, go to Plugins → Add New → Upload Plugin.
- Upload the release zip and activate the plugin. The zip already contains the SDK in its
vendor/directory.
You can also install it from the WordPress.org plugin directory.
Developers installing from source:
composer install --no-devThen copy or symlink the directory to wp-content/plugins/qasimha-payment-gateway.
Configure
Go to WooCommerce → Settings → Payments → Qasimha.
| Setting | What to enter |
|---|---|
| Environment | Sandbox (sk_test_ / pk_test_) or Production (sk_live_ / pk_live_). The SDK picks the API host from the key prefix. |
| Sandbox / Production secret key | Your sk_test_... or sk_live_... key. Shown masked (sk_live_…AbCd) after saving. Leave blank to keep the saved key. |
| Publishable key | Your pk_test_... or pk_live_... key. Used only by the widget. Must match the environment. |
| Webhook secret | The signing secret from the Merchant Portal. The webhook URL to register is shown next to this field. |
| Test connection | Checks the saved keys of the selected environment against the API. |
| Title / description | One pair for Arabic and one for English. The shopper's locale decides which is shown. |
| Minimum / maximum amount | Hides the method outside this range. |
| Widget on product / cart pages | Shows the instalment summary under the price and under the cart total. |
| Debug log | Adds info/debug lines to WooCommerce → Status → Logs, source qasimha. Errors are always logged. |
The settings screen warns you when the store currency is not SAR.
Register the webhook
Register this URL in the Qasimha Merchant Portal, then paste the secret the portal gives you into Webhook secret:
https://<your-store>/wc-api/qasimha_webhookCopy the exact URL shown next to the Webhook secret field; it reflects your site address. See Webhooks.
The webhook answers:
| Status | Meaning |
|---|---|
200 | Received |
400 | Bad body |
401 | Bad signature, or no webhook secret saved |
503 | Qasimha API unreachable — Qasimha retries |
How a payment flows
- Place order. The plugin creates the checkout session from the WooCommerce order, saves the Qasimha order id on the order (
_qasimha_order_id) and redirects the shopper to the hosted checkout. - Return. The shopper comes back to
/wc-api/qasimha_return. The plugin checks its own token, reads the order from the API, and marks the order paid only when the Qasimha order isConfirmed, the reference matches and the total matches to the halala. Otherwise the order stays pending. - Webhook. Confirms the order the same way if the shopper never comes back.
The order reference sent to Qasimha is the WooCommerce order number, then number-2, number-3 and so on for each new attempt. So a shopper who retries after a decline or expiry is not blocked.
Order status changes
| Event | What happens to the WooCommerce order |
|---|---|
Qasimha order Confirmed (return or webhook) | Marked paid |
| Declined at checkout creation | Marked failed with a private note; shopper sees one neutral line |
| Declined event on an unpaid order | Marked failed |
| Shopper cancels on the hosted checkout | Stays pending; shopper goes back to the cart with a notice |
order.voided event | Cancelled |
| Refund event from Qasimha | Order note added |
| Any other API error at checkout | Private note with the error code and request id; "payment not completed" notice |
Each step writes a private order note with the Qasimha order id, the reference and the API request id.
Widget placement
- Product page:
<qasimha-widget type="summary">under the price, using the displayed price. - Cart page: under the cart total.
- Checkout: the widget is loaded on the checkout page. In Blocks checkout the method shows its title, description and the card snippet, and hides itself outside the amount range.
The widget script is bundled inside the plugin (WordPress.org does not allow remote scripts). Language follows the store locale (Arabic or English). See Plans widget.
Fulfilment, refunds and cancellations
- Fulfilment: when you set the order to Completed, the plugin reports fulfilment to Qasimha with the order total. It runs once per order; if it fails, a note is added and it is tried again the next time the order is completed.
- Refund: use the normal Refund button on the order screen. WooCommerce keeps the refund only when Qasimha accepts it. If Qasimha refuses (for example
AMOUNT_EXCEEDED), the message appears in the refund dialog as Qasimha wrote it. - Cancel: cancelling an unpaid order also cancels the Qasimha order while it is still
AwaitingCheckout.
Test in UAT
- Environment set to Sandbox;
sk_test_andpk_test_keys saved; Test connection passes. - Webhook URL registered for sandbox and the secret saved.
- Widget shows on a product page and the cart page.
- Place an order with Qasimha, complete the hosted checkout: order is marked paid and the note shows the Qasimha order id.
- Place an order and cancel on the hosted checkout: order stays pending, you are back in the cart.
- Set a paid order to Completed: a fulfilment note appears.
- Refund part of a paid order, then try to refund more than is left: the second refund is refused with Qasimha's message.
- Check WooCommerce → Status → Logs (source
qasimha) for errors.
Troubleshooting
Qasimha does not appear at checkout
Check that the store currency is SAR, the order total is inside the minimum/maximum range, and the method is enabled with a key saved for the selected environment.
Webhook deliveries fail with 401
No webhook secret is saved, or it does not match the endpoint registered in the Merchant Portal. Paste the secret again for the environment you are testing.
Order stays pending after a successful checkout
The plugin marks the order paid only when the Qasimha order is Confirmed and both the reference and the total match. Check the private order notes and the qasimha log for the status it read. If the shopper did not return to the store, the webhook confirms the order; check that the webhook is registered.
Payment refused before the shopper is redirected
The SDK checks the request before sending it. The private order note lists the field names that failed (never their values). A negative calculated tax amount means the order cannot be expressed and is refused.
Security
- Secret key: stored encrypted in the WordPress options table (libsodium secretbox, AES-256-GCM fallback) with a key derived from
wp_salt('auth'). Masked on screen and never logged. - Browser: only the publishable key. The secret key and webhook secret never leave the server.
- CSRF: the settings form uses WooCommerce's settings nonce and the
manage_woocommercecapability; Test connection checks its own nonce and the capability. - Return route: a
GETthat only selects an order and asks the API. Nothing changes on the strength of URL parameters. - Webhook route: no nonce by design; protected by the HMAC signature (constant-time compare, 5-minute tolerance, rotated secrets). See Webhook signatures.
- PCI DSS: no card data touches the store; you stay in SAQ-A scope.
Report vulnerabilities privately to the security contact in the Merchant Portal, not in a public issue.
Next steps
Updated 3 days ago
