Skip to Content

Retries and Idempotency in Odoo Integrations: Preventing Duplicate Transactions

Discover how BrowseInfo helps businesses build reliable Odoo integrations with retry-safe workflows, idempotency controls, duplicate transaction prevention and scalable integration architecture.
12 min read
September 15, 2026
Odoo Integration

Introduction

Integration failures rarely happen at the most convenient moment.

An API request may reach Odoo but fail to return a response. A payment provider may process a transaction while the network connection times out. A webhook may be delivered more than once. An external system may retry the same request because it cannot determine whether the first request succeeded.

This creates one of the most dangerous problems in ERP integration:

The system cannot tell whether a request is new or a retry.

Without proper controls, the same customer order can be created twice, a payment can be recorded multiple times, inventory can be updated repeatedly, or an external transaction can be processed more than once.

For businesses integrating Odoo with payment gateways, eCommerce platforms, marketplaces, logistics systems, banking platforms, or custom applications, retries and idempotency should be treated as core integration architecture not as error-handling details.

What Are Retries in an Odoo Integration?

A retry occurs when an integration attempts the same operation again after the first attempt appears to have failed.

For example:

External System → Odoo

The external application sends a sales order.

Odoo processes the request successfully.

Before the external system receives the response, the network connection fails.

The external system assumes the request failed and sends it again.

If Odoo treats the second request as a new transaction, two sales orders may be created.

The original request was successful.

The response was what failed.

This distinction is critical.

What Is Idempotency?

Idempotency means that processing the same request multiple times produces the same business result as processing it once.

For example:

Request ID: ORD-84721

The integration sends the request three times because of network failures.

With idempotent processing:

First request → Order created

Second request → Existing order identified

Third request → Existing order returned

The result remains:

One business transaction.

Idempotency therefore provides protection when retries are necessary.

Retries improve reliability.

Idempotency makes retries safe.

Why Odoo Integrations Need Idempotency

Odoo commonly participates in integrations involving:

  • eCommerce orders
  • Payment gateways
  • Marketplaces
  • Shipping platforms
  • Banking systems
  • CRM systems
  • Manufacturing systems
  • Subscription platforms
  • Customer portals
  • External applications
  • Webhooks
  • Custom APIs

Any integration that creates or updates business records can potentially encounter duplicate requests.

The risk becomes particularly serious for operations such as:

Create Sale Order → Create Invoice → Register Payment

or:

Payment Request → Payment Confirmation → Accounting Entry

or:

Order → Delivery → Stock Movement

A duplicate read operation may be inconvenient.

A duplicate financial or inventory transaction can become a business problem.

1. Identify the Business Transaction Before Designing the API

The first architectural question should not be:

“Which endpoint should we call?”

Instead ask:

“What business transaction are we protecting?”

For example:

IntegrationBusiness TransactionDuplicate Risk
eCommerce → OdooSales OrderHigh
Payment Gateway → OdooPayment ConfirmationVery High
Marketplace → OdooCustomer OrderHigh
Shipping → OdooDelivery StatusMedium
Bank → OdooTransaction ImportVery High
CRM → OdooLead CreationMedium
Product System → OdooProduct UpdateMedium

The integration design should then identify the unique business reference that represents each transaction.

2. Use a Stable Idempotency Key

Integration ComponentRecommended ApproachPurpose
Transaction IDStable external referenceIdentify business transaction
Idempotency KeyUnique per transactionDetect repeated requests
Odoo RecordStore external referenceLink systems
Duplicate CheckSearch before creationPrevent duplicate records
Processing StatusPending/Success/FailedTrack transaction state
Response StorageStore successful resultReuse result on retry
Error LogStore failure detailsSupport troubleshooting
Retry CounterTrack attemptsControl repeated failures

An idempotency key is a unique identifier representing one business operation.

For example:

payment_20260915_84721

or:

shopify_order_100928

or:

warehouse_transfer_EXT-47281

The key should come from the business transaction—not from the individual HTTP attempt.

That distinction is important.

If a request fails and is retried, the retry should use:

The same idempotency key.

It should not generate a new key for every attempt.

The basic flow

Generate Business ID

Send Request

