Skip to main content

Shopify to Odoo Order Import: Complete Automation Guide

Step-by-step guide to automating Shopify order import into Odoo — customer sync, payment status, fulfillment writeback, error handling, and partial orders.

E
ECOSIRE Research and Development Team
|March 23, 202618 min read3.5k Words|

Every Shopify order that requires manual re-entry into Odoo is a liability — a chance for data entry errors, a delay in fulfillment processing, and a drain on staff time that compounds with every additional order.

For a store processing 200 orders per day, manual order import consumes roughly 3–4 hours of staff time daily and introduces an error rate of 2–5% that cascades through inventory, shipping, and accounting.

Automating the Shopify-to-Odoo order pipeline eliminates this bottleneck entirely. Orders arrive in Odoo within seconds of placement, customer records merge automatically, payment statuses sync in real-time, fulfillment updates write back to Shopify with tracking numbers, and error conditions are caught and queued for resolution rather than silently dropped.

This guide covers the complete order import automation — from the Shopify webhook that starts the process through the fulfillment writeback that closes the loop. Every step includes the specific data mappings, edge cases, and failure modes you need to handle for a production-grade implementation.

Key Takeaways

  • Shopify webhooks provide real-time order events — orders/create, orders/updated, orders/cancelled — that trigger the import pipeline
  • Customer sync uses email as the primary match key, with automated creation for new customers and field merging for existing ones
  • Payment status mapping translates Shopify's payment states (authorized, paid, partially_paid, refunded) into Odoo payment records
  • Product matching connects Shopify line items to Odoo products using SKU as the primary identifier — variant-level matching is essential
  • Fulfillment writeback sends Odoo delivery confirmation back to Shopify with tracking numbers, carrier information, and per-line-item fulfillment data
  • Partial fulfillments (split shipments from multiple warehouses) require line-item-level fulfillment tracking, not order-level
  • Error handling must include retry queues, dead letter processing, and alerting — silent failures are the most dangerous failures
  • Idempotency keys (Shopify order ID) prevent duplicate orders from webhook retries

Architecture: The Order Import Pipeline

The complete order import pipeline has six stages, each with specific data transformations and failure modes:

Stage 1: Webhook Reception
  Shopify → orders/create webhook → Integration endpoint

Stage 2: Customer Resolution
  Find or create Odoo customer from Shopify customer data

Stage 3: Product Matching
  Map Shopify line items to Odoo products by SKU/variant

Stage 4: Order Creation
  Create Odoo sale order with lines, taxes, shipping, discounts

Stage 5: Payment Recording
  Record payment status based on Shopify financial_status

Stage 6: Fulfillment Writeback
  Odoo delivery → Shopify fulfillment with tracking

Each stage is a distinct operation that can fail independently. A robust implementation processes these as a pipeline with checkpointing — if Stage 4 fails, stages 1–3 are not re-executed on retry.


Stage 1: Receiving Shopify Order Webhooks

Shopify webhooks are the foundation of real-time order import. When an order event occurs, Shopify sends an HTTP POST request to your registered endpoint with the complete order payload.

Required Webhook Subscriptions

Webhook TopicPurposeWhen It Fires
orders/createNew order placedCustomer completes checkout
orders/updatedOrder modifiedPayment captured, fulfillment added, edits made
orders/cancelledOrder cancelledMerchant or customer cancels
refunds/createRefund issuedFull or partial refund processed

Webhook Verification

Every incoming webhook must be verified using Shopify's HMAC-SHA256 signature. The webhook payload is signed with your app's shared secret — verify the signature before processing. Unverified webhooks should be rejected with a 401 response.

Handling Webhook Delivery Guarantees

Shopify guarantees at-least-once delivery, meaning the same webhook may be sent multiple times — after network timeouts, during Shopify's retry cycle, or during incident recovery. Your endpoint must be idempotent: receiving the same orders/create webhook twice must not create two Odoo orders.

Implementation pattern: Use Shopify's order ID as an idempotency key. Before creating an Odoo order, check whether an order with that Shopify reference already exists. If it does, skip creation and return a 200 response so Shopify stops retrying.

Response Time Requirements

Shopify expects a 200 response within 5 seconds. If your endpoint takes longer, Shopify marks the delivery as failed and retries. For this reason, the webhook endpoint should accept the payload, validate the HMAC signature, enqueue the order for asynchronous processing, and return 200 immediately. The actual order creation happens in a background worker.


Stage 2: Customer Resolution

Every Shopify order includes customer data — email, name, phone, shipping address, and billing address. The integration must resolve this against Odoo's contact database.

Customer Matching Algorithm

