PFlux DOCS
GitHub Integration enquiries Start integrating
INTEGRATIONS/WOOCOMMERCE

P2Flux for WooCommerce

WooCommerce orders and subscriptions paid in USDC on Base, settling directly to your own wallet. What the plugin does, what it refuses, and what every outcome means.

PLUGINP2Flux for WooCommerce · 1.0.0
SETTLESUSDC on Base
CUSTODYNone — direct to your wallet
SUBSCRIPTIONSNative (simple) or WooCommerce Subscriptions, USD
WOOCOMMERCE → P2FLUX → USDC ON BASE

A WooCommerce order becomes a P2Flux payment. The customer pays from their own wallet, the money lands in yours in the same transaction, and WooCommerce marks the order paid only after the plugin has verified that transaction on chain. For subscriptions, WooCommerce Subscriptions decides when a renewal is due and the plugin collects it; for P2Flux Native Subscriptions the plugin itself owns that schedule. Either way, P2Flux the service schedules nothing.

Overview

The plugin adds one payment method, P2Flux, to WooCommerce → Settings → Payments. It handles one-time orders and recurring products — simple fixed subscriptions through P2Flux Native Subscriptions, and everything WooCommerce Subscriptions offers through its adapter. Both environments are supported: Base Sepolia for testing with faucet money, and Base Mainnet for real USDC.

Non-custodial means exactly what it says. P2Flux never holds your revenue and cannot move it; there is no balance to withdraw and no payout step. The transaction the customer sends pays your wallet directly, with the P2Flux fee split out inside it.

Requirements

REQUIREMENTDETAIL
WordPress6.5 or newer.
WooCommerce8.0 or newer. HPOS (the new order tables) and the block checkout are both supported.
PHP8.1 or newer, 64-bit. The plugin refuses to run its money arithmetic on a 32-bit build and says so in the admin.
sodiumShips with PHP 7.2+ and with WordPress itself. Stored subscription authorizations are encrypted with it.
WooCommerce SubscriptionsOnly for advanced recurring features (trials, sign-up fees, variable subscriptions, switching). Simple fixed subscriptions use P2Flux Native Subscriptions and need nothing else.
A wallet on BaseYour payout address. Payments arrive there directly; you must control it.

Installation

  • Download p2flux-for-woocommerce-1.0.0.zip from the latest release on GitHub.
  • In WordPress, open Plugins → Add New → Upload Plugin, upload that ZIP and activate it. The plugin requires WooCommerce and declares that requirement to WordPress.
  • Open WooCommerce → Settings → Payments and enable P2Flux.
  • Open its settings, enter your payout wallet, choose the environment, and save.
THE RELEASE ZIP

Install the ZIP attached to the release, not GitHub’s “Download ZIP” of the source tree: that archive unpacks under the wrong folder name and carries development-only test fixtures which can shorten billing periods. The plugin is also submitted to the WordPress.org plugin directory and is awaiting review there; until it is published, GitHub is where it comes from.

The method appears at checkout once it is enabled, has a valid payout wallet, and can price the cart — which for a subscription means the cart shape below is one it can honour.

Configuration

SETTINGWHAT IT DOES
Enable P2FluxOffers the method at checkout.
Title / DescriptionWhat customers see. Defaults: “Pay with USDC” and “Pay in USDC from your own wallet on Base. No account needed.”
EnvironmentTest (Base Sepolia, faucet money) or Live (Base Mainnet, real USDC). Orders and subscriptions keep the environment they were created in.
Payout walletYour own address on Base. The plugin refuses a malformed address and the zero address, which would burn the money.
USDC approval for subscriptionsUnlimited (default): one wallet approval at signup, never asked again. Or 12 / 24 / 36 billing periods: the wallet approves that much, and when it runs out the customer’s account page offers Restore USDC approval and the renewal is collected right after. Either way the approval can only be used for the terms the customer signed. Existing subscriptions keep what they were set up with.
Exchange rateOnly for stores not priced in USD. Fetch automatically uses Coinbase’s public rates, cached for an hour; Fixed rate uses the number you enter as store currency per 1 USDC. USD is always 1:1.
Debug logWrites activity to WooCommerce → Status → Logs. Payment references and authorizations are never written to the log.
SETTINGS APPLY TO NEW PAYMENTS ONLY

