هذه المقالة متاحة حاليًا باللغة الإنجليزية فقط. الترجمة قريبا.
By the end of this recipe, customers can pay Odoo invoices and e-commerce checkout carts through Stripe with full Strong Customer Authentication (3DS2) support, refunds posted automatically as credit notes, and recurring subscriptions billed monthly without manual intervention. Skill required: Odoo administrator with Stripe Dashboard access. Time required: 2 hours setup, 90 minutes testing. ECOSIRE has connected Stripe to Odoo for 100+ clients including ECOSIRE.COM itself, and the recipe below is the deduplicated runbook.
The mistake most teams make: they configure Stripe with publishable + secret keys and call it done. They forget the webhook, so cancelled subscriptions never close in Odoo, refunded charges leave invoices marked "paid", and disputed transactions never trigger a workflow. Stripe is event-driven and Odoo without webhooks is half-blind to those events.
What you will need
- Odoo version: 17, 18, or 19. The native
payment_stripemodule ships with all three. - Stripe account: live mode active (or test mode for development). Activated business: name, address, bank, EIN/VAT.
- Modules:
payment_stripe(auto-loaded),account_payment(for invoice-pay flow),website_saleif you run e-commerce. - HTTPS: Stripe refuses to send webhooks to non-HTTPS endpoints. Make sure your Odoo is on a real cert (Let's Encrypt or AWS ACM).
- Time: 2 hours setup, 90 minutes testing including a real $1 charge and refund.
Step-by-step
1. Create a Stripe restricted API key (recommended over the secret key)
In Stripe Dashboard > Developers > API keys, click "Create restricted key". Grant write access to:
- Charges (write)
- Payment Intents (write)
- Refunds (write)
- Customers (write)
- Subscriptions (write)
- Webhook Endpoints (read)
Save and copy the rk_live_XXXX (live mode) or rk_test_XXXX (test mode) value. Verification: a quick curl -u rk_live_XXX: https://api.stripe.com/v1/charges?limit=1 returns the most recent charge JSON.
2. Configure the Stripe payment provider in Odoo
Go to Accounting > Configuration > Payment Providers > Stripe. Set:
- State: Test or Enabled
- Publishable Key:
pk_live_XXXXfrom Stripe (Developers > API keys) - Secret Key: paste the restricted key from step 1 (
rk_live_XXXX) - Allow Saving Payment Method: yes (enables tokenized cards for repeat customers)
- Enable 3D Secure: yes (regulatory requirement in EU)
Click Save. Click "Configure Webhook" — Odoo will tell you the webhook URL: https://your-odoo.com/payment/stripe/webhook. Copy this for step 3.
Verification: state shows "Enabled" and the test payment button on the public Odoo /shop page renders the Stripe Elements card form.
3. Create the Stripe webhook endpoint
In Stripe Dashboard > Developers > Webhooks > Add endpoint. URL = the one Odoo gave you. Subscribe to these events:
charge.refundedcharge.dispute.createdcharge.dispute.closedpayment_intent.succeededpayment_intent.payment_failedpayment_intent.processingcustomer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deletedinvoice.paidinvoice.payment_failed
Save. Stripe shows the Webhook signing secret (starts with whsec_). Paste this into Odoo's payment provider record > "Webhook Secret" field.
Verification: in Stripe Dashboard, click the webhook endpoint > "Send test webhook" and pick payment_intent.succeeded. Watch the Odoo log: a 200 response means the signature verified correctly.
4. Map Stripe events to Odoo flows
The default payment_stripe module handles payment_intent.succeeded (mark transaction confirmed) and charge.refunded (mark refunded). For the rest, extend the controller:
from odoo import http, models
from odoo.http import request
import stripe
import logging
_logger = logging.getLogger(__name__)
class PaymentStripeController(http.Controller):
@http.route('/payment/stripe/webhook/extended', auth='public', csrf=False, methods=['POST'])
def stripe_webhook_extended(self, **kwargs):
provider = request.env['payment.provider'].sudo().search([('code', '=', 'stripe')], limit=1)
signature = request.httprequest.headers.get('Stripe-Signature')
try:
event = stripe.Webhook.construct_event(
request.httprequest.get_data(),
signature,
provider.stripe_webhook_secret,
)
except Exception as e:
_logger.warning('Stripe webhook signature failed: %s', e)
return request.make_response('Bad signature', status=401)
if event['type'] == 'charge.dispute.created':
charge_id = event['data']['object']['charge']
tx = request.env['payment.transaction'].sudo().search([
('provider_reference', '=', charge_id),
], limit=1)
if tx:
tx.message_post(body=f"Dispute opened: {event['data']['object']['reason']}")
# Optional: create a follow-up activity for the finance team
tx.activity_schedule(
'mail.mail_activity_data_todo',
summary='Stripe dispute requires response',
note=event['data']['object']['evidence_details']['due_by'],
)
elif event['type'] == 'customer.subscription.deleted':
sub_id = event['data']['object']['id']
sub = request.env['sale.subscription'].sudo().search([
('stripe_subscription_id', '=', sub_id),
], limit=1)
if sub:
sub.set_close() # standard Odoo subscription close action
return request.make_response('OK', status=200)
Verification: in Stripe test mode, create a test subscription, cancel it, and watch the Odoo subscription close automatically.
5. Configure the customer-facing flow
On any customer invoice, the payment URL is /my/invoices/<id>?access_token=XXX. Click it from the customer email — they see a Stripe Elements card form. Test with the official Stripe test cards:
4242 4242 4242 4242— succeeds4000 0000 0000 9995— succeeds without 3DS4000 0027 6000 3184— requires 3DS authentication4000 0000 0000 0002— declined
Verification: a successful test charge marks the invoice as paid in Odoo within 10 seconds (the time it takes for the webhook to deliver).
6. Set up recurring billing (subscriptions)
For SaaS-style recurring invoicing, use the Subscriptions app. Configure a Stripe price (in Stripe Dashboard > Products > Prices > Create) for each Odoo subscription template. Map them in Odoo via a custom field on sale.subscription.template:
from odoo import models, fields
class SubscriptionTemplate(models.Model):
_inherit = 'sale.subscription.template'
stripe_price_id = fields.Char(
string="Stripe Price ID",
help="The Stripe Price ID, e.g., price_1NXXXXX",
)
When a customer subscribes, the connector creates a customer.subscription in Stripe with the mapped price. Stripe then handles the monthly billing — and posts invoice.paid webhooks back to Odoo, which auto-creates and pays the corresponding Odoo invoice.
Verification: subscribe a test customer to a $9.99/month plan. Wait 28 days (or use Stripe's "Advance time" feature in test mode). Confirm a new invoice is created and paid in Odoo.
7. Configure refunds
On any paid invoice, click "Refund" in Odoo. Choose full or partial. The connector calls stripe.Refund.create() with the original charge ID. Stripe processes the refund (5 to 10 business days for the customer to see it on their statement) and fires charge.refunded, which the webhook converts into an Odoo credit note.
Verification: process a $1 refund on a test charge. Within seconds, a credit note appears in Odoo with the refunded amount.
8. Configure SCA (3D Secure 2)
EU regulation requires 3DS2 on most card payments. Stripe handles this transparently when you use Payment Intents (which the connector does by default). The customer is redirected to their bank's authentication page, then back to your site. No code changes needed — just ensure "Enable 3D Secure" is on in the provider config.
Verification: use the 3DS test card 4000 0027 6000 3184 and confirm the bank challenge page appears, you can authenticate, and the payment succeeds.
Common mistakes
- Forgetting to set the webhook secret in Odoo. Webhooks arrive but signature verification fails silently, transactions never confirm.
- Using the secret key (
sk_live_) instead of a restricted key (rk_live_). Works the same but if leaked, an attacker has full account access. Always use restricted keys. - Testing with a real card in test mode. Stripe rejects real cards in test mode. Use the test card numbers above.
- Not handling
payment_intent.processingwebhook. ACH and SEPA Direct Debit go throughprocessingfor hours/days beforesucceeded. If you don't handle it, the order looks failed. - Hardcoding the Stripe API version. Stripe periodically deprecates versions. Pin the version in your Stripe dashboard so unrelated updates don't break the integration.
Going further
Card-on-file for repeat purchases: tick "Allow Saving Payment Method" so customers' cards get tokenized. Future purchases skip the card-entry step entirely.
Stripe Connect: if you run a marketplace (multiple sellers, single checkout), use Stripe Connect to split payouts. Each seller becomes a connected account in Stripe, and Odoo creates transfer records to route the seller's share.
Apple Pay / Google Pay / Link: enable in the Stripe Dashboard. The Odoo Stripe Elements form auto-shows the wallet buttons on supported devices.
Stripe Tax: Stripe automatically calculates sales tax for US states, EU VAT, UK VAT, etc. Odoo's tax engine can defer to Stripe's calculation by storing the Stripe-computed tax as the invoice tax line.
For complex Stripe setups including connected accounts, multi-currency settlement, and PCI-DSS compliance audits, ECOSIRE custom Odoo development builds bespoke pipelines. Pair this with how to integrate Shopify with Odoo if you have multiple sales channels.
Frequently Asked Questions
What does Stripe charge?
Standard pricing as of 2026 is 2.9 percent + 30 cents per US transaction (1.5 percent + 30 cents for ACH). EU/UK consumer cards are 1.5 percent + 25p, business cards 2.5 percent + 25p. Volume discounts available above $1M/year processing.
Can Stripe handle multi-currency?
Yes. Stripe accepts payments in 135+ currencies and settles to your bank in any of 50+ payout currencies. Odoo records the transaction in the customer's currency and the invoice's currency separately, so multi-currency flows record correctly.
How do I migrate from another gateway (Authorize.Net, PayPal) to Stripe?
The cards-on-file are NOT portable across gateways without a migration agreement. Contact Stripe Support and your old gateway to coordinate; the migration is technical but Stripe's team has done it hundreds of times.
What about chargebacks?
Stripe forwards chargebacks via the charge.dispute.created webhook. The connector creates an activity on the original transaction so the finance team can respond with evidence within Stripe's 7-day window. Set up a Slack alert on this event for high-volume merchants.
For full Stripe + Odoo billing implementation including dunning, churn analytics, and revenue recognition, ECOSIRE accounting services build the entire stack. Or read how to integrate QuickBooks with Odoo if you also need to sync with QuickBooks.
بقلم
ECOSIRE TeamTechnical Writing
The ECOSIRE technical writing team covers Odoo ERP, Shopify eCommerce, AI agents, Power BI analytics, GoHighLevel automation, and enterprise software best practices. Our guides help businesses make informed technology decisions.
ECOSIRE
قم بتحويل أعمالك باستخدام Odoo ERP
تنفيذ وتخصيص ودعم خبير Odoo لتبسيط عملياتك.
مقالات ذات صلة
كيفية إضافة زر مخصص إلى عرض نموذج Odoo (2026)
إضافة أزرار إجراءات مخصصة إلى طرق عرض نموذج Odoo 19: طريقة إجراء Python، وعرض الميراث، والرؤية المشروطة، ومربعات حوار التأكيد. تم اختبار الإنتاج.
كيفية إضافة حقل مخصص في Odoo بدون الاستوديو (2026)
قم بإضافة حقول مخصصة عبر وحدة مخصصة في Odoo 19: وراثة النموذج، وامتداد العرض، والحقول المحسوبة، وقرارات المتجر/غير المتجر. الكود أولاً، يتم التحكم في الإصدار.
كيفية إضافة تقرير مخصص في أودو باستخدام التخطيط الخارجي
أنشئ تقرير PDF يحمل علامة تجارية في Odoo 19 باستخدام web.external_layout: قالب QWeb، تنسيق الورق، ربط الإجراء. مع طباعة الشعار + تجاوزات التذييل.