The recommended matching logic follows this priority sequence:

  1. Exact email match: Search Odoo contacts for the email address from the Shopify order. Email is the most reliable unique identifier.
  2. Phone match (if no email match): Some B2B orders or POS orders may not have email. Fall back to phone number matching with normalization (strip spaces, dashes, country code normalization).
  3. Create new contact: If no match is found, create a new Odoo contact with all available data from the Shopify order.

Field Merging for Existing Customers

When an existing Odoo customer is matched, the integration should update (not overwrite) missing fields:

If Odoo contact has no phone but Shopify order does → add phone
If Odoo contact has phone and Shopify order has different phone → keep Odoo (source of truth)
If Shopify order has new shipping address → add as child contact (delivery address)

Address Handling

Shopify orders include both a billing address and a shipping address. In Odoo, these map to different contact types. The billing address should be associated with the main partner record (or a child contact of type "invoice address"). The shipping address should be a child contact of type "delivery address." If the customer has used multiple shipping addresses across different orders, each unique address should be a separate child contact — enabling address selection for future manual orders.

B2B Customer Handling

For B2B orders (Shopify Plus B2B features), the integration should map the Shopify company to an Odoo company-type contact, with the individual buyer as a child contact. This preserves the company-to-individual relationship that B2B operations require for credit terms, volume pricing, and account management.


Stage 3: Product Matching

Each line item on a Shopify order must be matched to a product in Odoo. This matching is where many integrations fail, because Shopify and Odoo represent products differently.

SKU-Based Matching

SKU is the recommended primary match key. When you manage products in Odoo and sync them to Shopify, the Odoo internal reference (SKU) should be set on both the Odoo product variant and the Shopify variant. The integration matches Shopify line item SKU to Odoo product variant internal reference.

Variant Matching Complexity

Shopify variants (Size: Large, Color: Blue) must match to Odoo product variants with the equivalent attribute values. This is straightforward when SKUs are consistent, but breaks when SKUs differ between systems, when Shopify has variants that do not exist in Odoo (e.g., a new variant added on Shopify but not yet synced to Odoo), or when Odoo products use configurable attributes while Shopify uses pre-defined variants.

Handling unmatched products: When a Shopify line item cannot be matched to an Odoo product, the integration should not silently skip it. Instead, it should create the order with a placeholder product line (e.g., a catch-all "Unmatched Shopify Product" item with the Shopify variant title in the description), flag the order for review, and alert the operations team.

Bundle and Kit Products

If you sell bundles on Shopify (e.g., a "Starter Kit" that ships as three separate products), the integration needs to know whether to create a single Odoo order line (for the bundle product) or multiple lines (for the component products). This depends on your Odoo inventory setup — whether you track bundle products as a single item or as individual components.


Stage 4: Order Creation in Odoo

With the customer resolved and products matched, the integration creates the Odoo sale order. This is the most data-intensive stage, requiring careful field mapping.

Field Mapping: Shopify to Odoo Sale Order

Shopify FieldOdoo FieldNotes
order.idx_shopify_order_idCustom field for reference
order.nameclient_order_refe.g., "#1042"
order.created_atdate_orderOrder date
order.customer.emailpartner_idResolved in Stage 2
order.shipping_addresspartner_shipping_idDelivery address contact
order.billing_addresspartner_invoice_idInvoice address contact
order.currencycurrency_idMap to Odoo currency
order.notenoteCustomer notes
order.tagstag_idsOptional tag sync

Line Item Mapping

Shopify FieldOdoo Sale Order Line FieldNotes
line_item.variant_idproduct_idResolved in Stage 3
line_item.quantityproduct_uom_qtyOrder quantity
line_item.priceprice_unitUnit price
line_item.total_discountdiscountConvert to percentage
line_item.tax_linestax_idMap to Odoo fiscal position

Discount Handling

Shopify represents discounts differently than Odoo. Shopify provides a discount amount per line item and an overall discount code at the order level. Odoo expects a discount percentage per line.

Conversion: discount_percentage = (shopify_discount_amount / (quantity * unit_price)) * 100

For order-level discounts (e.g., "10% off entire order"), the discount must be distributed across line items proportionally. Some implementations add a separate negative-amount line item for order-level discounts instead of distributing — both approaches are valid, but the proportional distribution produces cleaner per-line-item margin analysis.

Shipping Line

Shopify shipping charges should map to a dedicated Odoo product (e.g., "Shopify Shipping") on a separate order line. This keeps shipping revenue distinct from product revenue in reporting.

Shopify FieldOdoo LineNotes
shipping_lines[0].titleproduct_id → "Shopify Shipping"Description from Shopify
shipping_lines[0].priceprice_unitShipping amount
shipping_lines[0].tax_linestax_idShipping tax if applicable

Order Confirmation

After creating the sale order in draft state, the integration should automatically confirm it (action_confirm) to trigger downstream workflows — delivery order creation, manufacturing orders (for MTO products), and purchase orders (for dropship products). Only confirm automatically if the payment status is "paid" or "authorized" — hold draft orders for "pending" payment states.