Changing the environment or the payout wallet affects new payments and new subscriptions. Existing subscriptions keep paying the wallet the customer authorized, on the environment they were created in — including when they are re-authorized. See Changing settings later.

Test mode

With the environment set to Test, the plugin talks to api-test.p2flux.com and opens pay-test.p2flux.com. Payments settle on Base Sepolia in faucet USDC — the same contracts, the same signatures and the same failure modes as production, with nothing at stake. The checkout and the admin both say “Test mode” so nobody mistakes a test order for revenue.

Faucets: Base Sepolia ETH for gas and Circle for USDC (choose Base Sepolia).

One-time checkout

The customer chooses P2Flux at checkout and places the order. A small P2Flux window opens from that same click, and the order’s pay screen loads behind it, showing the amount in USDC (and the conversion, for a non-USD store) and the progress. Where a browser refuses the window, the pay screen offers one button, Pay with your wallet, that opens it on demand.

1The window shows the hosted P2Flux checkout: only the amount, the recipient and the network — never the product, the customer or the order.
2The customer connects a wallet and confirms one transaction. USDC goes from their wallet to yours.
3The checkout window tells the pay screen a transaction was sent. That message is a claim, not a payment.
4Your store asks P2Flux to verify that exact transaction against the chain, for the exact payment this order was given.
5Only that verification marks the WooCommerce order paid. The order note carries the transaction and a block explorer link.

If the window closes early — the customer shut it, the browser crashed — the pay screen does not offer to pay again, because the payment may already be on its way. It offers I already paid — check my payment, which asks P2Flux whether the money arrived. The store also asks on its own, at a few points over the next two days, so a payment whose confirmation was lost still marks its order paid without anyone doing anything.

Native Simple Subscriptions

Simple recurring products can use P2Flux Native Subscriptions without any separate subscription extension: WooCommerce plus this plugin is enough. Tick “P2Flux recurring subscription” on an ordinary simple product, choose daily, weekly, monthly or yearly, and the product’s price is the recurring amount. The plugin creates a renewal order each period, collects it, and shows the subscription under My Account → USDC subscriptions and WooCommerce → P2Flux Subscriptions.

NATIVE V1 SCOPE

Fixed-price, non-taxable virtual products, priced in US dollars, bought one at a time and on their own. Taxes, coupons, shipping, free trials, sign-up fees and variable subscriptions are not supported in native mode. Native mode intentionally supports fewer features than WooCommerce Subscriptions.

FEATUREP2FLUX NATIVEWOOCOMMERCE SUBSCRIPTIONS
Simple fixed subscriptionYesYes
USDC recurringYesVia P2Flux
Free trialNoWCS may support
Sign-up feeNoWCS may support
Variable subscriptionsNoWCS may support
Switching / prorationNoWCS may support
Multiple advanced lifecycle featuresNoYes

Paid through P2Flux only. P2Flux Native Subscription products cannot be paid with other WooCommerce gateways; the checkout offers P2Flux alone for such a cart and refuses anything else server-side. Normal WooCommerce products continue using your existing payment gateways — the P2Flux-only requirement applies only to products using P2Flux Native Subscriptions, not to WooCommerce Subscriptions products.

Activation. The first payment must complete shortly after the customer authorizes it. If the setup expires before payment completes, the subscription is marked expired: it never activated, and it will never charge automatically later. The customer starts a new order. An expired signup keeps its unused wallet authorization on record so the customer can revoke it from My Account.

Renewals and misses. Each renewal is bound to its own billing period. If it cannot be collected, the renewal order is marked failed, the subscription goes on hold, and the customer is emailed what to do. A period that passes unpaid is never collected later — no catch-up billing, no surprise bulk charges after downtime; at most one payment, the current one, is attempted when the store comes back. Missed renewals put the subscription on hold rather than cancelling it; only the customer or the store cancels.

