ARCNM

API reference

Calculations

The Calculations API runs a should-cost calculation on a part and returns the priced result.

The Calculations API runs a should-cost calculation on a part and returns the priced result — quote a stored revision, upload-and-quote a file in one call, then list, fetch, or bulk-manage runs.

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).

List Calculations

GET /api/v1/parts/calculations

List recent calculations for the tenant.

Returns the most recent limit rows ordered by created_at descending with a slim projection — no analytics blob, to keep the list response cheap.

Optional part_id narrows the result to a single part.

Parameters

Name In Type Required Description
limit query integer no Maximum number of results to return.
status_filter query string no Filter by lifecycle status (e.g. queued, running, succeeded, failed, cancelled).
part_id query string no Identifier of the part.

Request

curl -X GET https://api.arcnm.io/api/v1/parts/calculations \
  -H "X-API-Key: $ARCNM_API_KEY"
import requests

resp = requests.get(
    "https://api.arcnm.io/api/v1/parts/calculations",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/parts/calculations", {
  method: "GET",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
  },
})
const data = await resp.json()

Responses

Status Description
200 Successful Response
422 Validation Error

Errors

Standard error responses — see the Errors catalog 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.
429 rate_limited Per-key or per-org rate limit exceeded — back off with jitter and retry.

Response body 200

Field Type Description
count integer Number of calculations returned in items (this page's size).
items CalculationListItem[] The calculations on this page, newest first.

Example response

{
  "count": 0,
  "items": [
    {
      "created_at": "string",
      "currency": "EUR",
      "engine": "arcanum",
      "finished_at": "string",
      "id": "string",
      "lot_size": 50,
      "material_grade_id": "string",
      "material_ref": "1.4301",
      "name": "string",
      "started_at": "string",
      "status": "string",
      "unit_cost": 12.84
    }
  ]
}

Create a calculation (queued)

POST /api/v1/parts/calculations

Create a new Calculation row tied to (revision × env × dataset). Does NOT enqueue — call POST /parts/calculations/{id}/run to schedule.

One engine (ARCNM), one endpoint. The platform chooses the right drawing-understanding depth per calculation automatically. The optional extraction_tier field lets you override that depth — auto (default), lite (faster), or full (deepest); most callers should leave it unset.

Request body (application/json)

Field Type Required Description
annual_volume integer no Expected yearly quantity, used for amortizing setup over the run (>= 1).
costing_environment_id string yes UUID of the costing environment (machine rates, region) to price against.
currency string no ISO 4217 currency code for the quote; defaults to the costing environment's currency when omitted.
dataset_link_id string no UUID of a specific dataset link to use; omit to use the revision's active primary CAD.
engine string no Pricing engine selector; retained for back-compat and always normalized to the sole engine.
extraction_tier auto | lite | full no Drawing-understanding depth. auto (default) lets the platform choose the right depth per drawing; lite is faster and lighter; full is the deepest. Most callers should leave this unset.
lot_size integer no Number of identical parts produced per batch (>= 1).
material_grade_id string no UUID of a resolved material grade; takes precedence over material_ref when both are supplied.
material_ref string no Free-form material reference (URN, Werkstoffnummer, AISI/SAE code, trade name, or your SKU); resolved to a material grade.
name string no Optional human-readable label; defaults to a timestamped name when omitted.
part_revision_id string yes UUID of the part revision to price.
region string no Pricing region override; defaults to the costing environment's region when omitted.

Request

curl -X POST https://api.arcnm.io/api/v1/parts/calculations \
  -H "X-API-Key: $ARCNM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "part_revision_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "costing_environment_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  }'
import requests

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/calculations",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "part_revision_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "costing_environment_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    },
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/parts/calculations", {
  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",
    "costing_environment_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  }),
})
const data = await resp.json()

Responses

Status Description
201 Successful Response
422 Validation Error

Errors

Standard error responses — see the Errors catalog 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 201

Field Type Description
enqueued_task string Name of the background task enqueued for this run; null if nothing was scheduled.
id string UUID of the calculation.
job_id string Identifier of the queued background job; null when no job was enqueued.
status string Current lifecycle state (e.g. queued, running, succeeded, failed, cancelled).

Example response

{
  "enqueued_task": "string",
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "job_id": "string",
  "status": "string"
}

Delete Calculation

