Recipes
Recipe — teach an environment from your actuals
Close the calibration loop over the API. POST your realised costs, recalibrate an environment, and read the tightened prediction interval.
Adaptive Calibration is what turns a generic benchmark into a cortex for your shop. The dashboard drives it interactively; this recipe drives the same thing over the API, so you can wire it into your ERP close or a nightly job.
The loop:
- Collect realised costs — work-order actuals from your ERP / MES.
- POST them to a costing environment.
- ARCNM re-quotes each part, fits the delta, and tightens the interval.
- Every subsequent quote on that environment uses the calibrated fit.
Calibration writes need parts:write; the status read needs
parts:read.
1. The one-call path — actual unit costs
If you already have per-part actual unit costs, POST them to
auto-calibrate. You don't supply a predicted value — the service pairs
each part with its most recent quote in this environment and fits the
difference:
import os, requests
BASE = "https://api.arcnm.io/api/v1"
H = {"X-API-Key": os.environ["ARCNM_API_KEY"]} # scope: parts:write
r = requests.post(
f"{BASE}/parts/calibration/environments/{env_id}/auto-calibrate",
headers=H,
json={"actuals": [
{"part_revision_id": "1f…", "actual_unit_cost": 12.40, "lot_size": 50},
{"part_revision_id": "2a…", "actual_unit_cost": 8.10, "lot_size": 100},
]},
)
r.raise_for_status()
report = r.json()
# { matched, unmatched_part_ids, n_train, n_holdout, holdout_mape, holdout_coverage, … }
Pass lot_size whenever you have it (the work-order quantity) — without
it the fit can't separate one-time setup from per-unit cost. Parts with
no prior quote come back in unmatched_part_ids; quote them once, then
retry.
2. The ERP-native path — raw work orders
Most ERPs export work orders, not unit costs. auto-calibrate-from-erp
takes the raw columns (SAP AUFK/AFKO, Oracle WIP_DISCRETE_JOBS) and
does part-number resolution + unit-cost derivation for you:
r = requests.post(
f"{BASE}/parts/calibration/environments/{env_id}/auto-calibrate-from-erp",
headers=H,
json={"work_orders": [
{"part_number": "BRACKET-001", "work_order_id": "WO-5512",
"quantity": 50, "total_cost": 620.00},
]},
)
work_order_id is the idempotency key — re-POSTing the same work order
is a no-op, so you can stream your last 12 months once and replay safely.
Unknown part numbers come back in unknown_part_numbers.
3. Check calibration health
GET .../environments/{env_id}/status is the safe, read-only endpoint to
call first (and after) — it reports whether the env is calibrated, when
it last ran, how many observations are queued, and any drift alerts:
{
"env_id": "env_2a…",
"active_posterior_count": 36,
"last_fit_at": "2026-05-28T14:00:00Z",
"observations": [{ "oracle": "erp", "target_metric": "unit_cost", "count": 142 }],
"conformal": [{ "target_metric": "unit_cost", "observed_coverage": 0.91 }],
"drift_alerts": []
}
active_posterior_count: 0 means the env is still on platform
benchmarks — submit a batch to calibrate it.
4. Read the tightened interval
Once calibrated, every quote on that environment carries a narrower quote-level interval (see Audit & provenance). Use it to set a margin buffer, or to trigger a re-quote when it's too wide for the customer:
{ "unit_cost": 12.84, "currency": "EUR", "interval": [12.20, 13.50] }
Pick the right entry point
| Endpoint | Use it when |
|---|---|
auto-calibrate |
You have per-part actual unit costs. |
auto-calibrate-from-erp |
You have raw work orders (quantity + total cost). |
teach |
You have explicit (predicted, actual) pairs. |
learning-curve-fit |
You have lot-progression actuals for one part. |
conformal-recalibrate |
You only want to refresh the prediction interval. |
status |
Always — read calibration health before and after a run. |
See also
- Concepts → Adaptive Calibration — the model behind this.
- API → Calibration — every endpoint and payload.
- Recipe → ERP integration — the sync-out side of the same loop.