---
title: Calibration
description: The Calibration API teaches an environment your real costs.
---

# Calibration

The Calibration API teaches an environment your real costs: submit observations and auto-calibrate its prediction interval, learning curve, and machine policy from your actuals.

> **Auto-generated** from the public OpenAPI spec — this page never
> drifts from the running API. Base URL `https://api.arcnm.io`. Authenticate with
> the `X-API-Key` header (see [Authentication](../authentication.md)).

## Recalibrate an environment's prediction interval from recent samples.

`POST /api/v1/parts/calibration/conformal-recalibrate`

Recalibrate the prediction interval applied to priced quotes from a fresh set of (predicted, actual) samples. Once updated, subsequent quotes use the new interval. A monthly cadence is the recommended default; submit fresh samples whenever your recent outcomes have shifted.

**Request body** (`application/json`)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `env_id` | string | no | Target environment; required when scope is 'environment'. |
| `samples` | object[] | no | Up to 20,000 (predicted, actual) samples; both values must be greater than 0. |
| `scope` | `platform` \| `environment` | yes | Scope to recalibrate; tenant tokens may use 'environment' only. |
| `target_alpha` | number | no | Target miss rate for the prediction interval (0.10 → a 90% interval). |
| `target_metric` | `cycle_time_s` \| `setup_time_s` \| `unit_cost` | no | Metric whose prediction interval is recalibrated. |

**Request**

<CodeTabs>

```bash title="cURL"
curl -X POST https://api.arcnm.io/api/v1/parts/calibration/conformal-recalibrate \
  -H "X-API-Key: $ARCNM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "scope": "platform"
  }'
```

```python title="Python"
import requests

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/calibration/conformal-recalibrate",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "scope": "platform"
    },
)
resp.raise_for_status()
print(resp.json())
```

```typescript title="TypeScript"
const resp = await fetch("https://api.arcnm.io/api/v1/parts/calibration/conformal-recalibrate", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "scope": "platform"
  }),
})
const data = await resp.json()
```

</CodeTabs>

**Responses**

| Status | Description |
| --- | --- |
| `200` | Successful Response |
| `422` | Validation Error |

**Errors**

Standard error responses — see the [Errors catalog](../errors.md) for the full envelope, `request_id`, and retry-safety table.

| Status | Code | When |
| --- | --- | --- |
| `401` | `invalid_api_key` | Missing, malformed, or revoked API key. |
| `403` | `insufficient_scope` | The key is valid but lacks a scope this endpoint requires. |
| `409` | `conflict` | A conflicting change, or an `Idempotency-Key` reused with a different body. |
| `429` | `rate_limited` | Per-key or per-org rate limit exceeded — back off with jitter and retry. |


**Response body** `200`

| Field | Type | Description |
| --- | --- | --- |
| `a` | number | Fitted first-unit cost coefficient of the curve. |
| `alpha` | number | Target miss rate of the prediction interval (e.g. 0.10 → 90%). |
| `b` | number | Fitted log-log slope exponent of the learning curve. |
| `env_id` | string | Identifier of the calibrated environment. |
| `fit` | object | Structured object with the fitted parameters and fit diagnostics. |
| `fitted_accuracy` | number | Accuracy (0–1) of the fitted policy on the training rows. |
| `fitted_policy` | object | Structured object describing the fitted selection policy. |
| `grid_size` | integer | Number of policy candidates evaluated during the fit. |
| `holdout_accuracy` | number | Accuracy (0–1) of the fitted policy on held-out rows. |
| `holdout_coverage` | number | Fraction (0–1) of held-out actuals falling inside the interval. |
| `holdout_mape` | number | Mean absolute percentage error on the held-out rows. |
| `id` | string | Identifier of the resulting record, when applicable. |
| `ingested` | integer | Number of observations persisted by an ingest call. |
| `learning_rate` | number | Learning rate (0–1): cost retained each time output doubles. |
| `matched` | integer | Number of supplied rows matched to an existing quote. |
| `message` | string | Human-readable note about the run, when present. |
| `n_calibration` | integer | Number of samples used to fit the conformal interval. |
| `n_holdout` | integer | Number of rows held out to size the prediction interval. |
| `n_iterations` | integer | Iterations the midpoint solver ran before converging. |
| `n_lots` | integer | Number of production lots used in the curve fit. |
| `n_train` | integer | Number of rows used to fit the calibration. |
| `observed_coverage` | number | Empirical coverage (0–1) of the fitted interval on its samples. |
| `part_revision_id` | string | Identifier of the part revision that was fit. |
| `policy_history_id` | string | Identifier of the newly written selection-policy row. |
| `q_alpha` | number | Fitted conformal quantile that sets the interval half-width. |
| `r_squared` | number | Coefficient of determination (0–1) of the curve fit. |
| `residual_sigma_log` | number | Standard deviation of the fit residuals in log space. |
| `run_id` | string | Identifier of the calibration run, when one was created. |
| `samples` | integer | Number of samples considered by the run. |
| `samples_applied` | integer | Number of samples actually applied to the fit. |
| `scope` | string | Scope the run applied to: 'platform' or 'environment'. |
| `seed_accuracy` | number | Accuracy (0–1) of the seed policy before calibration. |
| `status` | string | Outcome status of the calibration run. |
| `target_metric` | string | Metric the calibration targeted (e.g. 'unit_cost'). |
| `unknown_part_numbers` | string[] | Part numbers that could not be resolved to a known part. |
| `unmatched_part_ids` | string[] | Part revision IDs with no prior quote, so they were skipped. |
| `work_orders_received` | integer | Number of ERP work-order rows received. |
| `work_orders_resolved` | integer | Number of work orders resolved to a known part revision. |

**Example response**

```json
{
  "a": 0,
  "alpha": 0,
  "b": 0,
  "env_id": "string",
  "fit": {},
  "fitted_accuracy": 0,
  "fitted_policy": {},
  "grid_size": 0,
  "holdout_accuracy": 0,
  "holdout_coverage": 0.9,
  "holdout_mape": 0.05,
  "id": "string",
  "ingested": 0,
  "learning_rate": 0,
  "matched": 0,
  "message": "string",
  "n_calibration": 0,
  "n_holdout": 0,
  "n_iterations": 0,
  "n_lots": 0,
  "n_train": 0,
  "observed_coverage": 0.9,
  "part_revision_id": "string",
  "policy_history_id": "string",
  "q_alpha": 0,
  "r_squared": 0,
  "residual_sigma_log": 0,
  "run_id": "string",
  "samples": 0,
  "samples_applied": 0,
  "scope": "string",
  "seed_accuracy": 0,
  "status": "string",
  "target_metric": "string",
  "unknown_part_numbers": [
    "string"
  ],
  "unmatched_part_ids": [
    "string"
  ],
  "work_orders_received": 0,
  "work_orders_resolved": 0
}
```

## One-click environment calibration from (part_revision_id, actual_unit_cost) rows.

`POST /api/v1/parts/calibration/environments/{env_id}/auto-calibrate`