DELETE /api/v1/parts/calculations/{calculation_id}

Hard-delete a calculation row.

A non-terminal row is first cancelled (which releases the wallet hold) so the worker can no longer transition it; the row itself is then removed. Use Cancel if you want the audit trail to persist.

Parameters

Name In Type Required Description
calculation_id path string yes Identifier of the calculation.

Request

curl -X DELETE https://api.arcnm.io/api/v1/parts/calculations/{calculation_id} \
  -H "X-API-Key: $ARCNM_API_KEY"
import requests

resp = requests.delete(
    "https://api.arcnm.io/api/v1/parts/calculations/{calculation_id}",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/parts/calculations/{calculation_id}", {
  method: "DELETE",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
  },
})
const data = await resp.json()

Responses

Status Description
200 Successful Response
422 Validation Error

Errors

Standard error responses — see the Errors catalog 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
message string Human-readable confirmation that the calculation was deleted.

Example response

{
  "message": "string"
}

Get Calculation

GET /api/v1/parts/calculations/{calculation_id}

Parameters

Name In Type Required Description
calculation_id path string yes Identifier of the calculation.

Request

curl -X GET https://api.arcnm.io/api/v1/parts/calculations/{calculation_id} \
  -H "X-API-Key: $ARCNM_API_KEY"
import requests

resp = requests.get(
    "https://api.arcnm.io/api/v1/parts/calculations/{calculation_id}",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/parts/calculations/{calculation_id}", {
  method: "GET",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
  },
})
const data = await resp.json()

Responses

Status Description
200 Successful Response
422 Validation Error

Errors

Standard error responses — see the Errors catalog 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
analytics object Free-form engine-output object carrying the cost breakdown and audit detail; its internal keys may evolve.
annual_volume integer Expected yearly quantity used to amortize setup cost.
costing_environment_id string UUID of the costing environment used for pricing.
created_at string ISO 8601 timestamp when the calculation was created.
currency string ISO 4217 currency code for the cost figures.
engine string Pricing engine used for this calculation.
error string Failure message; null unless the run failed.
finished_at string ISO 8601 timestamp when the run finished; null before it completes.
id string UUID of the calculation.
lot_size integer Number of identical parts produced per batch.
material_grade_id string UUID of the linked material grade; null when no grade is set.
material_ref string Material reference (URN) of the linked grade; null when no grade is set.
name string Human-readable label for the calculation.
part_id string UUID of the part this calculation belongs to.
part_revision_id string UUID of the part revision that was priced.
setup_cost number One-time setup cost in the quote's currency; null until pricing completes.
started_at string ISO 8601 timestamp when the run started; null before it begins.
status string Current lifecycle state (e.g. queued, running, succeeded, failed, cancelled).
total_cost number Total cost for the full lot in the quote's currency; null until pricing completes.
total_time_s number Total production time for the lot in seconds; null until pricing completes.
unit_cost number Cost per part in the quote's currency; null until pricing completes.
unit_time_s number Production time per part in seconds; null until pricing completes.

Example response

{
  "analytics": {},
  "annual_volume": 500,
  "costing_environment_id": "string",
  "created_at": "string",
  "currency": "EUR",
  "engine": "arcanum",
  "error": "string",
  "finished_at": "string",
  "id": "string",
  "lot_size": 50,
  "material_grade_id": "string",
  "material_ref": "1.4301",
  "name": "string",
  "part_id": "string",
  "part_revision_id": "string",
  "setup_cost": 52.5,
  "started_at": "string",
  "status": "string",
  "total_cost": 642,
  "total_time_s": 184,
  "unit_cost": 12.84,
  "unit_time_s": 184
}

Cancel Calculation

POST /api/v1/parts/calculations/{calculation_id}/cancel

Cancel a queued / running / polling calculation.

Idempotent: a terminal row is returned untouched. The wallet hold is released as part of the transition so a cancelled calc never debits the org's balance.

Parameters

Name In Type Required Description
calculation_id path string yes Identifier of the calculation.

Request

curl -X POST https://api.arcnm.io/api/v1/parts/calculations/{calculation_id}/cancel \
  -H "X-API-Key: $ARCNM_API_KEY"
import requests

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/calculations/{calculation_id}/cancel",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/parts/calculations/{calculation_id}/cancel", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
  },
})
const data = await resp.json()

Responses