Stage 5: Payment Recording

Shopify's financial_status field indicates the payment state of the order. The integration must translate this into Odoo payment records.

Payment Status Mapping

Shopify financial_statusOdoo ActionNotes
paidRegister payment (full)Create payment matching invoice
authorizedNo payment yetPayment captured later
partially_paidRegister partial paymentRecord amount paid so far
pendingHold in draftAwait payment confirmation
refundedRegister payment + credit noteFull refund scenario
partially_refundedRegister payment + partial creditPartial refund scenario
voidedCancel orderPayment authorization voided

Automatic Invoice Creation

For "paid" orders, the integration should create and validate the Odoo invoice automatically, then register the payment against it. This keeps the accounts receivable clean — fully paid Shopify orders should have zero AR balance in Odoo.

For "authorized" orders (common with Shopify Payments when manual capture is enabled), the integration should create the sale order but not the invoice. When the payment is later captured (triggering an orders/updated webhook with financial_status changing to "paid"), the integration creates the invoice and registers the payment.

Payment Method Configuration

Create a dedicated Odoo payment journal for Shopify payments (e.g., "Shopify Payments" journal of type "Bank"). All automated payment registrations should use this journal. This keeps Shopify payment records separate from other payment methods and simplifies bank reconciliation.


Stage 6: Fulfillment Writeback

The final stage closes the loop — when an order is fulfilled in Odoo (delivery order validated), the integration sends fulfillment data back to Shopify, updating the order status and providing the customer with tracking information.

Triggering the Writeback

In Odoo, the fulfillment event is the validation of a delivery order (stock.picking). The integration should listen for delivery order confirmation events and trigger a Shopify fulfillment API call.

Fulfillment Data Mapping

Odoo Delivery FieldShopify Fulfillment FieldNotes
carrier_tracking_reftracking_numberCarrier tracking number
carrier_id.nametracking_companye.g., "UPS", "FedEx"
move_line_idsline_itemsMap Odoo products back to Shopify line item IDs
date_done—Shopify timestamps automatically

Partial Fulfillment Handling

Partial fulfillments occur when an order ships in multiple packages, from multiple warehouses, or when some items are backordered. Shopify supports partial fulfillments natively — you can fulfill specific line items while leaving others unfulfilled. The integration must track which Shopify line items correspond to which Odoo delivery order lines, and send only the fulfilled items in each fulfillment API call. Sending a fulfillment for items that have already been fulfilled causes an API error.

Handling Split Shipments

When Odoo splits a delivery order into multiple shipments (backorder scenario), each shipment generates a separate delivery order. The integration must:

  1. Detect that the new delivery order is a backorder (related to the same sale order)
  2. Identify which line items are in this shipment
  3. Create a partial fulfillment on Shopify for only those items
  4. Include the correct tracking number for this specific shipment

Fulfillment Writeback for Dropship Orders

For dropship fulfillments (where the supplier ships directly to the customer), the tracking information comes from the purchase order receipt, not a warehouse delivery order. The integration should monitor purchase receipt confirmations for dropship orders and use the supplier's tracking number for the Shopify fulfillment.


Error Handling and Recovery

Errors in the order import pipeline fall into three categories, each requiring a different recovery strategy.

Transient Errors (Retry Automatically)

Network timeouts, API rate limits, temporary service unavailability — these resolve themselves. The integration should implement exponential backoff retry: first retry after 30 seconds, second after 2 minutes, third after 10 minutes, up to a configurable maximum retry count (typically 5–10).

Data Errors (Quarantine for Review)

Unmatched products, invalid addresses, missing required fields — these require human intervention. The integration should quarantine the order in a review queue with a clear description of what failed, create an Odoo activity or notification for the operations team, and provide a one-click retry mechanism after the data issue is fixed.

Systemic Errors (Alert Immediately)

Authentication failures, API permission changes, connector configuration errors — these affect all orders, not just one. The integration should detect patterns (e.g., 5 consecutive failures) and escalate immediately via email and dashboard alert.

The Dead Letter Queue

Orders that fail all retry attempts move to a dead letter queue — a persistent record of unprocessable orders. This queue must be monitored daily. Common dead letter reasons include products that exist in Shopify but were never synced to Odoo, customer data with invalid characters that Odoo rejects, orders with zero-price items that fail Odoo validation, and currency mismatches when a new Shopify currency is not configured in Odoo.


Testing the Order Import Pipeline

Before going live, test every path through the pipeline:

Functional Test Scenarios