The headline customer-facing endpoint — turn a list of ERP actual unit costs into a calibrated environment in one call. The server re-quotes every part with the environment's current pricing so the result reflects your true cost delta. Parts with no prior successful quote are returned in ``unmatched_part_ids`` so you can quote them and retry. Safe for AI-agent use over MCP and idempotent: the same set of actuals yields the same result.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `env_id` | path | string | yes | Identifier of the env. |

**Request body** (`application/json`)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `actuals` | AutoCalibrateActualRow[] | yes | Up to 20,000 (part_revision_id, actual_unit_cost) rows. Designed for ERP exports: an AI agent or a CSV uploader can stream a tenant's history in one call. |
| `holdout_pct` | number | no | Fraction of rows held out to size the prediction interval. |
| `target_alpha` | number | no | Target miss rate for the prediction interval (default 0.10 → a 90% interval). |

**Request**

<CodeTabs>

```bash title="cURL"
curl -X POST https://api.arcnm.io/api/v1/parts/calibration/environments/{env_id}/auto-calibrate \
  -H "X-API-Key: $ARCNM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "actuals": [
      {
        "actual_unit_cost": 0,
        "annual_volume": 500,
        "bin": "string",
        "lot_size": 50,
        "part_revision_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "tooling_lifetime_units": 0
      }
    ]
  }'
```

```python title="Python"
import requests

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/calibration/environments/{env_id}/auto-calibrate",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "actuals": [
            {
                "actual_unit_cost": 0,
                "annual_volume": 500,
                "bin": "string",
                "lot_size": 50,
                "part_revision_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
                "tooling_lifetime_units": 0
            }
        ]
    },
)
resp.raise_for_status()
print(resp.json())
```

```typescript title="TypeScript"
const resp = await fetch("https://api.arcnm.io/api/v1/parts/calibration/environments/{env_id}/auto-calibrate", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "actuals": [
      {
        "actual_unit_cost": 0,
        "annual_volume": 500,
        "bin": "string",
        "lot_size": 50,
        "part_revision_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "tooling_lifetime_units": 0
      }
    ]
  }),
})
const data = await resp.json()
```

</CodeTabs>

**Responses**

| Status | Description |
| --- | --- |
| `200` | Successful Response |
| `422` | Validation Error |

**Errors**

Standard error responses — see the [Errors catalog](../errors.md) for the full envelope, `request_id`, and retry-safety table.

| Status | Code | When |
| --- | --- | --- |
| `401` | `invalid_api_key` | Missing, malformed, or revoked API key. |
| `403` | `insufficient_scope` | The key is valid but lacks a scope this endpoint requires. |
| `404` | `not_found` | A referenced resource doesn't exist or isn't visible to your organisation. |
| `409` | `conflict` | A conflicting change, or an `Idempotency-Key` reused with a different body. |
| `429` | `rate_limited` | Per-key or per-org rate limit exceeded — back off with jitter and retry. |


**Response body** `200`

| Field | Type | Description |
| --- | --- | --- |
| `a` | number | Fitted first-unit cost coefficient of the curve. |
| `alpha` | number | Target miss rate of the prediction interval (e.g. 0.10 → 90%). |
| `b` | number | Fitted log-log slope exponent of the learning curve. |
| `env_id` | string | Identifier of the calibrated environment. |
| `fit` | object | Structured object with the fitted parameters and fit diagnostics. |
| `fitted_accuracy` | number | Accuracy (0–1) of the fitted policy on the training rows. |
| `fitted_policy` | object | Structured object describing the fitted selection policy. |
| `grid_size` | integer | Number of policy candidates evaluated during the fit. |
| `holdout_accuracy` | number | Accuracy (0–1) of the fitted policy on held-out rows. |
| `holdout_coverage` | number | Fraction (0–1) of held-out actuals falling inside the interval. |
| `holdout_mape` | number | Mean absolute percentage error on the held-out rows. |
| `id` | string | Identifier of the resulting record, when applicable. |
| `ingested` | integer | Number of observations persisted by an ingest call. |
| `learning_rate` | number | Learning rate (0–1): cost retained each time output doubles. |
| `matched` | integer | Number of supplied rows matched to an existing quote. |
| `message` | string | Human-readable note about the run, when present. |
| `n_calibration` | integer | Number of samples used to fit the conformal interval. |
| `n_holdout` | integer | Number of rows held out to size the prediction interval. |
| `n_iterations` | integer | Iterations the midpoint solver ran before converging. |
| `n_lots` | integer | Number of production lots used in the curve fit. |
| `n_train` | integer | Number of rows used to fit the calibration. |
| `observed_coverage` | number | Empirical coverage (0–1) of the fitted interval on its samples. |
| `part_revision_id` | string | Identifier of the part revision that was fit. |
| `policy_history_id` | string | Identifier of the newly written selection-policy row. |
| `q_alpha` | number | Fitted conformal quantile that sets the interval half-width. |
| `r_squared` | number | Coefficient of determination (0–1) of the curve fit. |
| `residual_sigma_log` | number | Standard deviation of the fit residuals in log space. |
| `run_id` | string | Identifier of the calibration run, when one was created. |
| `samples` | integer | Number of samples considered by the run. |
| `samples_applied` | integer | Number of samples actually applied to the fit. |
| `scope` | string | Scope the run applied to: 'platform' or 'environment'. |
| `seed_accuracy` | number | Accuracy (0–1) of the seed policy before calibration. |
| `status` | string | Outcome status of the calibration run. |
| `target_metric` | string | Metric the calibration targeted (e.g. 'unit_cost'). |
| `unknown_part_numbers` | string[] | Part numbers that could not be resolved to a known part. |
| `unmatched_part_ids` | string[] | Part revision IDs with no prior quote, so they were skipped. |
| `work_orders_received` | integer | Number of ERP work-order rows received. |
| `work_orders_resolved` | integer | Number of work orders resolved to a known part revision. |

**Example response**

```json
{
  "a": 0,
  "alpha": 0,
  "b": 0,
  "env_id": "string",
  "fit": {},
  "fitted_accuracy": 0,
  "fitted_policy": {},
  "grid_size": 0,
  "holdout_accuracy": 0,
  "holdout_coverage": 0.9,
  "holdout_mape": 0.05,
  "id": "string",
  "ingested": 0,
  "learning_rate": 0,
  "matched": 0,
  "message": "string",
  "n_calibration": 0,
  "n_holdout": 0,
  "n_iterations": 0,
  "n_lots": 0,
  "n_train": 0,
  "observed_coverage": 0.9,
  "part_revision_id": "string",
  "policy_history_id": "string",
  "q_alpha": 0,
  "r_squared": 0,
  "residual_sigma_log": 0,
  "run_id": "string",
  "samples": 0,
  "samples_applied": 0,
  "scope": "string",
  "seed_accuracy": 0,
  "status": "string",
  "target_metric": "string",
  "unknown_part_numbers": [
    "string"
  ],
  "unmatched_part_ids": [
    "string"
  ],
  "work_orders_received": 0,
  "work_orders_resolved": 0
}
```

## Calibrate an env from raw ERP work-order rows.