Status Description
200 Successful Response
422 Validation Error

Errors

Standard error responses — see the Errors catalog 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
enqueued_task string Name of the background task enqueued for this run; null if nothing was scheduled.
id string UUID of the calculation.
job_id string Identifier of the queued background job; null when no job was enqueued.
status string Current lifecycle state (e.g. queued, running, succeeded, failed, cancelled).

Example response

{
  "enqueued_task": "string",
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "job_id": "string",
  "status": "string"
}

Upload Inputs

POST /api/v1/parts/calculations/{calculation_id}/inputs

Attach a 2D drawing PDF / STL mesh / RFQ text file to the calculation.

The file is stored against the calculation's part revision under the requested role. Subsequent POST /run calls auto-discover it by role so the pipeline can fan out additional extractors (drawing, mesh fallback, RFQ text) alongside the primary geometry pass.

Parameters

Name In Type Required Description
calculation_id path string yes Identifier of the calculation.

Request body (multipart/form-data)

Field Type Required Description
file string yes The file to attach (2D drawing PDF, STL mesh, or RFQ text).
role string yes Role the file plays on the calculation's revision (e.g. drawing_2d, mesh_3d, rfq_text).

Request

curl -X POST https://api.arcnm.io/api/v1/parts/calculations/{calculation_id}/inputs \
  -H "X-API-Key: $ARCNM_API_KEY" \
  -F "role=primary" \
  -F "[email protected]"
import requests

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/calculations/{calculation_id}/inputs",
    headers={"X-API-Key": "YOUR_API_KEY"},
    files={
        "file": open("file.bin", "rb"),
    },
    data={
        "role": "primary",
    },
)
resp.raise_for_status()
print(resp.json())
const form = new FormData()
form.append("role", "primary")
form.append("file", file) // a File or Blob

const resp = await fetch("https://api.arcnm.io/api/v1/parts/calculations/{calculation_id}/inputs", {
  method: "POST",
  headers: { "X-API-Key": process.env.ARCNM_API_KEY! },
  body: form,
})
const data = await resp.json()

Responses

Status Description
200 Successful Response
422 Validation Error

Errors

Standard error responses — see the Errors catalog 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
billing object Free-form billing object describing the upload charge; its internal keys may evolve.
calculation_id string UUID of the calculation the file was attached to.
data_source_id string UUID of the stored data source created for the uploaded file.
role string Role the file was attached under (e.g. drawing_2d, mesh, rfq_text).
sha256 string Hex-encoded SHA-256 digest of the uploaded bytes.
size_bytes integer Size of the uploaded file in bytes.

Example response

{
  "billing": {},
  "calculation_id": "string",
  "data_source_id": "string",
  "role": "primary",
  "sha256": "9f86d081884c7d659a2feaa0c55ad015…",
  "size_bytes": 204800
}

Patch Calculation Material

PATCH /api/v1/parts/calculations/{calculation_id}/material

Override the material on an existing calculation.

The new material_grade_id is resolved exactly the same way POST /parts/calculations resolves it on create, so the result is consistent with the create-time logic.

The calculation isn't re-priced here — follow up with POST /run if a re-quote is desired. The explicit two-step flow lets you review the override before paying for another pipeline pass.

Parameters

Name In Type Required Description
calculation_id path string yes Identifier of the calculation.

Request body (application/json)

Field Type Required Description
material_grade_id string no UUID of the material grade to link. Provide this or material_ref.
material_ref string no Material reference (URN, Werkstoffnummer, or trade name) to resolve and link. Provide this or material_grade_id.

Request

curl -X PATCH https://api.arcnm.io/api/v1/parts/calculations/{calculation_id}/material \
  -H "X-API-Key: $ARCNM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "material_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "material_ref": "1.4301"
  }'
import requests

resp = requests.patch(
    "https://api.arcnm.io/api/v1/parts/calculations/{calculation_id}/material",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "material_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "material_ref": "1.4301"
    },
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/parts/calculations/{calculation_id}/material", {
  method: "PATCH",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "material_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "material_ref": "1.4301"
  }),
})
const data = await resp.json()

Responses

Status Description
200 Successful Response
422 Validation Error

Errors