Process Transaction

Store Idempotency Key

Retry if Necessary

Detect Existing Key

Return Existing Result

This allows the receiving system to distinguish a new operation from a retry.

3. Store the External Reference in Odoo

For integrations that create important Odoo records, store the external transaction identifier.

For example:

External Order ID: SHOP-100928

External Payment ID: PAY-78341

External Shipment ID: SHIP-55421

This creates a relationship between the external transaction and the Odoo record.

Before creating a new record, the integration can check whether the external reference already exists.

Conceptually:

External ID exists?

→ Yes: Return or update the existing record.

→ No: Create the new record.

This simple control can prevent many duplicate-record scenarios.

4. Do Not Generate Idempotency Keys From Request Time

A common design mistake is generating a new identifier every time the integration sends a request.

For example:

Attempt 1 → ID 1001

Attempt 2 → ID 1002

The system now believes these are two different transactions.

Instead:

Business Transaction → ID 1001

Attempt 1 → ID 1001

Attempt 2 → ID 1001

Attempt 3 → ID 1001

The identifier belongs to the transaction, not the network request.

5. Design Retries Around Failure Types

Failure TypeExampleRetry?Recommended Action
Network TimeoutExternal API does not respondYesRetry with controlled backoff
Temporary Server ErrorHTTP 500YesRetry after a delay
Rate LimitHTTP 429YesRespect retry-after or backoff
Authentication FailureInvalid API keyNoFix credentials first
Validation ErrorMissing required fieldNoCorrect the request
Duplicate RequestSame transaction sent againNoReturn or reuse existing result
Business Rule ErrorInvalid order stateUsually NoResolve business condition
Service UnavailableExternal system temporarily offlineYesRetry within defined limits

Not every error should trigger a retry.

A useful classification is:

Temporary Failure

Examples:

  • Network timeout
  • Temporary service unavailable
  • Connection reset
  • HTTP 5xx response

These may be retryable.

Permanent Failure

Examples:

  • Invalid customer
  • Invalid product
  • Missing required field
  • Authentication failure
  • Business-rule validation error

These normally require correction rather than repeated retries.

Unknown Outcome

This is the most dangerous category.

The external system does not know whether Odoo completed the transaction.

For example:

Request sent → Odoo processes → Network timeout → No response

The correct response is not necessarily to create a new transaction.

The system should first use the idempotency key or external reference to determine whether the original operation already succeeded.

6. Use Controlled Retry Strategies

Retrying immediately and continuously can make an outage worse.

A better strategy uses:

Limited Attempts + Increasing Delay + Clear Failure State

For example:

Attempt 1 → Immediate

Attempt 2 → 30 seconds

Attempt 3 → 2 minutes

Attempt 4 → 10 minutes

The exact timing depends on the integration.

The important principle is to avoid uncontrolled retry loops.

Retries should also have:

  • Maximum attempts
  • Maximum execution time
  • Error classification
  • Retry status
  • Final failure state
  • Monitoring

7. Make Webhook Processing Idempotent

Webhooks are particularly sensitive to duplicate delivery.

Odoo 19 supports webhook-based automation where an external system sends a payload to an Odoo webhook URL and a predefined action is performed in Odoo. Odoo recommends testing webhooks carefully before using them in a live database.

Consider:

Payment Provider → Webhook → Odoo

The payment provider sends:

PAY-88391 = Paid

If the webhook is delivered twice, Odoo should not create two payment records.

Instead:

Receive PAY-88391

Check Existing Payment Reference

Already Processed?

→ Yes: Return success.

→ No: Process payment.

This makes webhook handling safe against repeated delivery.

8. Protect Payment Integrations With Stronger Controls

Payment integrations require additional care because duplicates can have direct financial consequences.

A payment transaction should normally have a provider-side reference that can be associated with the Odoo payment transaction.

Odoo's payment transaction framework itself includes mechanisms for computing and searching transactions by provider references, which illustrates the importance of stable transaction identifiers in payment processing.

A payment workflow should therefore distinguish:

Payment Requested

from:

Payment Successfully Confirmed

and:

Payment Already Processed

The integration should never assume that a timeout means the payment failed.

