ARCNM

Get started

Quickstart

From zero to your first quote in under five minutes — cURL, Python, TypeScript.

Run your first ARCNM quote in under five minutes: send a STEP file and get back an audited unit price. By the end you'll have run Deep Feature Extraction and Deep Cost Modeling against a real part.

Billed on success. A calculation is billed when it succeeds. Failed runs, 4xx/5xx responses, and idempotent replays don't add usage. A wallet hold is pre-authorised when you run a calculation and released if it fails. New accounts start with a welcome credit worth your first 5 runs — so this quickstart is free. See Pricing.


1. Create an account and an org

Sign up at arcnm.io/signup. The first user in an org is the owner and can mint API keys.

If you already have an account, head to Settings → API keys.

2. Mint an API key

Settings → API keys → New key. Give it a name, pick the scopes you need, copy the plaintext key. It is shown exactly once.

For this quickstart, grant:

  • parts:read
  • parts:write
  • uploads:write
export ARCNM_API_KEY="ak_live_…"

Scopes are enforced per request. A leaked parts:read key cannot trigger a billable calculation. See Authentication. Send the key in the X-API-Key header (not Authorization).

3. No SDK required

cURL or any HTTP client is enough — the whole quickstart is plain REST. The Python and TypeScript tabs below use requests and fetch. (Native SDKs are on the roadmap; see SDKs.)

curl --version

4. Get a costing environment

A calculation prices a part against a costing environment (your machines + rates). Create one in the dashboard under Environments, or via the API, and copy its id:

export ARCNM_ENV_ID="7c1f…"

5. Upload a STEP and quote it in one call

POST /api/v1/parts/calculations/upload-and-quote is the one-shot endpoint: it creates a Part + Revision + Dataset from your uploaded files and enqueues the calculation in a single multipart 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=$ARCNM_ENV_ID" \
  -F "part_number=BRACKET-001" \
  -F "cad_file=@./bracket.step;type=application/step" \
  -F "drawing_file=@./bracket.pdf;type=application/pdf" \
  -F "lot_size=50" \
  -F "annual_volume=500" \
  -F "material_ref=1.4301"
import os, requests

API = "https://api.arcnm.io/api/v1"
H = {"X-API-Key": os.environ["ARCNM_API_KEY"]}

with open("bracket.step", "rb") as cad, open("bracket.pdf", "rb") as drw:
    r = requests.post(
        f"{API}/parts/calculations/upload-and-quote",
        headers=H,
        data={
            "costing_environment_id": os.environ["ARCNM_ENV_ID"],
            "part_number": "BRACKET-001",
            "lot_size": 50,
            "annual_volume": 500,
            "material_ref": "1.4301",
        },
        files={"cad_file": cad, "drawing_file": drw},
    )
r.raise_for_status()
calc = r.json()
print(calc["id"], calc["status"])  # e.g. ('9d…', 'queued')
import { readFile } from "node:fs/promises"

const API = "https://api.arcnm.io/api/v1"
const H = { "X-API-Key": process.env.ARCNM_API_KEY! }

const form = new FormData()
form.set("costing_environment_id", process.env.ARCNM_ENV_ID!)
form.set("part_number", "BRACKET-001")
form.set("lot_size", "50")
form.set("annual_volume", "500")
form.set("material_ref", "1.4301")
form.set("cad_file", new Blob([await readFile("./bracket.step")]), "bracket.step")
form.set("drawing_file", new Blob([await readFile("./bracket.pdf")]), "bracket.pdf")

const res = await fetch(`${API}/parts/calculations/upload-and-quote`, {
  method: "POST", headers: H, body: form,
})
const calc = await res.json()
console.log(calc.id, calc.status)

Response (202 Accepted):

{
  "id": "9d8f3b62-…",
  "status": "queued"
}

6. Poll for the result

Calculations finish in seconds for typical milled parts. Poll GET /api/v1/parts/calculations/{id} until status is terminal.

curl https://api.arcnm.io/api/v1/parts/calculations/9d8f3b62-… \
  -H "X-API-Key: $ARCNM_API_KEY"
import time

while True:
    calc = requests.get(f"{API}/parts/calculations/{calc['id']}", headers=H).json()
    if calc["status"] in ("succeeded", "failed", "cancelled", "timed_out"):
        break
    time.sleep(2)

print(calc["status"], calc["unit_cost"], calc["currency"])
let result = calc
while (!["succeeded", "failed", "cancelled", "timed_out"].includes(result.status)) {
  await new Promise((r) => setTimeout(r, 2000))
  result = await (await fetch(`${API}/parts/calculations/${calc.id}`, { headers: H })).json()
}
console.log(result.status, result.unit_cost, result.currency)

A successful response carries the unit cost, totals, cycle times, and an analytics audit blob:

{
  "id": "9d8f3b62-…",
  "status": "succeeded",
  "engine": "arcanum",
  "currency": "EUR",
  "unit_cost": 12.84,
  "total_cost": 642.0,
  "setup_cost": 52.5,
  "unit_time_s": 184.0,
  "total_time_s": 9200.0,
  "analytics": { "...": "audit blob — see Concepts → Audit" },
  "finished_at": "2026-05-28T14:23:32Z"
}

That's it. You've priced a part end-to-end. See the Calculations reference for the full field list.


Next steps

  • Audit & provenance — how a quote traces back to its inputs.
  • Adaptive Calibration — tune ARCNM to your tenant's machines, rates, and historical data.
  • Webhooks — subscribe to wallet and account events.
  • MCP — let Claude or Cursor quote parts inside the agent loop.
  • Errors — what to catch and how to retry safely.