Standard error responses — see the Errors catalog 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
id string UUID of the calculation that was updated.
material_grade_id string UUID of the newly assigned material grade.
material_ref string Material reference (URN) of the newly assigned grade; null when unavailable.
previous_material_grade_id string UUID of the material grade before this change; null if none was set.
resolved_via string How the grade was resolved: a directly supplied grade id, or a free-form reference lookup.

Example response

{
  "id": "string",
  "material_grade_id": "string",
  "material_ref": "1.4301",
  "previous_material_grade_id": "string",
  "resolved_via": "string"
}

Run Calculation

POST /api/v1/parts/calculations/{calculation_id}/run

Enqueue the calculation onto the worker queue.

Idempotent: a row in a non-terminal state (queued/running/polling) is not re-enqueued; a row in succeeded is returned untouched; a row in failed/cancelled/timed_out is reset to queued and re-enqueued so the user can retry.

Parameters

Name In Type Required Description
calculation_id path string yes Identifier of the calculation.

Request

curl -X POST https://api.arcnm.io/api/v1/parts/calculations/{calculation_id}/run \
  -H "X-API-Key: $ARCNM_API_KEY"
import requests

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/calculations/{calculation_id}/run",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/parts/calculations/{calculation_id}/run", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
  },
})
const data = await resp.json()

Responses

Status Description
202 Successful Response
422 Validation Error

Errors

Standard error responses — see the Errors catalog for the full envelope, request_id, and retry-safety table.

Status Code When
401 invalid_api_key Missing, malformed, or revoked API key.
402 insufficient_funds The pre-authorised wallet hold for the run exceeds your balance.
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 202

Field Type Description
enqueued_task string Name of the background task enqueued for this run; null if nothing was scheduled.
id string UUID of the calculation.
job_id string Identifier of the queued background job; null when no job was enqueued.
status string Current lifecycle state (e.g. queued, running, succeeded, failed, cancelled).

Example response

{
  "enqueued_task": "string",
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "job_id": "string",
  "status": "string"
}

Select Machine

POST /api/v1/parts/calculations/{calculation_id}/select-machine

Run geometry extraction and machine selection only, returning the rationale.

Cheaper than a full calculation (skips planning, physics, and economics); typical latency 200–800 ms for a 10-machine fleet.

Parameters

Name In Type Required Description
calculation_id path string yes Identifier of the calculation.
X-Request-ID header string no Optional client-supplied request ID; reused as an idempotency key for the metered charge.
Idempotency-Key header string no Optional key that makes this request safely retryable — see Idempotency.

Request

curl -X POST https://api.arcnm.io/api/v1/parts/calculations/{calculation_id}/select-machine \
  -H "X-API-Key: $ARCNM_API_KEY"
import requests

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/calculations/{calculation_id}/select-machine",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/parts/calculations/{calculation_id}/select-machine", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
  },
})
const data = await resp.json()

Responses

Status Description
200 Successful Response
422 Validation Error

Errors

Standard error responses — see the Errors catalog 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
calculation_id string Identifier of the calculation the selection was run for.
candidates SelectionCandidatePayload[] All machines evaluated, with their feasibility and scoring.
chosen_machine_id string Identifier of the selected machine, or null if none is feasible.
chosen_machine_name string Name of the selected machine, or null if none is feasible.
rationale_text string Human-readable explanation of why the machine was or was not selected.

Example response

{
  "calculation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "candidates": [
    {
      "blocking_violations": [],
      "capability_score": 0,
      "feasible": true,
      "machine_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "machine_name": "string",
      "provisional_unit_cost_eur": 0
    }
  ],
  "chosen_machine_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "chosen_machine_name": "string",
  "rationale_text": "string"
}

Bulk Cancel Calculations

POST /api/v1/parts/calculations/bulk-cancel

Request body (application/json)

Field Type Required Description
ids string[] yes Calculation IDs to act on (1–200). Duplicates collapse silently.

Request

curl -X POST https://api.arcnm.io/api/v1/parts/calculations/bulk-cancel \
  -H "X-API-Key: $ARCNM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "ids": [
      "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    ]
  }'
import requests

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/calculations/bulk-cancel",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "ids": [
            "3fa85f64-5717-4562-b3fc-2c963f66afa6"
        ]
    },
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/parts/calculations/bulk-cancel", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "ids": [
      "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    ]
  }),
})
const data = await resp.json()

Responses

Status Description
200 Successful Response
422 Validation Error

Errors