`POST /api/v1/parts/calibration/environments/{env_id}/auto-calibrate-from-erp`

ERP-native variant of ``auto-calibrate``: accepts the raw columns most ERPs export (part_number, work_order_id, quantity, total_cost) and handles part-number resolution + unit-cost derivation server-side. Idempotent on work_order_id.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `env_id` | path | string | yes | Identifier of the env. |

**Request body** (`application/json`)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `holdout_pct` | number | no | Fraction of rows held out to size the prediction interval. |
| `target_alpha` | number | no | Target miss rate for the prediction interval (0.10 → a 90% interval). |
| `work_orders` | ErpWorkOrderPayload[] | yes | Up to 20 000 raw ERP work-order lines. Designed for the AI-agent ERP-import use case: pull tenant's last 12 months of WIP_DISCRETE_JOBS rows, POST them once, and the service resolves part numbers, decomposes setup vs variable cost from the lot-size diversity, and returns a calibrated env. |

**Request**

<CodeTabs>

```bash title="cURL"
curl -X POST https://api.arcnm.io/api/v1/parts/calibration/environments/{env_id}/auto-calibrate-from-erp \
  -H "X-API-Key: $ARCNM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "work_orders": [
      {
        "annual_forecast": 0,
        "part_number": "BRACKET-001",
        "quantity": 0,
        "total_cost": 642,
        "work_order_id": "string"
      }
    ]
  }'
```

```python title="Python"
import requests

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/calibration/environments/{env_id}/auto-calibrate-from-erp",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "work_orders": [
            {
                "annual_forecast": 0,
                "part_number": "BRACKET-001",
                "quantity": 0,
                "total_cost": 642,
                "work_order_id": "string"
            }
        ]
    },
)
resp.raise_for_status()
print(resp.json())
```

```typescript title="TypeScript"
const resp = await fetch("https://api.arcnm.io/api/v1/parts/calibration/environments/{env_id}/auto-calibrate-from-erp", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "work_orders": [
      {
        "annual_forecast": 0,
        "part_number": "BRACKET-001",
        "quantity": 0,
        "total_cost": 642,
        "work_order_id": "string"
      }
    ]
  }),
})
const data = await resp.json()
```

</CodeTabs>

**Responses**

| Status | Description |
| --- | --- |
| `200` | Successful Response |
| `422` | Validation Error |

**Errors**

Standard error responses — see the [Errors catalog](../errors.md) for the full envelope, `request_id`, and retry-safety table.

| Status | Code | When |
| --- | --- | --- |
| `401` | `invalid_api_key` | Missing, malformed, or revoked API key. |
| `403` | `insufficient_scope` | The key is valid but lacks a scope this endpoint requires. |
| `404` | `not_found` | A referenced resource doesn't exist or isn't visible to your organisation. |
| `409` | `conflict` | A conflicting change, or an `Idempotency-Key` reused with a different body. |
| `429` | `rate_limited` | Per-key or per-org rate limit exceeded — back off with jitter and retry. |


**Response body** `200`

| Field | Type | Description |
| --- | --- | --- |
| `a` | number | Fitted first-unit cost coefficient of the curve. |
| `alpha` | number | Target miss rate of the prediction interval (e.g. 0.10 → 90%). |
| `b` | number | Fitted log-log slope exponent of the learning curve. |
| `env_id` | string | Identifier of the calibrated environment. |
| `fit` | object | Structured object with the fitted parameters and fit diagnostics. |
| `fitted_accuracy` | number | Accuracy (0–1) of the fitted policy on the training rows. |
| `fitted_policy` | object | Structured object describing the fitted selection policy. |
| `grid_size` | integer | Number of policy candidates evaluated during the fit. |
| `holdout_accuracy` | number | Accuracy (0–1) of the fitted policy on held-out rows. |
| `holdout_coverage` | number | Fraction (0–1) of held-out actuals falling inside the interval. |
| `holdout_mape` | number | Mean absolute percentage error on the held-out rows. |
| `id` | string | Identifier of the resulting record, when applicable. |
| `ingested` | integer | Number of observations persisted by an ingest call. |
| `learning_rate` | number | Learning rate (0–1): cost retained each time output doubles. |
| `matched` | integer | Number of supplied rows matched to an existing quote. |
| `message` | string | Human-readable note about the run, when present. |
| `n_calibration` | integer | Number of samples used to fit the conformal interval. |
| `n_holdout` | integer | Number of rows held out to size the prediction interval. |
| `n_iterations` | integer | Iterations the midpoint solver ran before converging. |
| `n_lots` | integer | Number of production lots used in the curve fit. |
| `n_train` | integer | Number of rows used to fit the calibration. |
| `observed_coverage` | number | Empirical coverage (0–1) of the fitted interval on its samples. |
| `part_revision_id` | string | Identifier of the part revision that was fit. |
| `policy_history_id` | string | Identifier of the newly written selection-policy row. |
| `q_alpha` | number | Fitted conformal quantile that sets the interval half-width. |
| `r_squared` | number | Coefficient of determination (0–1) of the curve fit. |
| `residual_sigma_log` | number | Standard deviation of the fit residuals in log space. |
| `run_id` | string | Identifier of the calibration run, when one was created. |
| `samples` | integer | Number of samples considered by the run. |
| `samples_applied` | integer | Number of samples actually applied to the fit. |
| `scope` | string | Scope the run applied to: 'platform' or 'environment'. |
| `seed_accuracy` | number | Accuracy (0–1) of the seed policy before calibration. |
| `status` | string | Outcome status of the calibration run. |
| `target_metric` | string | Metric the calibration targeted (e.g. 'unit_cost'). |
| `unknown_part_numbers` | string[] | Part numbers that could not be resolved to a known part. |
| `unmatched_part_ids` | string[] | Part revision IDs with no prior quote, so they were skipped. |
| `work_orders_received` | integer | Number of ERP work-order rows received. |
| `work_orders_resolved` | integer | Number of work orders resolved to a known part revision. |

**Example response**

```json
{
  "a": 0,
  "alpha": 0,
  "b": 0,
  "env_id": "string",
  "fit": {},
  "fitted_accuracy": 0,
  "fitted_policy": {},
  "grid_size": 0,
  "holdout_accuracy": 0,
  "holdout_coverage": 0.9,
  "holdout_mape": 0.05,
  "id": "string",
  "ingested": 0,
  "learning_rate": 0,
  "matched": 0,
  "message": "string",
  "n_calibration": 0,
  "n_holdout": 0,
  "n_iterations": 0,
  "n_lots": 0,
  "n_train": 0,
  "observed_coverage": 0.9,
  "part_revision_id": "string",
  "policy_history_id": "string",
  "q_alpha": 0,
  "r_squared": 0,
  "residual_sigma_log": 0,
  "run_id": "string",
  "samples": 0,
  "samples_applied": 0,
  "scope": "string",
  "seed_accuracy": 0,
  "status": "string",
  "target_metric": "string",
  "unknown_part_numbers": [
    "string"
  ],
  "unmatched_part_ids": [
    "string"
  ],
  "work_orders_received": 0,
  "work_orders_resolved": 0
}
```