The provider's transaction status should be checked when the outcome is uncertain.

9. Understand Odoo Transaction Boundaries

Transaction boundaries are another important part of integration design.

Odoo's JSON-2 API runs each call in its own SQL transaction. A successful call is committed, while an error causes that transaction to be discarded. Odoo's documentation also warns that multiple separate calls cannot be chained into one transaction through JSON-2.

This matters when an integration performs multiple related operations.

For example:

Create Order

then:

Confirm Order

then:

Create Delivery

then:

Create Invoice

If these are implemented as separate API calls, another transaction or concurrent process can change the state between calls.

Where multiple related operations need to remain atomic, Odoo recommends using a single method that performs the related operations in one transaction.

This can be particularly important for reservations, payments and other sensitive workflows.

10. Avoid Partial Integration Transactions

Consider this process:

External Order

Create Odoo Order - Success

Create Odoo Invoice - Failure

Retry Entire Request

If the retry blindly creates everything again, the integration may create a duplicate order.

Instead, each business transaction should have a clearly defined state.

For example:

Integration StateMeaning
ReceivedRequest arrived
ProcessingTransaction is being handled
CompletedBusiness operation succeeded
Retry PendingTemporary failure occurred
FailedManual intervention required
DuplicateExisting transaction detected

This makes failures visible and recoverable.

11. Keep an Integration Log

A reliable integration should provide enough information to answer:

What happened to this transaction?

For every important request, consider recording:

  • External transaction ID
  • Idempotency key
  • Odoo record ID
  • Request timestamp
  • Response timestamp
  • Attempt number
  • Request status
  • Error message
  • Last retry time
  • Final result

This makes troubleshooting significantly easier.

Instead of asking:

“Why did this order duplicate?”

the team can investigate:

“Order EXT-84721 was received three times. The first request created sale.order 12541, while attempts two and three matched the existing external reference.”

That is actionable information.

12. Make Duplicate Detection Explicit

Duplicate prevention should not depend on developers remembering to check for duplicates.

The business rule should be explicit.

For example:

External Payment ID must be unique.

External Order ID must be unique.

External Shipment ID must be unique.

Where appropriate, enforce uniqueness at the database/model level rather than relying only on application logic.

This provides stronger protection against concurrent requests.

13. Design for Concurrent Requests

Two requests can arrive at almost the same time.

For example:

Request A → Check external ID → Not Found

Request B → Check external ID → Not Found

Both requests may then attempt to create the same Odoo record.

This is why:

Check → Then Create

alone may not always be sufficient.

For high-value transactions, the design should also consider database-level uniqueness or another concurrency-safe mechanism.

The goal is to ensure that simultaneous requests cannot create multiple records for the same business transaction.

14. Make Updates Idempotent Too

Idempotency is not only for record creation.

Updates can also be repeated.

For example:

Shipment Status = Delivered

If the same webhook arrives five times, the result should remain:

Delivered

rather than triggering five downstream actions.

For updates, consider:

  • External reference
  • Event ID
  • Event timestamp
  • Current state
  • Previous state
  • Version number

The integration should understand whether the incoming event is new, repeated, or outdated.

15. Test Failure Scenarios Before Go-Live

Normal success testing is not enough.

Integration testing should deliberately simulate failures.

Test scenarios such as:

  • Request timeout
  • Network failure
  • Duplicate webhook
  • Duplicate API request
  • Odoo validation error
  • External API failure
  • Payment confirmation received twice
  • Two requests arriving simultaneously
  • Partial transaction failure
  • Retry after successful processing
  • Delayed webhook
  • Out-of-order events

For each scenario, ask:

What business records exist after the failure?

The expected answer should be clearly defined before production deployment.

16. Build an Odoo Integration Retry and Idempotency Framework

A practical architecture can follow:

Business Transaction ID

Idempotency Check

Validate Request

Process Transaction

Commit Successful Result

Store Result

Return Response

If the same request arrives again:

Receive Request

Find Existing Idempotency Key

Existing Result Found

Return Existing Result

No duplicate transaction is created.

Common Integration Mistakes

Retrying Every Error

Permanent business errors should not be endlessly retried.

