Skip to content

Quick start (15 minutes) ​

Start here

You will run a mock AIOTIC tenant, a receive endpoint with the SDK's validation pipeline, upload an order, and watch it flow into a (demo) ERP. Nothing here touches a real tenant.

Prerequisites

Python 3.11+ and pip (or uv). No AIOTIC account needed for this exercise.

1. Install the SDK ​

bash
python -m venv .venv && source .venv/bin/activate
pip install "aiotic-sdk[all]"
bash
uv venv && source .venv/bin/activate
uv pip install "aiotic-sdk[all]"

2. Start a mock tenant ​

bash
aiotic mock
# Mock AIOTIC tenant on http://localhost:8080
# keys: mock-integration-key (all endpoints), mock-sync-key (master data only)

The mock implements the public API with realistic behaviour: uploads move through Waiting → Processing → Processed in a few seconds, a file name containing attention produces an Attention order with an unresolved article, fail produces Failed, and /erp/send really calls your endpoint.

3. Bootstrap your service ​

In a second terminal:

bash
aiotic init            # answers: base URL http://localhost:8080, key mock-integration-key
aiotic doctor

init writes a .env (base URL, keys, a freshly generated AIOTIC_ERP_RECEIVE_KEY) and a service.py. doctor checks connectivity, both keys and whether master data is present:

┃ check                          ┃ result                          ┃
│ GET /healthcheck               │ OK ok                           │
│ GET /order_status/list (key)   │ OK 0 orders                     │
│ master data: customers         │ OK 1 records                    │
│ master data: products          │ OK 3 records                    │

4. Run the receive endpoint ​

bash
aiotic serve           # http://localhost:9000  (POST /aiotic/orders, /aiotic/processing, /erp/events)

service.py is three lines — the in-memory demo ERP behind the default pipeline:

python
from aiotic.service import build_app
from aiotic.erp.memory import InMemoryErp   # replace with your adapter later

app = build_app(erp=InMemoryErp())

Tell the mock tenant where your endpoint lives (in production you give this to the AIOTIC team; the mock has a helper):

bash
curl -X POST localhost:8080/_mock/config -H 'Content-Type: application/json' \
  -d "{\"erp_url\": \"http://localhost:9000/aiotic/orders\", \"erp_key\": \"$(grep AIOTIC_ERP_RECEIVE_KEY .env | cut -d= -f2)\"}"

5. Upload an order and send it ​

bash
echo "fake pdf" > PO-4711.pdf
aiotic orders upload PO-4711.pdf
# uploaded → request_id 7f0c…   then:  7f0c…: PROCESSED — PO-4711, 2 lines

aiotic orders send 7f0c…
# sent — ERP reference SO-1000

What happened, in sequence:

Your receive endpointAIOTICOperator / API callerstatus must be PROCESSED, MODIFIED or ATTENTION→ lock as SENDING (409 if already sending)merge operator corrections into the payloadstatus → SENT, erp_ref = "SO-981"Failure path — {"success": false, "error": "…"} → status rolls back, the caller gets 422 with your error text.Non-JSON body or timeout → rollback + 500. Nothing is lost — the operator can retry.POST /erp/send/{request_id}1POST ‹ERP URL› {request_id, purchase_order}X-API-KEY: your key · timeout 30 s2{ "success": true, "order_number": "SO-981" }3200 { success, request_id, data }4
Your receive endpointAIOTICOperator / API callerstatus must be PROCESSED, MODIFIED or ATTENTION→ lock as SENDING (409 if already sending)merge operator corrections into the payloadstatus → SENT, erp_ref = "SO-981"Failure path — {"success": false, "error": "…"} → status rolls back, the caller gets 422 with your error text.Non-JSON body or timeout → rollback + 500. Nothing is lost — the operator can retry.POST /erp/send/{request_id}1POST ‹ERP URL› {request_id, purchase_order}X-API-KEY: your key · timeout 30 s2{ "success": true, "order_number": "SO-981" }3200 { success, request_id, data }4

The mock did what a real tenant does: locked the order, POSTed it to your endpoint with the key, read success, stored the ERP reference.

6. See a rejection ​

bash
echo "x" > PO-4712-attention.pdf
aiotic orders upload PO-4712-attention.pdf      # → ATTENTION (one line has no article number)
aiotic orders send <request_id>
# ERP error: Line 3 has no article number (items[2].article_number)

The pipeline rejected the order before it reached the ERP, and the message is exactly what an operator would see in the AIOTIC app. Change service.py to use DataApiAdapter (a SQLite demo ERP with only tables) and you will see why that matters:

python
from aiotic.service import build_app
from aiotic.erp.data_api import DataApiAdapter, sqlite_demo

app = build_app(erp=DataApiAdapter(sqlite_demo("erp-demo.db")))

Where to go next ​

Revision 28-051026-58cfad3 · API v1.0.0 · AIOTIC is a product of DevOps Company.