## Recalibrate an environment from its accumulated observations.

`POST /api/v1/parts/calibration/environments/{env_id}/finalize`

Recalibrate this environment for the selected target metric using every observation submitted for it so far, then activate the result. Use after submitting observations. To start from raw ERP actuals without submitting observations first, use the one-click auto-calibrate endpoint instead.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `env_id` | path | string | yes | Identifier of the env. |

**Request body** (`application/json`)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `notes` | string | no | Optional free-text note recorded with the run. |
| `target_alpha` | number | no | Target miss rate for the prediction interval (0.10 → a 90% interval). |
| `target_metric` | `cycle_time_s` \| `setup_time_s` \| `unit_cost` \| `machine_choice` | no | Metric to calibrate the environment for. |

**Request**

<CodeTabs>

```bash title="cURL"
curl -X POST https://api.arcnm.io/api/v1/parts/calibration/environments/{env_id}/finalize \
  -H "X-API-Key: $ARCNM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "notes": "string",
    "target_alpha": 0.1,
    "target_metric": "cycle_time_s"
  }'
```

```python title="Python"
import requests

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/calibration/environments/{env_id}/finalize",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "notes": "string",
        "target_alpha": 0.1,
        "target_metric": "cycle_time_s"
    },
)
resp.raise_for_status()
print(resp.json())
```

```typescript title="TypeScript"
const resp = await fetch("https://api.arcnm.io/api/v1/parts/calibration/environments/{env_id}/finalize", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "notes": "string",
    "target_alpha": 0.1,
    "target_metric": "cycle_time_s"
  }),
})
const data = await resp.json()
```

</CodeTabs>

**Responses**

| Status | Description |
| --- | --- |
| `200` | Successful Response |
| `422` | Validation Error |

**Errors**

Standard error responses — see the [Errors catalog](../errors.md) for the full envelope, `request_id`, and retry-safety table.

| Status | Code | When |
| --- | --- | --- |
| `401` | `invalid_api_key` | Missing, malformed, or revoked API key. |
| `403` | `insufficient_scope` | The key is valid but lacks a scope this endpoint requires. |
| `404` | `not_found` | A referenced resource doesn't exist or isn't visible to your organisation. |
| `409` | `conflict` | A conflicting change, or an `Idempotency-Key` reused with a different body. |
| `429` | `rate_limited` | Per-key or per-org rate limit exceeded — back off with jitter and retry. |


**Response body** `200`

| Field | Type | Description |
| --- | --- | --- |
| `a` | number | Fitted first-unit cost coefficient of the curve. |
| `alpha` | number | Target miss rate of the prediction interval (e.g. 0.10 → 90%). |
| `b` | number | Fitted log-log slope exponent of the learning curve. |
| `env_id` | string | Identifier of the calibrated environment. |
| `fit` | object | Structured object with the fitted parameters and fit diagnostics. |
| `fitted_accuracy` | number | Accuracy (0–1) of the fitted policy on the training rows. |
| `fitted_policy` | object | Structured object describing the fitted selection policy. |
| `grid_size` | integer | Number of policy candidates evaluated during the fit. |
| `holdout_accuracy` | number | Accuracy (0–1) of the fitted policy on held-out rows. |
| `holdout_coverage` | number | Fraction (0–1) of held-out actuals falling inside the interval. |
| `holdout_mape` | number | Mean absolute percentage error on the held-out rows. |
| `id` | string | Identifier of the resulting record, when applicable. |
| `ingested` | integer | Number of observations persisted by an ingest call. |
| `learning_rate` | number | Learning rate (0–1): cost retained each time output doubles. |
| `matched` | integer | Number of supplied rows matched to an existing quote. |
| `message` | string | Human-readable note about the run, when present. |
| `n_calibration` | integer | Number of samples used to fit the conformal interval. |
| `n_holdout` | integer | Number of rows held out to size the prediction interval. |
| `n_iterations` | integer | Iterations the midpoint solver ran before converging. |
| `n_lots` | integer | Number of production lots used in the curve fit. |
| `n_train` | integer | Number of rows used to fit the calibration. |
| `observed_coverage` | number | Empirical coverage (0–1) of the fitted interval on its samples. |
| `part_revision_id` | string | Identifier of the part revision that was fit. |
| `policy_history_id` | string | Identifier of the newly written selection-policy row. |
| `q_alpha` | number | Fitted conformal quantile that sets the interval half-width. |
| `r_squared` | number | Coefficient of determination (0–1) of the curve fit. |
| `residual_sigma_log` | number | Standard deviation of the fit residuals in log space. |
| `run_id` | string | Identifier of the calibration run, when one was created. |
| `samples` | integer | Number of samples considered by the run. |
| `samples_applied` | integer | Number of samples actually applied to the fit. |
| `scope` | string | Scope the run applied to: 'platform' or 'environment'. |
| `seed_accuracy` | number | Accuracy (0–1) of the seed policy before calibration. |
| `status` | string | Outcome status of the calibration run. |
| `target_metric` | string | Metric the calibration targeted (e.g. 'unit_cost'). |
| `unknown_part_numbers` | string[] | Part numbers that could not be resolved to a known part. |
| `unmatched_part_ids` | string[] | Part revision IDs with no prior quote, so they were skipped. |
| `work_orders_received` | integer | Number of ERP work-order rows received. |
| `work_orders_resolved` | integer | Number of work orders resolved to a known part revision. |

**Example response**

```json
{
  "a": 0,
  "alpha": 0,
  "b": 0,
  "env_id": "string",
  "fit": {},
  "fitted_accuracy": 0,
  "fitted_policy": {},
  "grid_size": 0,
  "holdout_accuracy": 0,
  "holdout_coverage": 0.9,
  "holdout_mape": 0.05,
  "id": "string",
  "ingested": 0,
  "learning_rate": 0,
  "matched": 0,
  "message": "string",
  "n_calibration": 0,
  "n_holdout": 0,
  "n_iterations": 0,
  "n_lots": 0,
  "n_train": 0,
  "observed_coverage": 0.9,
  "part_revision_id": "string",
  "policy_history_id": "string",
  "q_alpha": 0,
  "r_squared": 0,
  "residual_sigma_log": 0,
  "run_id": "string",
  "samples": 0,
  "samples_applied": 0,
  "scope": "string",
  "seed_accuracy": 0,
  "status": "string",
  "target_metric": "string",
  "unknown_part_numbers": [
    "string"
  ],
  "unmatched_part_ids": [
    "string"
  ],
  "work_orders_received": 0,
  "work_orders_resolved": 0
}
```

## Calibrate cost-down-with-volume from lot-progression actuals.

`POST /api/v1/parts/calibration/environments/{env_id}/learning-curve-fit`

Calibrate how this environment's per-unit cost falls as cumulative production grows, using a sequence of production-lot actuals for one part. Choose the cumulative model (the safer default, observed directly) or the per-unit model. Submit at least three lots.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `env_id` | path | string | yes | Identifier of the env. |