ScenarioExpected Result
Standard paid orderOdoo SO created, confirmed, invoiced, payment registered
Order with discount codeDiscount distributed across lines correctly
Order with multiple variantsEach variant maps to correct Odoo product
Order for new customerNew Odoo contact created with all addresses
Order for existing customerExisting contact found, fields merged
Multi-currency orderRecorded in presentment currency, converted to functional
Partial fulfillmentShopify shows partially fulfilled with correct line items
Full fulfillmentShopify shows fulfilled with tracking number
Order cancellationOdoo SO cancelled, inventory restored
Refund (full)Credit note created, payment reversed
Refund (partial)Partial credit note for specific line items
Duplicate webhookSecond webhook does not create duplicate order
Product not in OdooOrder quarantined with alert
API rate limit hitOrder retried after backoff period

Load Testing

If your store processes high volumes (500+ orders/day), load test the import pipeline with production-like data volumes. Verify that the pipeline handles burst traffic (flash sales), that database locks do not create bottlenecks, and that Shopify and Odoo API rate limits are respected.


Performance Optimization

Batch Processing for Historical Imports

When initially setting up the integration or importing historical orders, use Shopify's REST API to fetch orders in batches of 250 (the maximum page size) rather than processing each order individually. Create Odoo records in batches using ORM create method with a list of values.

Caching Product and Customer Lookups

Product matching (Stage 3) and customer resolution (Stage 2) involve database lookups for every order. Cache frequently accessed products and customers to reduce Odoo API calls. Invalidate the cache when products or customers are updated.

Webhook Processing Concurrency

For high-volume stores, process webhooks concurrently — multiple workers pulling from the message queue simultaneously. Ensure concurrency safety by using database-level locking on the idempotency key check to prevent two workers from creating the same order simultaneously.


Frequently Asked Questions

How quickly do Shopify orders appear in Odoo with webhook-based automation?

With a properly configured webhook-based integration, Shopify orders appear in Odoo within 2–10 seconds of order placement. This includes webhook delivery, HMAC verification, customer resolution, product matching, and sale order creation. Cron-based alternatives add 5–60 minutes of delay depending on the polling interval.

What happens if Odoo is down when a Shopify order comes in?

The integration's message queue holds the order webhook payload until Odoo is available. When Odoo comes back online, the queue processes all pending orders in sequence. Shopify also retries failed webhook deliveries for up to 48 hours, providing a secondary safety net. Orders are never lost if the integration uses a persistent message queue.

Can I import orders from multiple Shopify stores into one Odoo instance?

Yes. Each Shopify store connects via its own set of API credentials and webhook subscriptions. The integration tags each order with the source store (using a custom field or Odoo sales team) so you can report by store. Products can be shared across stores or store-specific, depending on your catalog strategy.

How does the integration handle Shopify draft orders?

Draft orders (created by merchants for phone orders or B2B quotes) should be imported when they are completed (paid), not when they are created as drafts. Subscribe to the orders/create webhook, which fires when a draft order is converted to a real order. Alternatively, subscribe to draft_orders/update and import only when the status changes to "completed."

What about Shopify POS orders — do they follow the same pipeline?

Shopify POS orders trigger the same orders/create webhook as online orders. The integration can process them identically, though you may want to tag POS orders with a different Odoo sales team or source for reporting. POS orders may also include cash or external terminal payment methods, which require different Odoo payment journal configurations.

How do I handle order edits after import (e.g., merchant edits an order on Shopify)?

Shopify fires an orders/updated webhook when an order is edited. The integration should compare the updated order against the existing Odoo sale order and apply the differences — added line items, removed items, quantity changes, or price adjustments. This is one of the most complex parts of the integration, and some implementations handle it by cancelling the Odoo SO and recreating it, which is simpler but creates more accounting entries.

Can the automation handle subscription orders from Shopify Subscriptions apps?

Subscription orders (from Recharge, Bold Subscriptions, or Shopify native subscriptions) trigger standard orders/create webhooks for each recurring charge. The integration imports them like any other order. To link recurring orders to an Odoo subscription record, use the subscription ID from the app's metafield as a reference, and associate all related Odoo sale orders with a single Odoo subscription.


Implementation With ECOSIRE

Building a production-grade Shopify-to-Odoo order import pipeline requires handling dozens of edge cases that are not obvious until you encounter them in production — partial payments, orders with both digital and physical items, complex tax jurisdictions, multi-warehouse routing, and vendor dropship fulfillments.

Our Shopify integration services include complete order automation with the full pipeline described in this guide, pre-built handling for all common edge cases, real-time monitoring and alerting, and ongoing maintenance as APIs evolve.

For businesses also looking to automate the financial side, see our guide to Shopify + Odoo Accounting Integration, or compare your options with our Shopify-Odoo connector comparison.

Schedule a consultation to discuss your Shopify order automation requirements with our integration team.

E

Written by

ECOSIRE Research and Development Team

Technical 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

Transform Your Business with Odoo ERP

Expert Odoo implementation, customization, and support to streamline your operations.