Privacy. The plugin stores no name, address, email, wallet address or IP of its own — those stay in WooCommerce’s records and follow WooCommerce’s personal-data export and erasure. It keeps the financial history of each subscription (amounts, periods, public blockchain identifiers, the encrypted authorization needed for refunds) and registers its own exporter and eraser: erasure unlinks the subscription from the customer and cancels it; the financial rows are retained, as they are on uninstall unless the store opts into destructive removal.

Price changes. An existing subscriber keeps the amount they authorized; a new price applies to new customers only. Disabling the recurring option or trashing the product stops new sales and leaves existing subscriptions running from their stored terms until cancelled.

WooCommerce Subscriptions

With WooCommerce Subscriptions installed, recurring products can be paid with P2Flux. The customer authorizes once, in their wallet, and is never asked again; the store collects each renewal when WooCommerce Subscriptions says it is due.

WOOCOMMERCE SUBSCRIPTIONS OWNS THE SCHEDULE

P2Flux does not schedule charges. WooCommerce Subscriptions decides when a renewal is due, creates the renewal order and asks the plugin to collect it; the plugin asks P2Flux to execute that one charge. The amount, the wallet it pays and the billing period are fixed by what the customer signed — a store cannot change them afterwards.

What the plugin can honour in this version, and what it refuses at the cart rather than sells:

CARTV1
Priced in USDRequired. A recurring authorization fixes one USDC amount for its whole life; a euro-priced subscription would drift away from its own price with the exchange rate, and neither side would have agreed to what it became.
No free trialRequired. The first charge and the renewals are one signed amount with one start date.
No sign-up feeRequired, for the same reason.
Nothing else in the cartRequired. A one-off product alongside the subscription makes the first payment differ from the renewals, and the authorization carries one amount. The customer pays such a cart with another method, or removes the extra item.
One subscription per orderRequired. One authorization covers one subscription.

A cart that breaks one of these does not see P2Flux at checkout — in the block checkout the decision travels with the cart itself, so adding or removing an item updates it at once. That is deliberate: a subscription sold under terms the authorization cannot express is a checkout that succeeds and a renewal that can never collect.

Recurring authorization

At signup the pay screen’s button reads Authorize with your wallet. The hosted checkout asks the customer for two things, once: a standard USDC approval (an on-chain transaction, so it costs a little ETH for gas) and a signature over the exact terms — amount, period, your wallet. The signature is not a transaction and costs nothing.

The result is a standing permission the store holds. It is stored encrypted, on your server, and it can only ever pay the wallet the customer authorized — it is not something that could be used to pay anyone else. It never appears in a page, a URL, an email or a log. Before it is stored, the plugin reads the subscription’s own terms from the chain and checks them against the order, so a permission for somebody else’s cheaper plan cannot be attached to this one.

The first payment is collected immediately after authorization, and the checkout window shows the result. If the store’s page is closed before that finishes, nothing is lost: reopening the same authorization link resumes the same subscription rather than creating a second one.

Renewal outcomes

Every renewal ends in one of these, and the order note says which.

CollectedThe renewal is paid and the note carries the transaction. The ordinary case.
Collected, confirmingThe charge went through and the exact transaction is still being confirmed, or P2Flux reported the period as already collected from an earlier attempt whose reply was lost. The order stays pending until the plugin has recovered the exact transaction — then it is marked paid. Nothing is charged twice, and the customer is not told anything went wrong.
Insufficient USDC balanceThe customer’s wallet is short. The renewal is marked failed, the subscription goes on hold, and the store retries daily for three days. See below.
Insufficient USDC approvalThe customer’s standing approval no longer covers the charge. Retrying cannot fix it; the customer restores the approval from their account page. See below.
Authorization revokedThe customer revoked the permission in their wallet. The subscription is cancelled; they would need to subscribe again.
Authorization expiredPast the signed end date. Cancelled likewise.
Temporary service problemP2Flux or the network could not be reached, or the renewal fired a moment before its billing period opened. Nothing was charged. The store retries quietly on a bounded schedule and tells no one until the retries are exhausted, at which point the renewal is marked failed for a person to look at.

Insufficient USDC balance

