Shopify <───> Odoo ERP Integration
| 1. Product & Variant Sync | 2. Real-Time Inventory | 3. Automated Order Routing | 4. Financial & Tax Reconciliation |
|---|
- Product & Variant Catalog Mapping: Standardize SKUs, barcodes, variants (size, color, weight), and price lists across both systems.
- Real-Time Multi-Warehouse Inventory Sync: Prevent overselling by automatically updating available-to-promise (ATP) inventory levels in Shopify whenever stock changes in Odoo.
- Automated Order & Fulfillment Lifecycle: Instantly push Shopify orders into Odoo as Sales Orders (
sale.order), generate picking lists, and feed tracking numbers back to Shopify upon shipment. - Financial & Tax Reconciliation: Map Shopify Payments, PayPal, Stripe, taxes, and discounts directly into Odoo Accounting (
account.move) for accurate bookkeeping.
Selecting the Right Integration Approach
When connecting Shopify with Odoo, choosing the right architectural approach depends on your transaction volume, customization needs, and IT infrastructure.
| Feature / Criteria | Native / Third-Party Connectors | Custom Middleware / REST API | Webhooks + Event-Driven Bus |
|---|---|---|---|
| Best For | Standard stores, single warehouse | Custom business logic, multi-company | High-volume enterprise stores |
| Setup Complexity | Low to Moderate | High | High |
| Flexibility & Scaling | Limited to pre-built features | Fully customizable | Scalable & decoupled |
| Real-time Performance | Scheduled polling intervals | Near real-time | Instantaneous (Sub-second) |
| Maintenance Cost | Low subscription fee | Medium development overhead | Infrastructure management |
Technical Architecture: Data Flow & Synchronization
Understanding how data flows bi-directionally between Shopify Admin API and Odoo ORM is key to designing a reliable pipeline.
┌────────────────────────┐ ┌────────────────────────┐
│ SHOPIFY STORE │ │ ODOO ERP │
│ │ Webhooks (HTTP) │ │
│ • New Order Created │ ────────────────> │ • Create Draft Order │
│ • Customer Registered │ │ • Reserve Stock │
│ │ │ │
│ │ REST / GraphQL │ │
│ • Update Tracking │ <──────────────── │ • Delivery Validated │
│ • Inventory Adjust │ <──────────────── │ • Stock Level Updated │
└────────────────────────┘ └────────────────────────┘
1. Product & Catalog Synchronization
Maintain Odoo as the Primary Master Data Source for product information.
- Product Template & Variants: Odoo
product.templatemaps to Shopify Product, andproduct.productmaps to Shopify Variants. - SKU Matching: Always enforce SKU uniqueness. Non-matching SKUs lead to duplicate products or failed order processing.
- Price Lists: Map Odoo Pricelists (
product.pricelist) to Shopify base currency and multi-currency localized storefronts.
2. Order Processing & Fulfillment Pipeline
- Order Capture: Shopify fires an
orders/createWebhook to the integration endpoint. - Customer Matching: The system queries Odoo (
res.partner) by email or phone. If found, link to existing partner; otherwise, create a new record. - Order Creation: Draft Sales Order (
sale.order) created with matching lines and tax settings. - Payment Confirmation: Paid orders automatically trigger order confirmation (
action_confirm()) in Odoo, generating a Stock Picking (stock.picking). - Fulfillment Sync: Once the warehouse team validates delivery in Odoo, a
fulfillments/createpayload pushes carrier names and tracking numbers back to Shopify.
Implementation Code Example: Webhook Handler for Shopify Orders
Below is a robust example of an Odoo HTTP controller handling incoming Shopify orders/create webhooks:
import json
import hmac
import hashlib
import base64
from odoo import http, SUPERUSER_ID
from odoo.http import request
class ShopifyWebhookController(http.Controller):
SHOPIFY_SECRET = 'your_shopify_api_shared_secret'
def _verify_webhook(self, data, hmac_header):
digest = hmac.new(
self.SHOPIFY_SECRET.encode('utf-8'),
data,
hashlib.sha256
).digest()
computed_hmac = base64.b64encode(digest).decode('utf-8')
return hmac.compare_digest(computed_hmac, hmac_header)
@http.route('/api/v1/shopify/orders/create', type='json', auth='public', methods=['POST'], csrf=False)
def shopify_order_created(self, **kwargs):
req_data = request.httprequest.get_data()
hmac_header = request.httprequest.headers.get('X-Shopify-Hmac-SHA256')
if not hmac_header or not self._verify_webhook(req_data, hmac_header):
return {'status': 'error', 'message': 'Invalid signature'}, 401
order_data = json.loads(req_data.decode('utf-8'))
# Process order using Odoo Environment in admin context
env = request.env(user=SUPERUSER_ID)
# 1. Partner Lookup or Creation
email = order_data.get('email')
partner = env['res.partner'].search([('email', '=', email)], limit=1)
if not partner:
partner = env['res.partner'].create({
'name': f"{order_data['customer'].get('first_name', '')} {order_data['customer'].get('last_name', '')}",
'email': email,
'phone': order_data.get('phone'),
})
# 2. Build Sales Order Lines
order_lines = []
for line in order_data.get('line_items', []):
product = env['product.product'].search([('default_code', '=', line.get('sku'))], limit=1)
if product:
order_lines.append((0, 0, {
'product_id': product.id,
'product_uom_qty': line.get('quantity'),
'price_unit': float(line.get('price')),
'name': line.get('name'),
}))
# 3. Create Sales Order
sale_order = env['sale.order'].create({
'partner_id': partner.id,
'client_order_ref': f"Shopify #{order_data.get('order_number')}",
'order_line': order_lines,
})
return {'status': 'success', 'odoo_order_id': sale_order.id}
Best Practices for High-Volume E-commerce Sync
-
Implement Asynchronous Queueing (Celery / Odoo Job Queue): Never execute direct database updates synchronously inside HTTP webhooks. Enqueue jobs to prevent timeout failures during flash sales.
-
Handle Multi-Location Stock Allocation: Map Shopify Locations to specific Odoo Stock Locations (stock.location). Ensure stock computations read only available, unreserved stock (free_qty).
-
Automate Inventory Delta Updates: Avoid syncing your entire catalog stock every hour. Use database delta triggers or Odoo stock movement signals (stock.quant) to update changed SKUs only.
-
Robust Error Handling & Logging: Build an integration dashboard in Odoo to log failed webhooks, missing SKUs, or tax mismatch errors with retry buttons.
Building a resilient Shopify-Odoo integration requires real knowledge of both Shopify's GraphQL API and Odoo's ORM — it's not a weekend webhook project once you factor in multi-location stock and error recovery. If you need a custom connector built or want a second opinion on your integration architecture, get in touch.
By Shahid Malik