Standard error responses — see the Errors catalog 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
not_found string[] IDs that did not match a calculation for this tenant.
skipped string[] IDs skipped because their state didn't allow the action.
succeeded string[] IDs of calculations the bulk action applied to successfully.

Example response

{
  "not_found": [
    "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  ],
  "skipped": [
    "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  ],
  "succeeded": [
    "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  ]
}

Bulk Delete Calculations

POST /api/v1/parts/calculations/bulk-delete

Request body (application/json)

Field Type Required Description
ids string[] yes Calculation IDs to act on (1–200). Duplicates collapse silently.

Request

curl -X POST https://api.arcnm.io/api/v1/parts/calculations/bulk-delete \
  -H "X-API-Key: $ARCNM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "ids": [
      "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    ]
  }'
import requests

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/calculations/bulk-delete",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "ids": [
            "3fa85f64-5717-4562-b3fc-2c963f66afa6"
        ]
    },
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/parts/calculations/bulk-delete", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "ids": [
      "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    ]
  }),
})
const data = await resp.json()

Responses

Status Description
200 Successful Response
422 Validation Error

Errors

Standard error responses — see the Errors catalog 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
not_found string[] IDs that did not match a calculation for this tenant.
skipped string[] IDs skipped because their state didn't allow the action.
succeeded string[] IDs of calculations the bulk action applied to successfully.

Example response

{
  "not_found": [
    "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  ],
  "skipped": [
    "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  ],
  "succeeded": [
    "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  ]
}

Bulk Retry Calculations

POST /api/v1/parts/calculations/bulk-retry

Re-enqueue eligible failed/cancelled/timed_out rows.

Each row goes through the same place-hold + enqueue path as a direct POST /run so wallet semantics and attempt budgets are enforced identically. A row that's already running, succeeded, or out of attempt budget lands in skipped.

Request body (application/json)

Field Type Required Description
ids string[] yes Calculation IDs to act on (1–200). Duplicates collapse silently.

Request

curl -X POST https://api.arcnm.io/api/v1/parts/calculations/bulk-retry \
  -H "X-API-Key: $ARCNM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "ids": [
      "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    ]
  }'
import requests

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/calculations/bulk-retry",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "ids": [
            "3fa85f64-5717-4562-b3fc-2c963f66afa6"
        ]
    },
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/parts/calculations/bulk-retry", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "ids": [
      "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    ]
  }),
})
const data = await resp.json()

Responses

Status Description
200 Successful Response
422 Validation Error

Errors

Standard error responses — see the Errors catalog 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
not_found string[] IDs that did not match a calculation for this tenant.
skipped string[] IDs skipped because their state didn't allow the action.
succeeded string[] IDs of calculations the bulk action applied to successfully.

Example response

