Appearance
Idempotency & failure handling
Receiving orders
The receive endpoint sits between two systems that both retry. Get three things right and nothing gets booked twice or lost.
1. Idempotency on request_id
request_id is AIOTIC's identity for the order and it never changes across retries of a send. Your rule: one request_id → at most one sales order.
python
existing = erp.find_order_by_request_id(request_id) # external reference column, indexed
if existing:
return {"success": True, "order_number": existing.number}Persist the link in the same transaction as the order (or before you answer). If you keep it in a side table, write it before returning success: true.
The SDK's ErpReceiver does this with an IdempotencyStore (in-memory, SQLite, or your own) and asks the adapter's find_order_by_request_id as a second line of defence.
2. Transactions
Create header and lines atomically. A half-written order that later answers success: false leaves debris in the ERP that no one knows about. With a data API this means one database transaction; with a functional API, one create call (or compensating delete on failure).
3. Failure paths, one by one
| What went wrong | Right behaviour | Result in AIOTIC |
|---|---|---|
| Wrong key | 401, {"success": false, "error": "unauthorized"} | rollback; operator sees error |
| Payload does not validate (your rules) | {"success": false, "error": "<why>"} | rollback; operator fixes and resends |
| ERP rejects for business reasons | {"success": false, "error": "<ERP text>"} | same |
| ERP unreachable / timeout | {"success": false, "error": "ERP unavailable, retry later"} — nothing written | rollback; retry later |
| Your endpoint crashes after the ERP created the order but before answering | AIOTIC times out and rolls back; the operator retries; your idempotency lookup finds the order and answers success: true | consistent |
| Your endpoint is down entirely | AIOTIC gets a connection error, rolls back | operator retries when you are back |
The one case you must design for is the crash after create: the external reference must be written with the order, not afterwards.
4. Duplicates that are not retries
A customer can send the same PO twice; an operator can upload it twice. Those arrive with different request_ids. Detect by (customer_id, order_number) and decide:
- reject with
success: false"PO EB2500011645 already booked as SO-981" (recommended — a person decides), or - accept and create a new order if your business allows repeat POs with the same number.
The SDK's NoDuplicateOrder rule implements the first policy; the key is remembered only after a successful booking, so a rejected order can be corrected and sent again.
5. What to log
Per call: request_id, outcome, order_number or error text, duration. Never the key. Keep the payload for a while (it is small) — support questions come days later.
6. What to monitor
- rate of
success: falseper error text (a spike in "unknown article" means your product sync is behind) - p95 response time (must stay well under 30 s)
- calls with an unknown key (someone is probing)