Odoo integration
Connect Stripe Payments and Subscriptions to Odoo
Three different problems get called "Stripe integration": taking a payment, running a subscription lifecycle, and making the accounting agree afterwards. They fail in different ways, so this page treats them separately.
- Checkout
- Recurring billing
- Webhooks
- Refunds
- Reconciliation
Reviewed by Bhavesh Selarka, COO & Co-Founder, Heliconia Solutions · Odoo 16 Functional Certification · Odoo Partner · Updated
Proof
Clients
Businesses that run on what we built
The short answer
What Does a Stripe and Odoo Integration Cover?
Stripe owns the card, the payment method and the money movement. Odoo owns the customer, the order, the subscription state and the ledger. The integration is a webhook-driven flow in one direction (Stripe tells Odoo what happened) and an API call in the other (Odoo asks Stripe to charge). Everything hard about it is in the third part: making the two agree at the end of the month.
Odoo ships payment provider support, and for a simple online checkout that is often enough. You'll need a real integration when the payment has to drive something else: activate an account, extend an expiry date, release a delivery, post a specific journal entry, or start a dunning sequence.
That is the work we have done twice. WaveContact takes recurring payments on Stripe against membership plans held in Odoo. MEP Emart runs a full subscription lifecycle on Odoo 14 Community where Stripe billing drives database activation, expiry, renewals, reminders and plan upgrades.
The first decision
Which System Owns What
Agree this before writing code. Most Stripe integration bugs are really disagreements about a row in this table.
| Object | System of record | Direction | Conflict rule |
|---|---|---|---|
| Card and payment method | Stripe | Never leaves Stripe | Odoo stores a token reference only, never card data |
| Customer identity | Odoo | Odoo to Stripe on first charge | Odoo partner id is the key, and the Stripe customer carries it in metadata |
| Price and plan definition | Odoo | Odoo to Stripe | A plan changed only in Stripe is a plan that will drift. Change it in Odoo |
| Payment outcome | Stripe | Stripe to Odoo by webhook | The webhook is the truth. A UI redirect is a hint, not a confirmation |
| Subscription state | Odoo | Both, reconciled | Odoo decides what access the state grants, Stripe decides whether money arrived |
| Refunds | Wherever it was issued | Both | Either way it ends as a credit note in Odoo. Never only in Stripe |
| Invoice and ledger entry | Odoo | Odoo only | Stripe invoices are not accounting records for your books |
The row people skip is the fourth. Treating the browser redirect as confirmation, instead of the webhook, is the single most common cause of orders that are paid in Stripe and unpaid in Odoo.
The lifecycle
From Checkout to Reconciled Ledger
Three flows, kept separate on purpose: capture, subscription lifecycle, and accounting.
Step 01
Capture: intent
Odoo creates the order and asks Stripe for a payment intent with the amount, currency and metadata that ties it back to the Odoo record.
- Odoo to Stripe
Step 02
Capture: authorisation
The customer pays. Strong customer authentication happens in Stripe, which is exactly where it should happen and why the browser cannot be trusted with the result.
- Stripe
Step 03
Capture: confirmation
Stripe sends a webhook. Odoo verifies the signature, looks up the record by metadata, marks the payment and moves the order on. Idempotent, so a repeated delivery changes nothing.
- Webhook
Step 04
Subscription: billing cycle
On a schedule, the plan bills. Success advances the period. Failure starts retries, and the Odoo subscription state follows, which is what actually gates access.
- Stripe + Odoo
Step 05
Subscription: change and cancel
Upgrades, interval changes and cancellations decided in Odoo, applied to Stripe, and confirmed back by webhook. MEP Emart lets customers do this themselves.
- Odoo to Stripe
Step 06
Consequence
This is where the value is. Payment received means: activate the database, extend the expiry, release the order, send the confirmation. Payment failed means the opposite, on a defined timetable.
- Custom
Step 07
Accounting
Invoice and payment posted in Odoo, fees recorded, payouts matched against the bank statement. Stripe settles net of fees, so gross and net have to be handled deliberately.
- Accounting
Stripe pays out in batches, net of fees, days after the transactions. If nobody designs for that, the bank reconciliation is manual forever.
Which pattern
Native Provider, Community Module or Custom Integration?
Try them in this order. We will tell you when the built-in option covers your case.
| Your need | Approach | Why |
|---|---|---|
| One-off online payments on an Odoo website or portal | Odoo's built-in Stripe provider | Configuration, not a project. Use it |
| Recurring billing, standard terms, Enterprise | Subscriptions app with the provider | Covered, as long as nothing outside Odoo depends on the payment |
| Recurring billing on Community | Custom | What we built for MEP Emart: the lifecycle, not just the charge |
| Payment must trigger provisioning, access or fulfilment | Custom | The consequence is the integration. That logic is yours |
| Payments from a custom frontend or mobile app | Custom API layer | WaveContact bills through Odoo behind a web frontend and a Flutter app |
| Fee and payout reconciliation into the ledger | Custom, with accounting agreement | Gross, fees and payout timing have to be modelled, not assumed |
Failure handling
What Makes It Survive a Bad Day
- Signature verification on every webhook, rejecting anything unsigned or replayed outside the tolerance window
- Idempotent handlers keyed on the Stripe event id, because at-least-once delivery means duplicates are normal, not exceptional
- A queue with retry and backoff, so a brief Odoo outage doesn't lose a payment confirmation
- A scheduled catch-up that pulls recent Stripe events and fills gaps, because a webhook you never received can't be retried by anyone
- Idempotency keys on outbound charge requests, so a timeout never becomes a double charge
- Daily reconciliation of Stripe payments against Odoo records, reporting differences before finance finds them
- Alerting on failed webhook processing and on queue depth, with a named person who receives it
Security boundary
Credentials, Data and What We Do Not Touch
- 01
Card data never reaches Odoo or our code. Stripe holds the payment method and Odoo holds a token reference, which is what keeps your PCI scope small.
- 02
API keys live in the server environment, never in the database or a module, and restricted keys are used where Stripe supports them.
- 03
Webhook endpoints are signature-verified and rate-limited, and they do exactly one thing: enqueue a verified event.
- 04
Access to the Stripe dashboard stays yours. We ask for the least access that lets us build and debug.
- 05
Audit trail: every inbound event and outbound call logged with its identifier, so a disputed payment can be traced end to end.
- 06
We are not a payment institution and we do not advise on PCI scope or financial licensing. Where your setup raises those questions, they go to your compliance adviser.
How we run it
Implementation Sequence
Assessment
Odoo version and edition, what triggers a payment, what a payment must trigger, currencies, volumes and whether subscriptions are involved.
Ownership and mapping
The matrix above filled in, plus the product and plan mapping between Odoo and Stripe.
Build in test mode
Full flow against Stripe test keys, including the awkward paths: failed card, retry, refund, duplicate webhook, expired subscription.
Reconciliation first
The daily comparison job is built before go-live, not after the first month-end discrepancy.
Controlled go-live
Live keys, a small volume first, webhooks monitored, with a rollback path that does not strand a paid customer.
First cycle support
We stay close through the first full billing cycle and the first payout reconciliation.
Evidence
Stripe and Odoo in Production
Two subscription businesses, one on Community and one behind web and mobile clients.
| Project | Industry | Odoo | Key capabilities | Technology |
|---|---|---|---|---|
| MEP Emart | SaaS: AI solutions & digital transformation | Odoo 14 Community | Stripe · Odoo Website & customer portal · Email (SMTP) | Odoo 14 Community · Python · PostgreSQL |
| WaveContact | SaaS: digital business cards | Odoo | Digital Business Card Management · Contact Management · Profile Management · Subscription Management | Odoo · Python · PostgreSQL · GraphQL · Flutter |
Integration assessment
Request an Integration Assessment
Send us your Odoo version and edition, where payments start, what a successful payment has to trigger, your currencies and volumes, and whether you already use a connector. You get the ownership matrix filled in and an honest answer on whether the built-in provider covers you.
- Data ownership matrix completed for your setup
- Capture, subscription and reconciliation flows mapped separately
- Built-in provider, Subscriptions app or custom, with the reasoning
- Failure-handling plan: webhooks, retries, catch-up and reconciliation
- Accounting treatment of fees and payouts, agreed with your finance team
What clients say
In Their Words
Heliconia transformed our business with Odoo. They implemented a dynamic website with e-commerce capabilities, enhancing our online presence significantly.
Sandesh ThummarBusiness Owner, Ladder Logix
Heliconia provided a unique canteen solution, saving us valuable ordering time. Their innovative approach has been invaluable to our operations.
Pradeep LakhaniBusiness Owner, Avasar Agency
Questions
Stripe and Odoo Questions, Answered Directly
Does Odoo support Stripe out of the box?
Yes, as a payment provider for online payments on the Odoo website and portal, and that covers a straightforward checkout without any development.
You need an integration when the payment has to drive something beyond marking an order paid: provisioning, access, fulfilment or a specific accounting treatment.
Can we run subscriptions on Odoo Community with Stripe?
Yes. MEP Emart runs online recurring plans on Stripe and offline annual plans, with automated activation and expiry, renewals, reminders, plan upgrades and customer self-service, entirely on Odoo 14 Community.
What happens if a webhook never arrives?
A scheduled catch-up job pulls recent events from Stripe and processes anything missing, and the daily reconciliation reports what still doesn't match. Don't rely on webhook delivery alone, or orders end up paid in one system and unpaid in the other.
How do Stripe fees appear in the accounts?
Deliberately, because Stripe pays out net of fees on its own schedule. We agree the treatment with your finance team up front: gross revenue, fee expense and the payout matched against the bank line. Getting it wrong means a bank reconciliation nobody can close.
Can customers pay from our app rather than the Odoo website?
Yes. WaveContact takes subscription payments behind a web frontend and a Flutter mobile app, with Odoo holding the memberships, orders and store. The app talks to your API, and the card still never touches your systems.
Is card data ever stored in Odoo?
No. Stripe holds the payment method and Odoo holds a token reference. That boundary is deliberate: it keeps card data out of your database and your PCI scope small, and anyone proposing otherwise isn't solving your problem, they're creating one.
Next step
Make the Payment Trigger the Right Thing
Tell us what a successful payment has to cause in your business, and what a failed one has to stop. That is the integration. We will scope it and tell you if Odoo already does it.