**Request body** (`application/json`)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `lots` | LearningCurveLotPayload[] | yes | Sequence of production-lot actuals to fit; at least three. |
| `model` | `crawford_unit` \| `wright_cumulative` | no | Learning-curve model to fit (per-unit or cumulative). |
| `part_revision_id` | string | yes | Identifier of the part revision the lots belong to. |

**Request**

<CodeTabs>

```bash title="cURL"
curl -X POST https://api.arcnm.io/api/v1/parts/calibration/environments/{env_id}/learning-curve-fit \
  -H "X-API-Key: $ARCNM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "part_revision_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "lots": [
      {
        "lot_index": 0,
        "lot_size": 50,
        "lot_total_cost": 0
      }
    ]
  }'
```

```python title="Python"
import requests

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/calibration/environments/{env_id}/learning-curve-fit",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "part_revision_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "lots": [
            {
                "lot_index": 0,
                "lot_size": 50,
                "lot_total_cost": 0
            }
        ]
    },
)
resp.raise_for_status()
print(resp.json())
```

```typescript title="TypeScript"
const resp = await fetch("https://api.arcnm.io/api/v1/parts/calibration/environments/{env_id}/learning-curve-fit", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "part_revision_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "lots": [
      {
        "lot_index": 0,
        "lot_size": 50,
        "lot_total_cost": 0
      }
    ]
  }),
})
const data = await resp.json()
```

</CodeTabs>

**Responses**

| Status | Description |
| --- | --- |
| `200` | Successful Response |
| `422` | Validation Error |

**Errors**

Standard error responses — see the [Errors catalog](../errors.md) for the full envelope, `request_id`, and retry-safety table.

| Status | Code | When |
| --- | --- | --- |
| `401` | `invalid_api_key` | Missing, malformed, or revoked API key. |
| `403` | `insufficient_scope` | The key is valid but lacks a scope this endpoint requires. |
| `404` | `not_found` | A referenced resource doesn't exist or isn't visible to your organisation. |
| `409` | `conflict` | A conflicting change, or an `Idempotency-Key` reused with a different body. |
| `429` | `rate_limited` | Per-key or per-org rate limit exceeded — back off with jitter and retry. |


**Response body** `200`

| Field | Type | Description |
| --- | --- | --- |
| `a` | number | Fitted first-unit cost coefficient of the curve. |
| `alpha` | number | Target miss rate of the prediction interval (e.g. 0.10 → 90%). |
| `b` | number | Fitted log-log slope exponent of the learning curve. |
| `env_id` | string | Identifier of the calibrated environment. |
| `fit` | object | Structured object with the fitted parameters and fit diagnostics. |
| `fitted_accuracy` | number | Accuracy (0–1) of the fitted policy on the training rows. |
| `fitted_policy` | object | Structured object describing the fitted selection policy. |
| `grid_size` | integer | Number of policy candidates evaluated during the fit. |
| `holdout_accuracy` | number | Accuracy (0–1) of the fitted policy on held-out rows. |
| `holdout_coverage` | number | Fraction (0–1) of held-out actuals falling inside the interval. |
| `holdout_mape` | number | Mean absolute percentage error on the held-out rows. |
| `id` | string | Identifier of the resulting record, when applicable. |
| `ingested` | integer | Number of observations persisted by an ingest call. |
| `learning_rate` | number | Learning rate (0–1): cost retained each time output doubles. |
| `matched` | integer | Number of supplied rows matched to an existing quote. |
| `message` | string | Human-readable note about the run, when present. |
| `n_calibration` | integer | Number of samples used to fit the conformal interval. |
| `n_holdout` | integer | Number of rows held out to size the prediction interval. |
| `n_iterations` | integer | Iterations the midpoint solver ran before converging. |
| `n_lots` | integer | Number of production lots used in the curve fit. |
| `n_train` | integer | Number of rows used to fit the calibration. |
| `observed_coverage` | number | Empirical coverage (0–1) of the fitted interval on its samples. |
| `part_revision_id` | string | Identifier of the part revision that was fit. |
| `policy_history_id` | string | Identifier of the newly written selection-policy row. |
| `q_alpha` | number | Fitted conformal quantile that sets the interval half-width. |
| `r_squared` | number | Coefficient of determination (0–1) of the curve fit. |
| `residual_sigma_log` | number | Standard deviation of the fit residuals in log space. |
| `run_id` | string | Identifier of the calibration run, when one was created. |
| `samples` | integer | Number of samples considered by the run. |
| `samples_applied` | integer | Number of samples actually applied to the fit. |
| `scope` | string | Scope the run applied to: 'platform' or 'environment'. |
| `seed_accuracy` | number | Accuracy (0–1) of the seed policy before calibration. |
| `status` | string | Outcome status of the calibration run. |
| `target_metric` | string | Metric the calibration targeted (e.g. 'unit_cost'). |
| `unknown_part_numbers` | string[] | Part numbers that could not be resolved to a known part. |
| `unmatched_part_ids` | string[] | Part revision IDs with no prior quote, so they were skipped. |
| `work_orders_received` | integer | Number of ERP work-order rows received. |
| `work_orders_resolved` | integer | Number of work orders resolved to a known part revision. |

**Example response**

```json
{
  "a": 0,
  "alpha": 0,
  "b": 0,
  "env_id": "string",
  "fit": {},
  "fitted_accuracy": 0,
  "fitted_policy": {},
  "grid_size": 0,
  "holdout_accuracy": 0,
  "holdout_coverage": 0.9,
  "holdout_mape": 0.05,
  "id": "string",
  "ingested": 0,
  "learning_rate": 0,
  "matched": 0,
  "message": "string",
  "n_calibration": 0,
  "n_holdout": 0,
  "n_iterations": 0,
  "n_lots": 0,
  "n_train": 0,
  "observed_coverage": 0.9,
  "part_revision_id": "string",
  "policy_history_id": "string",
  "q_alpha": 0,
  "r_squared": 0,
  "residual_sigma_log": 0,
  "run_id": "string",
  "samples": 0,
  "samples_applied": 0,
  "scope": "string",
  "seed_accuracy": 0,
  "status": "string",
  "target_metric": "string",
  "unknown_part_numbers": [
    "string"
  ],
  "unmatched_part_ids": [
    "string"
  ],
  "work_orders_received": 0,
  "work_orders_resolved": 0
}
```

## Calibrate which machine an environment recommends from past choices.

`POST /api/v1/parts/calibration/environments/{env_id}/policy/calibrate`

Calibrate how this environment chooses a machine, using a list of historical 'the shop actually picked machine X' decisions. Once calibrated, the environment's machine recommendations better match your shop's real choices.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `env_id` | path | string | yes | Identifier of the env. |

**Request body** (`application/json`)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `history` | object[] | yes | Past machine-choice records, each with candidates and the chosen_machine_id. |
| `region` | string | no | Region whose seed policy to start from (e.g. DE-BY); null for the default. |

**Request**

<CodeTabs>

