Payment processors
OpenReceive + Stripe
Keep Stripe for cards and add Bitcoin and stablecoins next to it, with card plans and prepaid crypto passes on one design.
Tested in production since September 2026
A subscription software business sells card plans through Stripe and prepaid crypto passes through OpenReceive on this design, side by side. The agent directions below build the same design into your app.
Get agent directions
Add to my Stripe app
This app already takes card payments through Stripe.
Start a new app with both
No payments yet. Build card and crypto checkout together.
On WordPress with WooCommerce? Install the OpenReceive plugin and it appears next to the Stripe gateway at checkout. Automatic subscription renewals stay card-only. OpenReceive for WooCommerce.
Java, Go or .NET? Not supported yet, so get in touch. Selling through Payment Links or a site builder with no server of its own? Start from a platform instead. See platforms.
Keep Stripe for cards. Add Bitcoin over Lightning, plus USDT, USDC, ETH and SOL through a swap provider that converts them to Bitcoin, paid straight into a wallet you control. This page is the design we run in production next to Stripe, and agent directions that build it into your app.
Tested in production
This is not a sketch. Since September 2026 this design has run a subscription software business, with Stripe and OpenReceive side by side on one pricing page:
- Monthly plans and credit packs by card, through Stripe.
- Prepaid passes of 60, 180 and 365 days, and the same credit packs, by crypto through OpenReceive.
- Customers who hold a card plan and a crypto pass at the same time.
Everything on this page comes from running it, including the mistakes we fixed. The agent directions below build the same design into your app.
What changes, and what doesn’t
Stripe stays as it is. Checkout, subscriptions, the customer portal, webhooks, receipts and tax settings keep working exactly as they do today. Your customers who pay by card see no difference.
OpenReceive adds a second way to pay. Next to “Pay with card” your pricing page gets “Pay with crypto”. The invoice comes from your own Lightning wallet through a receive-only connection code, so there is no account to open, no payout to wait for and no one holding your money. A configured swap provider turns stablecoin, ETH and SOL payments into Bitcoin on the way in.
Both end in the same place. A card payment and a crypto payment run the same piece of your code: the one that grants what was bought. Everything after that (access, credits, features) doesn’t care how the customer paid.
Why a crypto subscription works differently
A card subscription works because Stripe keeps the card on file and charges it every month. Nobody can pull money out of a crypto wallet. Each payment is one the customer sends, so there is nothing to bill next month.
So the two payment methods sell time differently:
| Card (Stripe) | Crypto (OpenReceive) | |
|---|---|---|
| Plans | Monthly or yearly, renews automatically | A prepaid pass of 60, 180 or 365 days, never renews |
| Paid | Every period | Once, up front |
| Credits | Each month | The whole pass’s worth, at purchase |
| Credit packs | Same price | Same price |
| Chargebacks | Possible | None |
Pricing a crypto pass
Start from the card price. A pass costs the monthly price times the months it covers, less a discount for paying up front: about 10% for 60 days, 20% for 180 days and 26% for 365 days. Count 365 days as 365/30 months, and round to whole dollars.
| Plan | Card, per month | 60-day pass | 180-day pass | 365-day pass |
|---|---|---|---|---|
| Basic | $19 | $34 | $91 | $171 |
| Plus | $39 | $70 | $187 | $351 |
| Business | $99 | $178 | $475 | $891 |
The discount is fair, not a giveaway. You get the money up front, with no card fees, no failed renewals and no chargebacks.
- Show 60 days first. It is the easiest yes.
- Credits arrive all at once. A pass includes the plan’s monthly credits times days ÷ 30, granted when it is paid, and they expire when the pass ends.
- Passes stack. Buying a pass while one is running adds its days to the end of the current one. Let customers renew early. Stacking only works if the buy button stays enabled.
- Say it clearly. Put “One-time pass, no auto-renew” next to every crypto price.
- Remind people. Email 7 days before a pass ends and on the day it ends. A pass that lapses quietly is a customer you lose without them deciding to leave.
Credit packs
If you sell usage, credit packs cost the same in dollars by card or by crypto, and they never expire. When a customer has both, spend the plan’s or pass’s credits first, since those expire, and pack credits last.
When a customer has both
These rules come straight from production, where getting them wrong cost us a customer’s paid time.
- A live card plan blocks crypto passes. While a card subscription is live, even one set to cancel at the period end, the crypto pass buttons are disabled and the server refuses them: “You have a card plan. Crypto passes become available once it ends. Crypto credit packs are available any time.”
- A pass first, then a card plan: both run. The pass keeps its days. The customer gets the features of the better plan, and the credits add up.
- A pass paid late still counts. A customer can prepare a crypto checkout, start a card plan, and pay the crypto invoice afterwards. That pass runs as a normal pass on its own record.
- Never write a pass onto a card subscription’s record. If a crypto pass updates the same row that Stripe keeps alive, Stripe keeps charging while the app thinks the customer is on a pass. Keep card and crypto access separate, and let only the Stripe sync touch a row that holds a Stripe subscription.
The design
This is what the agent directions build. It fits any framework OpenReceive supports.
Stripe webhook ─────────┐
├──▶ settle(order) ──▶ grant plan time, credits or the product
OpenReceive on_paid ────┘
- One order table for both. Every purchase is an order row. It records which payment method it used, what kind of purchase it is (a card plan period, a crypto pass, a credit pack or a product), and the price in dollars. Revenue reports read dollars for both, never satoshis.
- One settle function. The Stripe webhook and OpenReceive’s
on_paidhook both call it. It locks the order, does nothing if the order is already paid, and grants what the order bought. Every grant has a unique key, so a replayed event can never grant twice. - Separate access records. A card plan’s access lives on its Stripe subscription record, which only the Stripe sync updates. A crypto pass lives on its own record, with a paid-until date. One helper reads both and decides what the customer can do.
- The crypto order comes first. When the customer clicks “Pay with
crypto”, the app creates the order with its dollar price and an opaque,
never-reused reference. OpenReceive’s
amount_forreturns that saved price, andauthorizechecks that the order belongs to the signed-in customer. OpenReceive converts dollars to Bitcoin at checkout and refuses when the exchange rate is stale. - Stripe is store-then-process. Verify the signature, save the event, and answer 200. Then process it, re-reading the subscription from Stripe, because events arrive out of order. Nothing is granted on the success redirect.
- Crypto needs no webhook. The checkout polls, every OpenReceive request
checks for payments first, and an optional worker makes it instant when no
browser is open.
on_paidruns inside OpenReceive’s database transaction, so emails and live updates go out after it commits. - The checkout link is the refund link. If a stablecoin deposit arrives short or late, the swap provider refunds it, and the customer claims it on the same checkout page. Keep that page reachable from the order.
Get the agent directions
Pick your situation and your framework at the top of this page, and copy the directions into Claude Code, Codex, Cursor or another coding agent. There are two sets:
- Add to my Stripe app. The agent finds the code your Stripe webhook runs when a payment succeeds and reuses it for crypto. It adds the crypto order, passes and buttons, and leaves Stripe alone. Your existing tests have to keep passing.
- Start a new app with both. The agent builds the whole design: card plans and credit packs through Stripe Checkout, crypto passes and packs through OpenReceive, one settle function and one access helper.
Either way, the agent first asks for two codes from your wallet and swap provider, one at a time. Then it asks one question about your crypto prices, where the defaults above are a fine answer.
A coding agent reading this page can fetch the directions itself:
https://openreceive.org/agent-directions/stripe/add/<stack>/full.md to add
to an app that already uses Stripe, or …/stripe/new/<stack>/full.md for a
new app. <stack> is node (Express), fastify, next, rails, django,
fastapi, laravel or php.
What the agent won’t touch
- Your Stripe prices, products, webhook endpoint or API version
- How existing card customers are billed
- Your Stripe secret key, except in a new app where it sets one up
- Your existing tests, which must still pass
Questions
Can I refund a crypto payment? Not automatically. The connection code can receive but never send, which is what keeps your wallet safe. Refund from your wallet by hand if you need to. Stablecoin deposits that arrive short or late are refunded to the payer by the swap provider. The customer claims the refund on the checkout page.
Receipts? Stripe emails card receipts. For crypto orders, show the order on
the customer’s account page or send your own email after on_paid commits.
Where does the money go? To the Lightning wallet you connected. Stablecoin, ETH and SOL payments arrive there as Bitcoin, converted by the swap provider. Which coins and networks are available depends on the provider.
Which frameworks? Express, Fastify, Next.js, Rails, Django, FastAPI, Laravel and plain PHP. On WordPress with WooCommerce, install the OpenReceive plugin, and it appears next to the Stripe gateway at checkout. Java, Go and .NET servers aren’t supported yet. If you sell through Stripe Payment Links or a site builder with no server of your own, start from a platform instead.