Ogni snippet qui sotto colpisce endpoint reali — niente mock. I flussi edge puntano al runtime del nodo (http://<edge>:8291, il verticale manifests/LayoutManifest.production-line.example.json), i flussi cloud puntano al Control Plane (https://cp.axiom-trace.eu). Se non hai ancora letto Il Contratto, leggilo prima.
1 — Sessione operatore (edge)
# Login PIN → token di sessione (TTL in expiresInHours, revocabile, auditato)
TOKEN=$(curl -s http://localhost:8291/api/v1/auth/login \
-H 'content-type: application/json' \
-d '{"tenantId":"<tenant-uuid>","deviceCode":"IPC-01","pin":"1234"}' \
| jq -r .token)
# PIN condiviso tra operatori → 409 PIN_AMBIGUOUS + lista dei candidati;
# ri-invia con "operatorId" per disambiguare.
2 — Ciclo di vita del lotto: recezione → lavorazione → collaudo
# VERIFY_LOT (ruolo MAGAZZINIERE) — FSM IN_ATTESA → VERIFICATO
curl -X POST http://localhost:8291/api/v1/actions/VERIFY_LOT \
-H "Authorization: Bearer $TOKEN" -H 'content-type: application/json' \
-H "X-Idempotency-Key: $(uuidgen)" \
-d '{"payload":{"lot_id":"LOT-2026-091","peso_dichiarato":100.0,
"peso_misurato":100.3}}'
# ACCEPT_LOT — la formula `weight_delta_pct` gira, il constraint `peso_coerente`
# fallisce chiuso oltre ±0.5%: rifiuto, zero commit.
curl -X POST http://localhost:8291/api/v1/actions/ACCEPT_LOT \
-H "Authorization: Bearer $TOKEN" -H "X-Idempotency-Key: $(uuidgen)" \
-d '{"payload":{"lot_id":"LOT-2026-091","peso_dichiarato":100.0,
"peso_misurato":100.3}}'
# Collaudo (ruolo QUALITA) — START_MEASURE poi QC_PASS/QC_FAIL
curl -X POST http://localhost:8291/api/v1/actions/QC_PASS \
-H "Authorization: Bearer $TOKEN" -H "X-Idempotency-Key: $(uuidgen)" \
-d '{"payload":{"piece_id":"PZ-001","misura":0.018}}'
# misura > 0.02 → CONSTRAINT_VIOLATED (tolleranza_collaudo).
# Un trigger che il tuo ruolo non possiede → 403. Trigger fuori stato → 409.
// Lo stesso flusso in Node — una funzione async, zero dipendenze
async function closeOperation(base, token, order) {
const r = await fetch(`${base}/api/v1/actions/CLOSE_OPERATION`, {
method: 'POST',
headers: { 'content-type': 'application/json',
authorization: `Bearer ${token}`,
'x-idempotency-key': crypto.randomUUID() },
body: JSON.stringify({ payload: {
order_id: order, qta: 500, qta_ordinata: 500 } })
});
if (r.status === 401) throw new Error('sessione scaduta — rifare login');
return r.json();
}
// qta > qta_ordinata → la regola `qta_entro_ordine` rifiuta: non puoi mai
// committare più dell'ordinato. La formula `tempo_std` gira per la riga di audit.
3 — Rilettura tramite data-link
# Le query di lettura sono dichiarate nel manifest e indirizzate come trigger
curl -X POST http://localhost:8291/api/v1/actions/LIST_LOTTI \
-H "Authorization: Bearer $TOKEN" -H "X-Idempotency-Key: $(uuidgen)" \
-d '{"payload":{"lot_id":"LOT-2026-091"}}' | jq '.rows'
4 — Lato cloud: sessione portale → superficie tenant
# Login portale (cloud) → sessione Bearer
PS=$(curl -s https://cp.axiom-trace.eu/api/v1/portal/login \
-H 'content-type: application/json' \
-d '{"email":"qa@customer.com","password":"…","tenant_id":"<uuid>"}' \
| jq -r .token)
# Uno snapshot: contratto, heartbeat della flotta, metering mensile
curl -s https://cp.axiom-trace.eu/api/v1/tenant/usage \
-H "Authorization: Bearer $PS" | jq '{plan: .subscription.plan, edges: .edges|length}'
# Ri-verifica la catena di audit hash-chained del tenant — integrità self-service
curl -s https://cp.axiom-trace.eu/api/v1/tenant/audit/verify \
-H "Authorization: Bearer $PS" | jq '{ok, checked, head}'
# Export SIEM — NDJSON paginato a cursore, gli stessi fatti che la catena verifica
curl -s "https://cp.axiom-trace.eu/api/v1/tenant/audit?limit=1000" \
-H "Authorization: Bearer $PS" | head -1 | jq '{seq, action, integrity}'
# Equivalente in Python — export audit incrementale per un collector SIEM
import httpx
S = httpx.Client(base_url="https://cp.axiom-trace.eu",
headers={"authorization": f"Bearer {token}"})
since = 0
while True:
rows = S.get("/api/v1/tenant/audit",
params={"since_seq": since, "limit": 1000}).json()
events = rows["events"] if isinstance(rows, dict) else rows
if not events:
break
since = int(events[-1]["seq"]) # seq è una stringa 64-bit — converti
ship_to_siem(events)
5 — Ingest (canale edge → cloud)
# Il drain outbound del demone edge — idempotente su id evento, ≤1000/batch
curl -X POST https://cp.axiom-trace.eu/api/v1/sync/ingest \
-H "Authorization: Bearer $EDGE_API_KEY" \
-H "x-edge-node: edge-01" \
-H "x-edge-signature: ed25519.<b64-of-raw-body>" \
-H 'content-type: application/json' \
-d '{"events":[{"id":"<uuid>","aggregate_type":"BIZ_LOTTI",
"aggregate_id":"<uuid>","event_type":"INSERT_BIZ_LOTTI",
"payload":{"lotto":"LOT-2026-091","peso_misurato":100.3},
"created_at":"2026-09-26T14:01:03Z"}]}'
# → 201 {processed_count, duplicate_count, latest_manifest_version}
# reinviare lo stesso batch non è un errore, è il percorso di retry progettato.
Dove proseguire
- API Reference — ogni endpoint, ogni confine di credenziale
- Il Contratto — le regole sotto cui vivono queste chiamate
- Specifica Manifest — estendi tu stesso il contratto