WooCommerce
The Xaalis for WooCommerce plugin (in integrations/woocommerce/xaalis-for-woocommerce) adds a
“Wave / Orange Money (Xaalis)” payment method. The customer is redirected to the Xaalis hosted checkout, pays with
Wave or Orange Money, and the order is marked paid when Xaalis confirms it.
Requirements: WordPress 6.4+, WooCommerce 8.2+ (tested with 11.1), PHP 8.1+, store currency CFA franc (XOF). Works with the classic checkout and the Cart/Checkout blocks, and with HPOS (High-Performance Order Storage).
Install and configure
Section titled “Install and configure”- Zip the
xaalis-for-woocommercefolder, upload it in Plugins → Add New → Upload, activate it. - WooCommerce → Settings → General: currency CFA franc (XOF), number of decimals 0.
- WooCommerce → Settings → Payments → Wave / Orange Money (Xaalis):
| Setting | Value |
|---|---|
| Test mode | on until you have tested the whole flow |
| Test secret key | sk_test_… |
| Live secret key | sk_live_… |
| Webhook secret | whsec_… (given once when your account is created) |
| API base URL | https://api.xaalis.sn (leave the default) |
- Copy the webhook URL shown at the top of that page —
https://your-store/wp-json/xaalis/v1/webhook— and set it as your account’swebhook_url(PATCH /v1/account, must behttps://; see Webhooks).
Saved secrets are never shown again: the fields stay empty with a masked hint (sk_test_••••ab12). Leave a field
empty to keep its value. Live mode is refused without a sk_live_ key and an https:// API URL, and test mode
never uses a live key.
The payment method is hidden at checkout when the currency isn’t XOF or when the current mode has no valid key; an admin notice says why.
What happens at checkout
Section titled “What happens at checkout”sequenceDiagram
participant C as Customer
participant W as WooCommerce
participant X as Xaalis
C->>W: Place order (Wave / Orange Money)
W->>X: POST /v1/payments (Idempotency-Key wc:mode:order:amount)
X-->>W: payment + checkout_url
W-->>C: redirect to checkout_url (order "Pending payment")
C->>X: pays with Wave / Orange Money
X->>W: signed payment.succeeded webhook
W->>W: verify, check order/amount/mode, payment_complete() once
X-->>C: back to the order-received page
- The payment is created with the order total as an integer XOF amount,
client_reference= order number,metadata={order_id, order_key},success_url= the order-received page. - A total with decimals (e.g.
15000.50) is refused with an error, never rounded. Totals must be between 100 and 100 000 000 XOF. - Retrying the checkout returns the same Xaalis payment (same Idempotency-Key). If the cart total changes, a new payment is created. If the customer retries after a failed or expired payment, a new one is created too.
When is an order paid?
Section titled “When is an order paid?”Only when Xaalis confirms it — never because the customer reached the “thank you” page (Never trust the redirect):
- the signed
payment.succeededwebhook, or - when the customer lands on the order-received page, the plugin asks
GET /v1/payments/{id}server-side.
Either way the same checks run before anything changes: the payment is the one created for this order (id,
order_id and order_key in metadata), livemode matches the store’s mode, the currency is XOF and the amount
equals the order total. Until then the page says “Payment awaiting confirmation”.
| Event | Order |
|---|---|
payment.succeeded |
Processing (stock reduced, emails sent) — exactly once, even if the webhook is replayed or races the return page |
payment.failed |
Failed (the customer can retry from their account; a new payment is created) |
payment.expired |
Cancelled (if still pending) |
| succeeded, but the order total changed since | On hold with a note: review, then refund or adjust |
| a second payment succeeds on a paid order | note “refund one payment” |
The webhook answers 400 to a bad, missing or expired signature, 503 while no webhook secret is configured (so
Xaalis retries), and 200 otherwise. Every order shows its Xaalis payment id on the order screen; the transaction id
is the payment id once paid. Logs: WooCommerce → Status → Logs, source xaalis (ids and codes only, never
keys).
Test mode
Section titled “Test mode”With a sk_test_ key no real money moves. Place an order, then approve it on the hosted checkout, or from your
server with POST /v1/payments/{id}/simulate {"outcome":"succeeded"} (see Test mode). The
order should move to Processing within seconds.
Developing the plugin
Section titled “Developing the plugin”integrations/woocommerce/dev has a disposable WordPress + WooCommerce (Docker, http://localhost:8480) wired to a
local Xaalis API and a fresh test merchant:
integrations/woocommerce/tests/docker-test.sh # php -l + unit testsintegrations/woocommerce/dev/setup.sh # WordPress, WooCommerce, XOF store, 15 000 FCFA product, plugin configuredintegrations/woocommerce/dev/e2e.sh # payment, webhooks, replays, forged signatures, failure, expiry, blocksdocker compose -p xaalis-woo -f integrations/woocommerce/dev/docker-compose.yml down -vDetails: integrations/woocommerce/xaalis-for-woocommerce/README.md. Building your own PHP integration instead?
Use the PHP SDK.