{
  "not_found": [
    "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  ],
  "skipped": [
    "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  ],
  "succeeded": [
    "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  ]
}

Quote

POST /api/v1/parts/calculations/quote

Convenience: create + enqueue in one round-trip.

Equivalent to POST / + POST /{id}/run.

Request body (application/json)

Field Type Required Description
annual_volume integer no Expected yearly quantity, used for amortizing setup over the run (>= 1).
costing_environment_id string yes UUID of the costing environment (machine rates, region) to price against.
currency string no ISO 4217 currency code for the quote; defaults to the costing environment's currency when omitted.
dataset_link_id string no UUID of a specific dataset link to use; omit to use the revision's active primary CAD.
engine string no Pricing engine selector; retained for back-compat and always normalized to the sole engine.
extraction_tier auto | lite | full no Drawing-understanding depth. auto (default) lets the platform choose the right depth per drawing; lite is faster and lighter; full is the deepest. Most callers should leave this unset.
lot_size integer no Number of identical parts produced per batch (>= 1).
material_grade_id string no UUID of a resolved material grade; takes precedence over material_ref when both are supplied.
material_ref string no Free-form material reference (URN, Werkstoffnummer, AISI/SAE code, trade name, or your SKU); resolved to a material grade.
name string no Optional human-readable label; defaults to a timestamped name when omitted.
part_revision_id string yes UUID of the part revision to price.
region string no Pricing region override; defaults to the costing environment's region when omitted.

Request

curl -X POST https://api.arcnm.io/api/v1/parts/calculations/quote \
  -H "X-API-Key: $ARCNM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "part_revision_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "costing_environment_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  }'
import requests

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/calculations/quote",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "part_revision_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "costing_environment_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    },
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/parts/calculations/quote", {
  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",
    "costing_environment_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  }),
})
const data = await resp.json()

Responses

Status Description
202 Successful Response
422 Validation Error

Errors

Standard error responses — see the Errors catalog for the full envelope, request_id, and retry-safety table.

Status Code When
401 invalid_api_key Missing, malformed, or revoked API key.
402 insufficient_funds The pre-authorised wallet hold for the run exceeds your balance.
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 202

Field Type Description
enqueued_task string Name of the background task enqueued for this run; null if nothing was scheduled.
id string UUID of the calculation.
job_id string Identifier of the queued background job; null when no job was enqueued.
status string Current lifecycle state (e.g. queued, running, succeeded, failed, cancelled).

Example response

{
  "enqueued_task": "string",
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "job_id": "string",
  "status": "string"
}

Upload And Quote

POST /api/v1/parts/calculations/upload-and-quote

One-shot upload + new-calculation flow.

Takes a STEP file (+ optional 2D drawing PDF + RFQ text), creates the underlying Part / PartRevision / dataset rows, and enqueues the calculation. This is the simplest end-to-end UX — the user goes from "I have a CAD file" to "I'll see a quote in 30 s" with one HTTP call.

Idempotency: part_number is the natural key — if a Part with the same number already exists for this tenant, we attach a new revision rather than re-creating the Part.

Request body (multipart/form-data)

Field Type Required Description
annual_volume integer no Expected yearly quantity used to amortize setup cost (1 to 1,000,000,000).
cad_file string yes 3D CAD file (e.g. STEP) to price; required.
costing_environment_id string yes UUID of the costing environment (machine rates, region) to price against.
drawing_file string no Optional 2D drawing (PDF/PNG/JPEG) for the part.
engine string no Pricing engine selector; retained for back-compat and always normalized to the sole engine.
extraction_tier string no Drawing-understanding depth override: auto (default), lite (faster), or full (deepest). Most callers should leave this unset.
lot_size integer no Number of identical parts produced per batch (1 to 1,000,000,000).
material_grade_id string no UUID of a resolved material grade; takes precedence over material_ref when both are supplied.
material_ref string no Free-form material reference (URN, Werkstoffnummer, AISI/SAE code, trade name, or your SKU).
part_number string yes Natural-key part number; reused to attach a new revision if the part already exists.
rfq_file string no Optional RFQ text file with requirements for the part.

Request

curl -X POST https://api.arcnm.io/api/v1/parts/calculations/upload-and-quote \
  -H "X-API-Key: $ARCNM_API_KEY" \
  -F "costing_environment_id=3fa85f64-5717-4562-b3fc-2c963f66afa6" \
  -F "part_number=BRACKET-001" \
  -F "[email protected]"
import requests

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/calculations/upload-and-quote",
    headers={"X-API-Key": "YOUR_API_KEY"},
    files={
        "cad_file": open("part.step", "rb"),
    },
    data={
        "costing_environment_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "part_number": "BRACKET-001",
    },
)
resp.raise_for_status()
print(resp.json())
const form = new FormData()
form.append("costing_environment_id", "3fa85f64-5717-4562-b3fc-2c963f66afa6")
form.append("part_number", "BRACKET-001")
form.append("cad_file", file) // a File or Blob

const resp = await fetch("https://api.arcnm.io/api/v1/parts/calculations/upload-and-quote", {
  method: "POST",
  headers: { "X-API-Key": process.env.ARCNM_API_KEY! },
  body: form,
})
const data = await resp.json()

Responses

Status Description
202 Successful Response
422 Validation Error

Errors

Standard error responses — see the Errors catalog for the full envelope, request_id, and retry-safety table.

Status Code When
401 invalid_api_key Missing, malformed, or revoked API key.
402 insufficient_funds The pre-authorised wallet hold for the run exceeds your balance.
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 202

Field Type Description
enqueued_task string Name of the background task enqueued for this run; null if nothing was scheduled.
id string UUID of the calculation.
job_id string Identifier of the queued background job; null when no job was enqueued.
status string Current lifecycle state (e.g. queued, running, succeeded, failed, cancelled).

Example response

{
  "enqueued_task": "string",
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "job_id": "string",
  "status": "string"
}