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