```bash title="cURL"
curl -X POST https://api.arcnm.io/api/v1/parts/calibration/environments/{env_id}/policy/calibrate \
  -H "X-API-Key: $ARCNM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "history": [
      {}
    ]
  }'
```

```python title="Python"
import requests

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/calibration/environments/{env_id}/policy/calibrate",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "history": [
            {}
        ]
    },
)
resp.raise_for_status()
print(resp.json())
```

```typescript title="TypeScript"
const resp = await fetch("https://api.arcnm.io/api/v1/parts/calibration/environments/{env_id}/policy/calibrate", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "history": [
      {}
    ]
  }),
})
const data = await resp.json()
```

</CodeTabs>

**Responses**

| Status | Description |
| --- | --- |
| `200` | Successful Response |
| `422` | Validation Error |

**Errors**

Standard error responses — see the [Errors catalog](../errors.md) for the full envelope, `request_id`, and retry-safety table.

| Status | Code | When |
| --- | --- | --- |
| `401` | `invalid_api_key` | Missing, malformed, or revoked API key. |
| `403` | `insufficient_scope` | The key is valid but lacks a scope this endpoint requires. |
| `404` | `not_found` | A referenced resource doesn't exist or isn't visible to your organisation. |
| `409` | `conflict` | A conflicting change, or an `Idempotency-Key` reused with a different body. |
| `429` | `rate_limited` | Per-key or per-org rate limit exceeded — back off with jitter and retry. |


**Response body** `200`

| Field | Type | Description |
| --- | --- | --- |
| `a` | number | Fitted first-unit cost coefficient of the curve. |
| `alpha` | number | Target miss rate of the prediction interval (e.g. 0.10 → 90%). |
| `b` | number | Fitted log-log slope exponent of the learning curve. |
| `env_id` | string | Identifier of the calibrated environment. |
| `fit` | object | Structured object with the fitted parameters and fit diagnostics. |
| `fitted_accuracy` | number | Accuracy (0–1) of the fitted policy on the training rows. |
| `fitted_policy` | object | Structured object describing the fitted selection policy. |
| `grid_size` | integer | Number of policy candidates evaluated during the fit. |
| `holdout_accuracy` | number | Accuracy (0–1) of the fitted policy on held-out rows. |
| `holdout_coverage` | number | Fraction (0–1) of held-out actuals falling inside the interval. |
| `holdout_mape` | number | Mean absolute percentage error on the held-out rows. |
| `id` | string | Identifier of the resulting record, when applicable. |
| `ingested` | integer | Number of observations persisted by an ingest call. |
| `learning_rate` | number | Learning rate (0–1): cost retained each time output doubles. |
| `matched` | integer | Number of supplied rows matched to an existing quote. |
| `message` | string | Human-readable note about the run, when present. |
| `n_calibration` | integer | Number of samples used to fit the conformal interval. |
| `n_holdout` | integer | Number of rows held out to size the prediction interval. |
| `n_iterations` | integer | Iterations the midpoint solver ran before converging. |
| `n_lots` | integer | Number of production lots used in the curve fit. |
| `n_train` | integer | Number of rows used to fit the calibration. |
| `observed_coverage` | number | Empirical coverage (0–1) of the fitted interval on its samples. |
| `part_revision_id` | string | Identifier of the part revision that was fit. |
| `policy_history_id` | string | Identifier of the newly written selection-policy row. |
| `q_alpha` | number | Fitted conformal quantile that sets the interval half-width. |
| `r_squared` | number | Coefficient of determination (0–1) of the curve fit. |
| `residual_sigma_log` | number | Standard deviation of the fit residuals in log space. |
| `run_id` | string | Identifier of the calibration run, when one was created. |
| `samples` | integer | Number of samples considered by the run. |
| `samples_applied` | integer | Number of samples actually applied to the fit. |
| `scope` | string | Scope the run applied to: 'platform' or 'environment'. |
| `seed_accuracy` | number | Accuracy (0–1) of the seed policy before calibration. |
| `status` | string | Outcome status of the calibration run. |
| `target_metric` | string | Metric the calibration targeted (e.g. 'unit_cost'). |
| `unknown_part_numbers` | string[] | Part numbers that could not be resolved to a known part. |
| `unmatched_part_ids` | string[] | Part revision IDs with no prior quote, so they were skipped. |
| `work_orders_received` | integer | Number of ERP work-order rows received. |
| `work_orders_resolved` | integer | Number of work orders resolved to a known part revision. |

**Example response**

```json
{
  "a": 0,
  "alpha": 0,
  "b": 0,
  "env_id": "string",
  "fit": {},
  "fitted_accuracy": 0,
  "fitted_policy": {},
  "grid_size": 0,
  "holdout_accuracy": 0,
  "holdout_coverage": 0.9,
  "holdout_mape": 0.05,
  "id": "string",
  "ingested": 0,
  "learning_rate": 0,
  "matched": 0,
  "message": "string",
  "n_calibration": 0,
  "n_holdout": 0,
  "n_iterations": 0,
  "n_lots": 0,
  "n_train": 0,
  "observed_coverage": 0.9,
  "part_revision_id": "string",
  "policy_history_id": "string",
  "q_alpha": 0,
  "r_squared": 0,
  "residual_sigma_log": 0,
  "run_id": "string",
  "samples": 0,
  "samples_applied": 0,
  "scope": "string",
  "seed_accuracy": 0,
  "status": "string",
  "target_metric": "string",
  "unknown_part_numbers": [
    "string"
  ],
  "unmatched_part_ids": [
    "string"
  ],
  "work_orders_received": 0,
  "work_orders_resolved": 0
}
```

## Calibration health summary for one environment.

`GET /api/v1/parts/calibration/environments/{env_id}/status`

Read view of an environment's calibration health: whether it is calibrated, when it was last calibrated, and how many submitted observations are waiting to be applied. Designed as the AI agent's discovery endpoint — call this first to decide whether to submit fresh observations or recalibrate.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `env_id` | path | string | yes | Identifier of the env. |

**Request**

<CodeTabs>

```bash title="cURL"
curl -X GET https://api.arcnm.io/api/v1/parts/calibration/environments/{env_id}/status \
  -H "X-API-Key: $ARCNM_API_KEY"
```

```python title="Python"
import requests

resp = requests.get(
    "https://api.arcnm.io/api/v1/parts/calibration/environments/{env_id}/status",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
resp.raise_for_status()
print(resp.json())
```

```typescript title="TypeScript"
const resp = await fetch("https://api.arcnm.io/api/v1/parts/calibration/environments/{env_id}/status", {
  method: "GET",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
  },
})
const data = await resp.json()
```

</CodeTabs>

**Responses**

| Status | Description |
| --- | --- |
| `200` | Successful Response |
| `422` | Validation Error |

**Errors**

Standard error responses — see the [Errors catalog](../errors.md) for the full envelope, `request_id`, and retry-safety table.

| Status | Code | When |
| --- | --- | --- |
| `401` | `invalid_api_key` | Missing, malformed, or revoked API key. |
| `403` | `insufficient_scope` | The key is valid but lacks a scope this endpoint requires. |
| `404` | `not_found` | A referenced resource doesn't exist or isn't visible to your organisation. |
| `429` | `rate_limited` | Per-key or per-org rate limit exceeded — back off with jitter and retry. |