The authorization is fine; the wallet just does not hold enough. The renewal order is marked failed, WooCommerce Subscriptions puts the subscription on hold, and the customer is told to top up. The store then retries once a day for three days. On the customer’s account page, under the subscription, a Try the payment again button collects immediately once they have topped up, so nobody waits a day for the next scheduled attempt.

If none of that works, the renewal can also be paid by hand from its pay screen like any one-off order. When it is, the plugin cancels the pending automatic collection for that renewal so it cannot be charged twice.

Restore USDC approval

A wallet grants P2Flux’s recurring contract a standing approval to move USDC. If that approval runs short — the customer lowered it, or a wallet tool reset it — renewals fail with “insufficient approval”. The authorization itself is untouched, so the fix is small: one new approval, not a new subscription.

The customer’s account page shows Restore USDC approval. It opens a hosted P2Flux screen that asks their wallet for exactly one approval and nothing else — no signature, no new subscription — and then the store collects the outstanding renewal straight away. The link the store hands the browser for this can approve and can do nothing else: it cannot charge, cancel or refund.

Re-authorization

A new authorization is needed when the old one can no longer be used: the customer revoked it, it passed its end date, or the subscription’s terms changed — a price change, for instance. The plugin never charges an old authorization for new terms: if WooCommerce’s amount or period no longer matches what the customer signed, the renewal is stopped with a note saying so, and nothing is collected.

For changed terms, the customer’s account page explains the new amount and offers Re-authorize: one signature, and the outstanding renewal is collected at once. The old authorization stays on record, so the payments it made remain refundable. A re-authorization keeps that subscription’s original payout wallet and environment, whatever the store’s current settings say — the customer is authorizing the same arrangement at new terms, not a different one.

A revoked or expired authorization ends the subscription; the customer subscribes again.

Cancellation

There are two layers, and the plugin keeps them distinct.

LAYERWHOEFFECT
Cancel the WooCommerce subscriptionThe customer, or youThe store stops collecting immediately. Every queued retry is dropped, and the plugin will not attempt another charge for this subscription. This is entirely in the store’s hands.
Revoke the wallet authorizationThe customer, onlyRemoves the standing permission from the customer’s wallet on chain, so it cannot be used by anyone. Only the wallet that granted it can send this transaction; a store cannot do it for them.

When a subscription is cancelled, the customer’s account page keeps offering Revoke wallet authorization, with a plain explanation that the permission stays in their wallet until they remove it. The store’s side is already done; this is the customer’s cleanup, and it is theirs to decide.

Suspension and reactivation

WooCommerce Subscriptions puts a subscription on hold for two opposite reasons: itself, moments before collecting a renewal, and a person suspending it. The plugin tells them apart and records why.

  • A subscription you or the customer suspended is never charged, whatever is queued. Reactivating it resumes the normal schedule; nothing is collected on reactivation and no missed period is caught up.
  • A subscription on hold because a renewal failed — insufficient balance, say — may be retried, but only for that renewal and only within the bounded schedule above.

Refunds

A P2Flux refund is a USDC transfer from your own wallet back to the wallet that paid. No server can send money out of your wallet, so WooCommerce’s usual refund button is not offered for P2Flux orders. The order screen has a P2Flux box instead.

1Click Refund in USDC. The plugin reserves this order’s refund and asks P2Flux for the terms, derived from the original payment.
2A hosted P2Flux screen opens and asks your wallet to send the transfer. The recipient and the amount are fixed; there is nothing to type.
3P2Flux confirms the transfer on chain.
4Only then does WooCommerce record the refund on the order.
ONE FULL REFUND

Version 1 refunds a payment in full, once. Partial refunds are not offered: the protocol allows exactly one refund per payment, and a partial one would silently use it up. If the wallet window closed before confirmation, the box offers Re-check refund — never a second transfer.

Payment recovery

Money can move while the confirmation gets lost — a closed window, a timed-out request. The plugin treats every such case the same way: it never assumes, and it never asks the customer to pay again while a payment might exist.

