Woo Pay – Stellar (XLM/USDC)
WooCommerce plugin to accept XLM or USDC on Stellar
by StaveIndustries · github.com/staveindustries/woo-pay · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/staveindustries/woo-pay/archive/refs/heads/main.zipWoo Pay – Accept XLM / USDC on Stellar in WooCommerce
WordPress/WooCommerce plugin that adds “Pay with Stellar” at checkout.
- Settings: wallet address, asset choice (XLM/USDC), testnet/mainnet.
- Unique memo per order (e.g.
WOO-123-AB12CD) for payment matching. - Payment check via Stellar Horizon API marks the order paid when funds arrive.
- Small
assets/checkout.jsfor copy buttons + auto-refresh. - PHPUnit tests for memo generation, address validation, payment matching.
Requirements
- PHP 7.4+
- WordPress 6.0+
- WooCommerce 7.0+ (HPOS compatible)
- A Stellar wallet (testnet for testing, mainnet for live)
Install steps
- Download / clone:
git clone https://github.com/StaveIndustries/woo-pay.git - Upload to WordPress:
- Copy the
woo-payfolder towp-content/plugins/woo-pay/, or - Zip it and upload via WP Admin → Plugins → Add New → Upload Plugin.
- Copy the
- Activate: WP Admin → Plugins → activate “Woo Pay – Stellar”.
- Configure: WooCommerce → Settings → Payments → “Pay with Stellar” → Manage:
Enable= checkedWallet address= your Stellar public key (G…, 56 chars)Asset=XLMorUSDCNetwork=testnetfor testing,publicfor live money- For USDC mainnet the default issuer is Circle:
GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5
- Test on testnet:
- Set Network = testnet, create a test wallet at https://laboratory.stellar.org + fund with Friendbot.
- Place a test order, send the exact amount + memo from another test account.
- Order should move from On-hold → Processing/Completed automatically (cron + thank-you check + manual
check_payment_for_order()).
- Go live: switch Network to
public, double-check wallet + asset.
How payment matching works
process_payment()generatesWOO-{orderId}-{6 random}viaStellar_Utils::generate_memo()and saves it as order meta_stellar_memo.- Customer sends XLM/USDC to your wallet with that memo.
WC_Stellar_Checker::find_matching_payment()polls Horizon:GET https://horizon(-testnet).stellar.org/accounts/{wallet}/payments?limit=50&order=desc- Enriches each payment with its transaction memo.
Stellar_Utils::payment_matches()checks destination + exact memo + amount ≥ total + asset type.
- On match,
mark_order_paid()calls$order->payment_complete($tx_hash).
Manual check endpoint (optional): /wc-api/wc_gateway_stellar?order_id=123 returns {"paid":true/false}.
When a payment is not confirmed
The thank-you page asks that endpoint every 30 seconds and shows the shopper what is wrong and what to do next. Each reason has its own message:
| Reason code | When | Shopper is told to |
|---|---|---|
no_payment_found |
No payment carries this order's memo yet | Send the exact amount with the memo; contact the shop if already paid |
wrong_amount |
Memo matches, amount is too low | Not send a top-up (one payment per order is matched); contact the shop |
memo_mismatch |
A payment has this order's WOO-{id}- prefix but not the exact memo |
Not pay again; contact the shop to match it by hand |
wrong_asset |
Memo matches, wrong asset (e.g. USDC sent for an XLM order) | Contact the shop |
expired |
Nothing found and the order is older than the payment window | Place a new order; contact the shop if already paid |
network_error |
Horizon could not be reached | Wait, the page keeps trying; no need to pay again |
order_not_found |
Order missing or not a Stellar order | Contact the shop with the order number |
- The payment window is 60 minutes. Change it with the
woo_pay_stellar_payment_window_minutesfilter (return0to never expire). A correct payment that arrives late is still credited. - The endpoint adds
reasonandmessageto its JSON only when the order key is passed too (&key=wc_order_...), because the message can contain amounts and memos. Without the key it still returns justpaid. - Messages live in
WC_Stellar_Checker::failure_message();WC_Stellar_Checker::check_payment()returns the reason.
Config (.env.example)
This plugin stores settings in WooCommerce options, but .env.example documents the same values for staging scripts/CI:
STELLAR_WALLET_ADDRESS=G...
STELLAR_ASSET=XLM
STELLAR_NETWORK=testnet
STELLAR_USDC_ISSUER=GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5
Copy to .env for local tooling only — never commit real keys (public keys are safe to share, secret keys are never needed by this plugin).
Running tests
composer install
composer test
# or: vendor/bin/phpunit --testdox
Tests live in tests/StellarUtilsTest.php (memo format/uniqueness, StrKey address validation, XLM/USDC matching) and tests/StellarCheckerTest.php (one test per failure reason and its shopper message).
File layout
woo-pay.php Main plugin file, registers gateway + JS
includes/class-stellar-utils.php Pure-PHP: memo, address check, matching, Horizon URL
includes/class-wc-stellar-settings.php Settings defaults + form_fields
includes/class-wc-gateway-stellar.php WC_Payment_Gateway: checkout, process_payment, thank-you, checker hook
includes/class-wc-stellar-checker.php Horizon API client + mark_order_paid
assets/checkout.js Copy buttons + thank-you payment status messages
tests/StellarUtilsTest.php PHPUnit tests (pure helpers)
tests/StellarCheckerTest.php PHPUnit tests (failure reasons + messages)
phpunit.xml / composer.json / tests/bootstrap.php
.env.example / README.md / CONTRIBUTING.md / LICENSE
Security notes
- Only public keys (
G…) are stored. Never ask customers for secret keys. - Always validate address format (
/^G[A-Z2-7]{55}$/, 56 chars) before saving/using. - Amount check uses
>= expected - epsilonto tolerate stroop rounding; adjust if you need strict FX conversion. - For USDC on mainnet, verify the issuer matches Circle if you harden
payment_matches().
License
MIT — see LICENSE.
One-command local demo (Docker)
PHP cannot run on Vercel, so use Docker to try the plugin locally:
``bash docker compose up -d
open http://localhost:8080, finish the WP installer, install WooCommerce
Plugins -> Add New -> Upload -> zip this repo -> Activate
WooCommerce -> Settings -> Payments -> enable 'Pay with Stellar'
``n The plugin source is mounted live, so code edits apply without rebuilding. Testnet only. See docker-compose.yml for details.