**Response body** `200`

| Field | Type | Description |
| --- | --- | --- |
| `active_posterior_count` | integer | Number of active calibrated parameters; 0 means uncalibrated. |
| `conformal` | object[] | Recent prediction-interval calibrations, each a structured object. |
| `drift_alerts` | object[] | Recent drift alerts, each a structured object with signal and severity. |
| `env_id` | string | Identifier of the environment this status describes. |
| `last_fit_at` | string | ISO 8601 timestamp of the last calibration; null if never run. |
| `observations` | object[] | Per-source counts of submitted observations awaiting application. |

**Example response**

```json
{
  "active_posterior_count": 0,
  "conformal": [
    {}
  ],
  "drift_alerts": [
    {}
  ],
  "env_id": "string",
  "last_fit_at": "string",
  "observations": [
    {}
  ]
}
```

## Calibrate an environment from (predicted, actual) pairs.

`POST /api/v1/parts/calibration/environments/{env_id}/teach`

Calibrate an environment from caller-supplied (predicted, actual) rows. Each ``predicted`` value must come from a current quote for the part. If you only have actuals, use the one-click auto-calibrate endpoint, which re-quotes each part server-side.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `env_id` | path | string | yes | Identifier of the env. |

**Request body** (`application/json`)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `holdout_pct` | number | no | Fraction (0.05–0.5) of rows held out to size the prediction interval. |
| `rows` | TeachRow[] | yes | Between 1 and 20,000 (predicted, actual) rows to calibrate from. |
| `target_alpha` | number | no | Target miss rate for the prediction interval (0.10 → a 90% interval). |

**Request**

<CodeTabs>

```bash title="cURL"
curl -X POST https://api.arcnm.io/api/v1/parts/calibration/environments/{env_id}/teach \
  -H "X-API-Key: $ARCNM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "rows": [
      {
        "actual": 0,
        "bin": "string",
        "part_revision_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "predicted": 0,
        "target_metric": "unit_cost"
      }
    ]
  }'
```

```python title="Python"
import requests

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/calibration/environments/{env_id}/teach",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "rows": [
            {
                "actual": 0,
                "bin": "string",
                "part_revision_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
                "predicted": 0,
                "target_metric": "unit_cost"
            }
        ]
    },
)
resp.raise_for_status()
print(resp.json())
```

```typescript title="TypeScript"
const resp = await fetch("https://api.arcnm.io/api/v1/parts/calibration/environments/{env_id}/teach", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "rows": [
      {
        "actual": 0,
        "bin": "string",
        "part_revision_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "predicted": 0,
        "target_metric": "unit_cost"
      }
    ]
  }),
})
const data = await resp.json()
```

</CodeTabs>

**Responses**

| Status | Description |
| --- | --- |
| `200` | Successful Response |
| `422` | Validation Error |

**Errors**

Standard error responses — see the [Errors catalog](../errors.md) for the full envelope, `request_id`, and retry-safety table.

| Status | Code | When |
| --- | --- | --- |
| `401` | `invalid_api_key` | Missing, malformed, or revoked API key. |
| `403` | `insufficient_scope` | The key is valid but lacks a scope this endpoint requires. |
| `404` | `not_found` | A referenced resource doesn't exist or isn't visible to your organisation. |
| `409` | `conflict` | A conflicting change, or an `Idempotency-Key` reused with a different body. |
| `429` | `rate_limited` | Per-key or per-org rate limit exceeded — back off with jitter and retry. |


**Response body** `200`

| Field | Type | Description |
| --- | --- | --- |
| `a` | number | Fitted first-unit cost coefficient of the curve. |
| `alpha` | number | Target miss rate of the prediction interval (e.g. 0.10 → 90%). |
| `b` | number | Fitted log-log slope exponent of the learning curve. |
| `env_id` | string | Identifier of the calibrated environment. |
| `fit` | object | Structured object with the fitted parameters and fit diagnostics. |
| `fitted_accuracy` | number | Accuracy (0–1) of the fitted policy on the training rows. |
| `fitted_policy` | object | Structured object describing the fitted selection policy. |
| `grid_size` | integer | Number of policy candidates evaluated during the fit. |
| `holdout_accuracy` | number | Accuracy (0–1) of the fitted policy on held-out rows. |
| `holdout_coverage` | number | Fraction (0–1) of held-out actuals falling inside the interval. |
| `holdout_mape` | number | Mean absolute percentage error on the held-out rows. |
| `id` | string | Identifier of the resulting record, when applicable. |
| `ingested` | integer | Number of observations persisted by an ingest call. |
| `learning_rate` | number | Learning rate (0–1): cost retained each time output doubles. |
| `matched` | integer | Number of supplied rows matched to an existing quote. |
| `message` | string | Human-readable note about the run, when present. |
| `n_calibration` | integer | Number of samples used to fit the conformal interval. |
| `n_holdout` | integer | Number of rows held out to size the prediction interval. |
| `n_iterations` | integer | Iterations the midpoint solver ran before converging. |
| `n_lots` | integer | Number of production lots used in the curve fit. |
| `n_train` | integer | Number of rows used to fit the calibration. |
| `observed_coverage` | number | Empirical coverage (0–1) of the fitted interval on its samples. |
| `part_revision_id` | string | Identifier of the part revision that was fit. |
| `policy_history_id` | string | Identifier of the newly written selection-policy row. |
| `q_alpha` | number | Fitted conformal quantile that sets the interval half-width. |
| `r_squared` | number | Coefficient of determination (0–1) of the curve fit. |
| `residual_sigma_log` | number | Standard deviation of the fit residuals in log space. |
| `run_id` | string | Identifier of the calibration run, when one was created. |
| `samples` | integer | Number of samples considered by the run. |
| `samples_applied` | integer | Number of samples actually applied to the fit. |
| `scope` | string | Scope the run applied to: 'platform' or 'environment'. |
| `seed_accuracy` | number | Accuracy (0–1) of the seed policy before calibration. |
| `status` | string | Outcome status of the calibration run. |
| `target_metric` | string | Metric the calibration targeted (e.g. 'unit_cost'). |
| `unknown_part_numbers` | string[] | Part numbers that could not be resolved to a known part. |
| `unmatched_part_ids` | string[] | Part revision IDs with no prior quote, so they were skipped. |
| `work_orders_received` | integer | Number of ERP work-order rows received. |
| `work_orders_resolved` | integer | Number of work orders resolved to a known part revision. |

**Example response**

