Appearance
Errors, idempotency & limits
Concepts
Error shape
Every error is JSON with a detail member. Usually a string:
json
{ "detail": "Document with ID 550e8400-e29b-41d4-a716-446655440000 not found" }A few endpoints return a structured detail so you can branch on a stable code instead of parsing text. Today that is POST /order/raw/upload when the e-mail is not a purchase order:
json
{ "detail": { "error": "not_a_purchase_order", "message": "…", "request_id": "…", "category": "quotation",
"subject": "Offer 10531", "language": "de", "line_item_count": 25 } }Write your client so that detail may be a string or an object. FastAPI-style validation errors (422) carry a list under detail.
Status codes
| Code | Meaning | Typical cause |
|---|---|---|
200 / 202 / 204 | OK / upsert accepted / deleted | |
400 | Bad request | malformed UUID, unsupported file, order not in FAILED for a retry, e-mail not a PO |
401 | Unauthorized | missing/invalid key, or the sync key on a non-master-data path |
404 | Not found | unknown order / customer / product / mapping; mapping references a missing customer or product |
409 | Conflict | order not sendable or already SENDING; rejected e-mail already overridden |
415 | Unsupported media type | file extension not accepted |
422 | Unprocessable | your ERP answered success: false on a send (detail = your error text); validation error |
500 | Server error | your ERP returned a non-JSON body or timed out during a send; unexpected failure |
503 | Unavailable | tenant not initialised, classification or ERP integration not configured |
Retrying safely
| Operation | Safe to retry? | How |
|---|---|---|
POST /order/upload | Yes, if you pass your own request_id | Same UUID → same order; without it a retry creates a duplicate order |
PUT master data | Yes | Upserts are idempotent |
DELETE master data | Yes | A second delete returns 404 — treat as success |
POST /erp/send/{id} | Yes | AIOTIC locks the order; a concurrent send gets 409; a failed send rolls back so you can send again |
POST /order/retry/{id} | No (creates a new order each time it succeeds) | Check the status first |
GET anything | Yes |
Retry on 408, 429, 502, 503, 504 and on connection errors with exponential backoff and jitter (the SDK: 0.5 s · 2^attempt, capped at 30 s, three attempts). Do not retry a 503 on /erp/send blindly — it means the tenant has no ERP endpoint configured.
Idempotency on your side
Your ERP receive endpoint is called with a request_id that is stable across retries. Store request_id → your order number before you answer, and answer the same thing again if you see the id twice. Details in Idempotency & failure handling.
Correlating orders
- Put your own reference in the upload as extra form fields; it comes back in
metadataon every status read. - Use
request_idin your ERP as the external reference. It appears in the AIOTIC app, in support tickets and in the hand-off payload.
Limits
| Limit | Value |
|---|---|
size on list endpoints | 1 … 1000 |
top_k on customer search | 1 … 1000 |
| Files per upload | any; all files form one order |
| Accepted upload types | .pdf .jpg .jpeg .png .txt .md (+ .eml on the raw endpoint) |
| ERP receive timeout | 30 s default |
| Server-side rate limit | none — self-limit (SDK default 10 req/s) |