Idempotent ERP API Retry Wrapper (Python Generator)
A retry loop that resends a purchase order after a timeout can create two purchase orders. This generator outputs a small Python wrapper that retries on the right failures, waits with exponential backoff and jitter, honors Retry-After, and keeps one idempotency key across attempts.
Fill in
Use the header your ERP or gateway documents. Many APIs have none.
retry_wrapper.py
import os
import random
import time
import uuid
import requests
BASE_URL = "https://erp.example.com/api/v1"
RETRY_STATUS = {429, 500, 502, 503, 504}
MAX_ATTEMPTS = 5
BASE_DELAY = 1
MAX_DELAY = 30
TIMEOUT = 20
def _sleep_seconds(attempt, response):
# Honor Retry-After when the server sends a number of seconds
if response is not None:
value = response.headers.get("Retry-After")
if value and value.isdigit():
return min(int(value), MAX_DELAY)
delay = min(MAX_DELAY, BASE_DELAY * (2 ** attempt))
return random.uniform(0, delay)
def call_erp(method, path, json_body=None, idempotency_key=None):
url = BASE_URL + path
headers = {
"Authorization": "Bearer " + os.environ["ERP_API_TOKEN"],
"Accept": "application/json",
}
is_write = method.upper() in ("POST", "PATCH", "PUT")
if is_write:
# Same key on every attempt so the server can drop duplicates
headers["Idempotency-Key"] = idempotency_key or str(uuid.uuid4())
last_error = None
for attempt in range(MAX_ATTEMPTS):
response = None
try:
response = requests.request(
method, url, headers=headers, json=json_body, timeout=TIMEOUT
)
if response.status_code not in RETRY_STATUS:
return response
last_error = "HTTP " + str(response.status_code)
except (requests.ConnectionError, requests.Timeout) as exc:
last_error = str(exc)
if attempt < MAX_ATTEMPTS - 1:
time.sleep(_sleep_seconds(attempt, response))
raise RuntimeError("Giving up after " + str(MAX_ATTEMPTS) + " attempts: " + str(last_error))Usage example
resp = call_erp("GET", "/salesorders/41822")
resp.raise_for_status()
print(resp.json())
# Write: keep the key stable if you must re-run the same business action
key = "po-create-2026-10-20-ACME-0001"
resp = call_erp("POST", "/purchaseorders", json_body={"vendor": "V1001"}, idempotency_key=key)Only send an idempotency header if your ERP, API gateway or middleware actually honors it. If it does not, do not auto-retry writes on 5xx or timeouts: read the record first to see whether the first attempt committed. Requires the requests package. Verify header names and retry status codes against your vendor documentation.
Safe write-back design session
Optional: walk through your ERP write path with an engineer.
Optional. The tool and every export work without this. No spam.
How to use it
Set your base URL, the environment variable that holds the token, and the header name your API uses for idempotency. Choose attempt count and delays, then copy the code into your integration or agent tool. Call the function with the HTTP verb and path. For writes, pass your own stable key when the same business action might be triggered twice, such as a message processed again after a crash.
The method behind it
Exponential backoff doubles the wait after each failure, capped at a maximum. Full jitter picks a random value between zero and that delay so many clients do not retry in lockstep against a recovering ERP server. Retry-After from the server overrides the computed delay. An idempotency key lets the server recognize a repeated write and return the original result instead of executing it again.
- Retry set: 429, 500, 502, 503, 504, plus connection errors and timeouts
- Never retry 400, 401, 403, 404, 409, 422 automatically
- Same key across all attempts of one business action
- Cap total attempts and surface the failure
When this is not enough
Many ERP APIs have no idempotency support. In that case a timeout on a write leaves you not knowing whether the record exists. The safe pattern is to generate a client reference number, store it in a custom or external reference field, and query by it before retrying. Also consider a queue so a single worker owns each business action and concurrency stays below the ERP limits.
Common mistakes
The usual errors are generating a new key per attempt, which defeats the purpose, retrying on 4xx errors that will never succeed, and using a fixed sleep that makes every worker hit the server together. Another is forgetting a timeout, so a hung connection blocks the agent forever.
Frequently Asked Questions
What is an idempotency key?
It is a unique value the client sends with a write request so the server can detect a repeat of the same request and return the first result instead of performing the action twice. The key must stay the same across retries of one action.
Which ERPs support idempotency keys?
Support varies and is often absent on classic ERP APIs. Some gateways and payment style APIs honor it. Check your vendor documentation, and if there is no support use a client reference field and a lookup before retrying.
Why add jitter to backoff?
Without jitter, many clients that failed at the same moment retry at the same moment, which can overload a recovering server again. A random delay spreads the retries and reduces the repeated spikes.
Should an AI agent retry writes at all?
Only when duplicates are impossible or detectable. For most ERP writes we prefer approval before the call, one attempt, and a verification read if the outcome is unclear, rather than automatic repeated attempts.
Netray designs ERP integrations for AI agents where writes go through approval and safe retry. Contact us if you want your write path reviewed.
Related Tools
HTTP Status Codes for ERP API Agents Reference
Look up an HTTP status code and see what it usually means on an ERP API and whether an agent should retry, fix the request or escalate.
Developer ToolsPaginated OData Fetch Loop Python Generator
Build a Python loop that follows nextLink pages from an OData entity set and writes the result to CSV with a hard row cap.
Developer ToolsWebhook HMAC Signature Verification Node.js Generator
Create an Express endpoint that checks the HMAC of the raw body, rejects stale timestamps and acknowledges quickly for ERP event webhooks.
Developer ToolsERP Agent API Integration Readiness Assessment
Answer ten questions about APIs, roles, limits and logging to see whether your ERP is ready for an AI agent or MCP integration.
More Developer Tools tools
See all- SAP Sales Order ABAP SELECT Generator (VBAK, VBAP, VBFA)
- SAP Sales Order Create BAPI ABAP Generator (BAPI_SALESORDER_CREATEFROMDAT2)
- SAP ABAP Open Items SELECT Generator
- SAP ACDOCA SQL Query Generator
- SAP QM Inspection Lot ABAP SELECT Generator
- SAP Quality Notification Pareto SQL Query Generator
- SAP QM Usage Decision BAPI Skeleton
- ABAP Custom Exception Class Generator
- ABAP Unit Test Class Generator
Keep exploring
Free tools
- Webhook Retry Backoff Window CalculatorShows how long an exponential retry policy keeps trying and whether it outlasts your receiver's expected outage.
- Messaging Webhook Retry Backoff Schedule CalculatorWork out how long an exponential backoff retry policy keeps trying before a WhatsApp, Teams or Slack message is parked for review.
- SAP Interface Retry and Backoff Window CalculatorSee how long an interface keeps retrying before it gives up, using initial delay, multiplier, retry count and jitter.
ERP fixes and how-tos
- How to Send Production and Labor Reporting from MES to ERPHow to design MES to ERP production and labor reporting: operation confirmations, good and scrap quantities, labor clock times, idempotent posting and error handling.
- Calling SAP APIs from Python: OData with requests, Authentication and PyRFCCall SAP from Python with the requests library: authentication, filtering, paging and CSRF tokens for OData, plus when PyRFC and RFC make sense.
- Infor OS Usage Limits: What They Are and What to Do When You Hit ThemInfor OS usage limits: how API throttling and quotas show up, how to confirm you are being limited, and how to reduce calls or request a higher allowance.
Guides
- Integration Error Handling Patterns for ERP LandscapesIntegration error handling patterns for ERP: retries with backoff, idempotency keys, dead-letter queues, poison-message handling, and replay you can trust.
- Legacy ERP AI Modernization: Wrappers vs RewritesModernize a legacy ERP with AI: when an AI wrapper layer beats a full rewrite, how to scope it, and the failure modes of each approach in manufacturing.
- Managing Rate Limits and Throttling in SyteLine REST APIsManage SyteLine REST API rate limits and throttling. Configure request quotas, implement backoff strategies, and optimize throughput for CloudSuite Industrial APIs.