SITUATIONWHAT THE PLUGIN DOES
One-time payment sent, window closedThe pay screen offers I already paid — check my payment, and the store asks P2Flux on its own several times over two days. A found payment marks the order paid with its exact transaction.
Renewal charged, reply lostThe retry answers “already collected” — which proves the period was paid and names no transaction. The order is not marked paid on that alone. The plugin recovers the exact transaction from the chain, checks it against the order, and only then marks it paid. The P2Flux box shows Recover transaction for the rare case that needs a nudge.
Payment arrives for a changed orderA customer who paid an older version of the order (the total changed after they opened the checkout) is not silently credited. The order note says what arrived and the box lets you refund it.

Changing settings later

Both the payout wallet and the environment are written into each order and subscription when it is created, and never rewritten.

YOUEXISTING SUBSCRIPTIONNEW SUBSCRIPTION
Change the payout wallet from A to BKeeps paying wallet A — that is what the customer authorized. So does a re-authorization of it.Pays wallet B.
Switch the environment from Test to LiveStays on Base Sepolia, and keeps talking to the test API that issued its authorization.Created on Base Mainnet.

Supported in v1

FEATUREV1
One-time USDC paymentsYes
WooCommerce SubscriptionsYes
USD recurringYes
Non-USD one-timeYes, for currencies the exchange-rate source provides
Non-USD recurringNo
Free trialsNo
Sign-up feesNo
First payment different from the renewal amountNo
Multiple subscriptions in one orderNo
Full refundYes, once per payment
Partial refundNo
Changing a subscription’s amount or periodNot charged against the old authorization; the customer must authorize the new terms
Customer changes payment methodNo
Suspension and reactivationYes; a suspended subscription is never charged

Troubleshooting

SYMPTOMCAUSE AND FIX
P2Flux is not offered at checkoutIt is disabled, has no valid payout wallet, cannot get an exchange rate for a non-USD store, or the cart carries a subscription it cannot honour (see the cart rules). The admin shows a notice for the first three.
“No valid payout wallet”The address must be 0x plus 40 hex characters, and not the zero address.
Unsupported currencyOne-time payments need a rate the exchange-rate source provides, or a fixed rate you enter. Subscriptions need a USD store.
“Cannot encrypt stored authorizations”PHP was built without sodium. Ask the host; WordPress itself needs it too.
“Needs 64-bit PHP”The server runs a 32-bit PHP build. The plugin will not do money arithmetic on it.
Renewal failed: insufficient balanceThe customer tops up. Daily retries for three days, or Try the payment again on their account page.
Renewal failed: insufficient approvalRestore USDC approval on the customer’s account page. Retrying alone will not help.
Renewal failed: authorization revokedThe customer ended it in their wallet. The subscription is cancelled; they subscribe again if they want to.
Order stuck on “confirming”A payment is on chain and not settled deep enough yet, or the exact transaction is still being recovered. Wait; the plugin keeps checking. Do not ask the customer to pay again.
“Could not be recovered automatically”The exact transaction could not be found within the plugin’s bounded search. Use Recover transaction in the P2Flux box; if it persists, the order note explains what to check.
P2Flux temporarily unavailableNothing was charged. Checkout says so and the customer can try again; renewals retry on their own.

Security model

  • P2Flux never holds your money. Every payment goes from the customer’s wallet to yours in one transaction.
  • A message from the checkout window never marks an order paid. Your store verifies every transaction with P2Flux, server-side, against the exact payment it created.
  • The recurring permission stays on your server, encrypted. It never reaches a page, a URL, an email or a log, and it can only ever pay the wallet the customer authorized.
  • One period pays one order. If WooCommerce ever produces two renewal orders for the same billing period, the second is refused before anything is sent.
  • Nothing is paid without a transaction. An order is marked paid only for a settlement the plugin can name, which is what makes it refundable.

For a stronger key than the one the plugin generates, add P2FLUX_WC_ENCRYPTION_KEY to wp-config.php. The plugin’s own documentation describes the key model and how to rotate it.

Plugin on GitHubReleases, source, tests and the developer documentation.Recurring paymentsThe protocol underneath: authorization, charges, recovery.ErrorsEvery result code and what it means.
Something more than a standard integration?
Marketplace flows, platform billing and custom settlement logic.
Discuss an integration