```json
{
  "a": 0,
  "alpha": 0,
  "b": 0,
  "env_id": "string",
  "fit": {},
  "fitted_accuracy": 0,
  "fitted_policy": {},
  "grid_size": 0,
  "holdout_accuracy": 0,
  "holdout_coverage": 0.9,
  "holdout_mape": 0.05,
  "id": "string",
  "ingested": 0,
  "learning_rate": 0,
  "matched": 0,
  "message": "string",
  "n_calibration": 0,
  "n_holdout": 0,
  "n_iterations": 0,
  "n_lots": 0,
  "n_train": 0,
  "observed_coverage": 0.9,
  "part_revision_id": "string",
  "policy_history_id": "string",
  "q_alpha": 0,
  "r_squared": 0,
  "residual_sigma_log": 0,
  "run_id": "string",
  "samples": 0,
  "samples_applied": 0,
  "scope": "string",
  "seed_accuracy": 0,
  "status": "string",
  "target_metric": "string",
  "unknown_part_numbers": [
    "string"
  ],
  "unmatched_part_ids": [
    "string"
  ],
  "work_orders_received": 0,
  "work_orders_resolved": 0
}
```

## Submit calibration observations for an environment.

`POST /api/v1/parts/calibration/outcomes`

Submit a batch of observations (predicted vs. actual outcomes) for an environment so it can be calibrated. Tenant-bound; ``scope='environment'`` only. Safe for AI agent use: idempotent on each observation's natural key and rate-limited by the global tenant policy. Recalibrate the environment afterwards to apply the accumulated observations.

**Request body** (`application/json`)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `env_id` | string | no | Target environment; required when scope is 'environment'. |
| `observations` | object[] | no | Up to 20,000 observations; each carries target_metric, observation_type, predicted, and actual. |
| `oracle` | string | yes | Source of the observations (e.g. operator report, MES, supplier quote). |
| `scope` | `platform` \| `environment` | yes | Scope of the observations; tenant tokens may submit 'environment' only. |

**Request**

<CodeTabs>

```bash title="cURL"
curl -X POST https://api.arcnm.io/api/v1/parts/calibration/outcomes \
  -H "X-API-Key: $ARCNM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "scope": "platform",
    "oracle": "string"
  }'
```

```python title="Python"
import requests

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/calibration/outcomes",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "scope": "platform",
        "oracle": "string"
    },
)
resp.raise_for_status()
print(resp.json())
```

```typescript title="TypeScript"
const resp = await fetch("https://api.arcnm.io/api/v1/parts/calibration/outcomes", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "scope": "platform",
    "oracle": "string"
  }),
})
const data = await resp.json()
```

</CodeTabs>

**Responses**

| Status | Description |
| --- | --- |
| `200` | Successful Response |
| `422` | Validation Error |

**Errors**

Standard error responses — see the [Errors catalog](../errors.md) for the full envelope, `request_id`, and retry-safety table.

| Status | Code | When |
| --- | --- | --- |
| `401` | `invalid_api_key` | Missing, malformed, or revoked API key. |
| `403` | `insufficient_scope` | The key is valid but lacks a scope this endpoint requires. |
| `409` | `conflict` | A conflicting change, or an `Idempotency-Key` reused with a different body. |
| `429` | `rate_limited` | Per-key or per-org rate limit exceeded — back off with jitter and retry. |


**Response body** `200`

| Field | Type | Description |
| --- | --- | --- |
| `a` | number | Fitted first-unit cost coefficient of the curve. |
| `alpha` | number | Target miss rate of the prediction interval (e.g. 0.10 → 90%). |
| `b` | number | Fitted log-log slope exponent of the learning curve. |
| `env_id` | string | Identifier of the calibrated environment. |
| `fit` | object | Structured object with the fitted parameters and fit diagnostics. |
| `fitted_accuracy` | number | Accuracy (0–1) of the fitted policy on the training rows. |
| `fitted_policy` | object | Structured object describing the fitted selection policy. |
| `grid_size` | integer | Number of policy candidates evaluated during the fit. |
| `holdout_accuracy` | number | Accuracy (0–1) of the fitted policy on held-out rows. |
| `holdout_coverage` | number | Fraction (0–1) of held-out actuals falling inside the interval. |
| `holdout_mape` | number | Mean absolute percentage error on the held-out rows. |
| `id` | string | Identifier of the resulting record, when applicable. |
| `ingested` | integer | Number of observations persisted by an ingest call. |
| `learning_rate` | number | Learning rate (0–1): cost retained each time output doubles. |
| `matched` | integer | Number of supplied rows matched to an existing quote. |
| `message` | string | Human-readable note about the run, when present. |
| `n_calibration` | integer | Number of samples used to fit the conformal interval. |
| `n_holdout` | integer | Number of rows held out to size the prediction interval. |
| `n_iterations` | integer | Iterations the midpoint solver ran before converging. |
| `n_lots` | integer | Number of production lots used in the curve fit. |
| `n_train` | integer | Number of rows used to fit the calibration. |
| `observed_coverage` | number | Empirical coverage (0–1) of the fitted interval on its samples. |
| `part_revision_id` | string | Identifier of the part revision that was fit. |
| `policy_history_id` | string | Identifier of the newly written selection-policy row. |
| `q_alpha` | number | Fitted conformal quantile that sets the interval half-width. |
| `r_squared` | number | Coefficient of determination (0–1) of the curve fit. |
| `residual_sigma_log` | number | Standard deviation of the fit residuals in log space. |
| `run_id` | string | Identifier of the calibration run, when one was created. |
| `samples` | integer | Number of samples considered by the run. |
| `samples_applied` | integer | Number of samples actually applied to the fit. |
| `scope` | string | Scope the run applied to: 'platform' or 'environment'. |
| `seed_accuracy` | number | Accuracy (0–1) of the seed policy before calibration. |
| `status` | string | Outcome status of the calibration run. |
| `target_metric` | string | Metric the calibration targeted (e.g. 'unit_cost'). |
| `unknown_part_numbers` | string[] | Part numbers that could not be resolved to a known part. |
| `unmatched_part_ids` | string[] | Part revision IDs with no prior quote, so they were skipped. |
| `work_orders_received` | integer | Number of ERP work-order rows received. |
| `work_orders_resolved` | integer | Number of work orders resolved to a known part revision. |

**Example response**

```json
{
  "a": 0,
  "alpha": 0,
  "b": 0,
  "env_id": "string",
  "fit": {},
  "fitted_accuracy": 0,
  "fitted_policy": {},
  "grid_size": 0,
  "holdout_accuracy": 0,
  "holdout_coverage": 0.9,
  "holdout_mape": 0.05,
  "id": "string",
  "ingested": 0,
  "learning_rate": 0,
  "matched": 0,
  "message": "string",
  "n_calibration": 0,
  "n_holdout": 0,
  "n_iterations": 0,
  "n_lots": 0,
  "n_train": 0,
  "observed_coverage": 0.9,
  "part_revision_id": "string",
  "policy_history_id": "string",
  "q_alpha": 0,
  "r_squared": 0,
  "residual_sigma_log": 0,
  "run_id": "string",
  "samples": 0,
  "samples_applied": 0,
  "scope": "string",
  "seed_accuracy": 0,
  "status": "string",
  "target_metric": "string",
  "unknown_part_numbers": [
    "string"
  ],
  "unmatched_part_ids": [
    "string"
  ],
  "work_orders_received": 0,
  "work_orders_resolved": 0
}
```