Creating a New ID on Every Retry

The same business transaction needs the same idempotency identity.

Assuming Timeout Means Failure

A timeout only means the caller did not receive the response.

Relying Only on Application-Level Duplicate Checks

Concurrent requests can bypass a simple check-before-create pattern.

Ignoring Webhook Duplicates

Event-driven integrations must expect repeated delivery.

Not Logging Attempts

Without integration logs, duplicate transactions become difficult to investigate.

Splitting Atomic Operations Into Multiple Calls

Related operations may require a single transactional method in Odoo.

Testing Only Successful Scenarios

Production failures rarely behave like the happy-path test case.

Odoo Integration Retry & Idempotency Checklist

Before launching an integration, confirm that you have:

  • Defined the business transaction

  • Created stable external references

  • Defined idempotency keys

  • Stored external transaction IDs in Odoo

  • Classified retryable and non-retryable errors

  • Configured limited retry attempts

  • Added appropriate retry delays

  • Protected webhook processing

  • Protected payment transactions

  • Defined transaction boundaries

  • Added duplicate detection

  • Considered concurrent requests

  • Added integration logs

  • Defined failure states

  • Tested duplicate requests

  • Tested timeout scenarios

  • Tested partial failures

  • Tested webhook re-delivery

  • Defined monitoring and alerting

Frequently Asked Questions

1. What is idempotency in Odoo integrations?

Idempotency means processing the same integration request multiple times produces the same business result instead of creating duplicates.

It is especially important for orders, payments, invoices, inventory transactions and webhook-driven workflows.

2. Why are retries important in Odoo integrations?

Retries help recover from temporary failures such as network timeouts, unavailable services, or temporary API errors.

However, retries should be combined with duplicate detection so the same transaction is not processed twice.

3. How can Odoo integrations prevent duplicate transactions?

Use stable business references or idempotency keys and check whether the transaction has already been processed before creating a new record.

The integration should store the external reference and return the existing result when the same request is received again.

4. What is an idempotency key?

An idempotency key is a stable identifier associated with a specific business transaction or request.

The receiving system uses it to recognize repeated requests and prevent duplicate processing.

5. Can webhooks create duplicate records in Odoo?

Yes, duplicate webhook deliveries can create duplicate records if the receiving workflow does not identify previously processed events.

Webhook handlers should validate the event reference and make processing safe for repeated delivery. Odoo recommends testing webhooks before implementation.

6. Why should integrations store external transaction references?

External references create a reliable link between the transaction in Odoo and the source system.

They make duplicate detection, reconciliation, troubleshooting and support much easier.

7. How does Odoo 19 JSON-2 affect integration design?

Odoo 19's JSON-2 API executes each API call within its own SQL transaction, committing successful calls and rolling back failed ones.

Related operations that must succeed or fail together should therefore be handled within a single Odoo method where appropriate.

8. Should every integration error trigger a retry?

No. Temporary failures may be retried, but validation errors, authentication failures and permanent business-rule errors usually require correction instead.

A retry strategy should classify errors before deciding whether another attempt is appropriate.

Conclusion

Odoo integrations should be designed with the assumption that requests can fail, time out, or be delivered more than once. Retries are important for reliability, but without idempotency and stable transaction references, they can create duplicate orders, payments, stock movements, or other business transactions.

A reliable integration therefore needs more than API connectivity. It needs stable identifiers, duplicate detection, controlled retries, clear transaction boundaries, proper logging and testing for failure and concurrency scenarios. Odoo 19's JSON-2 API also treats each API call as its own database transaction, making transaction design particularly important when related operations need to remain consistent.

The goal is to build integrations that remain predictable even when something goes wrong. BrowseInfo can help businesses design and implement scalable Odoo integrations with stronger retry handling, idempotency controls, integration architecture, monitoring and long-term maintainability.

Retries and Idempotency in Odoo Integrations: Preventing Duplicate Transactions
Vishesh Joshi Business Systems Strategist

About the Author

Helps organizations scale operations, improve visibility, and drive growth through process transformation, ERP strategy, and digital execution. Writes about business systems, operational excellence, and technology-led growth.
Book a Consultation

Share this post