Tools
SDKs
Native SDKs are on the roadmap. Today, call the REST API directly or generate a client from the OpenAPI spec.
Status: not yet published. There is no
pip install arcanumornpm install @arcnm/sdkpackage today — native SDKs are on the roadmap. In the meantime the REST API is small and stable, and you can generate a typed client from the public OpenAPI spec. This page will document the official SDKs when they ship.
The full machine-readable spec lives at:
https://api.arcnm.io/api/v1/openapi-public.json
Generate a client from OpenAPI
Use openapi-generator or Speakeasy to scaffold a client in your language:
curl https://api.arcnm.io/api/v1/openapi-public.json > arcanum.json
openapi-generator-cli generate -i arcanum.json -g python -o ./arcanum-py
# or -g typescript-fetch / go / java / ruby / rust / csharp …
Remember to send the API key in the X-API-Key header (see
Authentication).
Python — thin wrapper with requests
import os, time, requests
API = "https://api.arcnm.io/api/v1"
HEADERS = {"X-API-Key": os.environ["ARCNM_API_KEY"]}
def upload_and_quote(env_id, part_number, cad_path, **fields):
with open(cad_path, "rb") as cad:
r = requests.post(
f"{API}/parts/calculations/upload-and-quote",
headers=HEADERS,
data={"costing_environment_id": env_id, "part_number": part_number, **fields},
files={"cad_file": cad},
)
r.raise_for_status()
return r.json()
def wait(calc_id, timeout=120):
deadline = time.time() + timeout
while time.time() < deadline:
calc = requests.get(f"{API}/parts/calculations/{calc_id}", headers=HEADERS).json()
if calc["status"] in ("succeeded", "failed", "cancelled", "timed_out"):
return calc
time.sleep(2)
raise TimeoutError(calc_id)
calc = upload_and_quote(env_id, "BRACKET-001", "bracket.step", lot_size=50, material_ref="1.4301")
result = wait(calc["id"])
print(result["status"], result["unit_cost"], result["currency"])
TypeScript — thin wrapper with fetch
const API = "https://api.arcnm.io/api/v1"
const H = { "X-API-Key": process.env.ARCNM_API_KEY! }
async function uploadAndQuote(envId: string, partNumber: string, cad: Blob, fields: Record<string, string> = {}) {
const form = new FormData()
form.set("costing_environment_id", envId)
form.set("part_number", partNumber)
for (const [k, v] of Object.entries(fields)) form.set(k, v)
form.set("cad_file", cad, "part.step")
const res = await fetch(`${API}/parts/calculations/upload-and-quote`, { method: "POST", headers: H, body: form })
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`)
return res.json()
}
async function wait(calcId: string, timeoutMs = 120_000) {
const deadline = Date.now() + timeoutMs
while (Date.now() < deadline) {
const calc = await (await fetch(`${API}/parts/calculations/${calcId}`, { headers: H })).json()
if (["succeeded", "failed", "cancelled", "timed_out"].includes(calc.status)) return calc
await new Promise((r) => setTimeout(r, 2000))
}
throw new Error(`timeout: ${calcId}`)
}
In the browser, never ship a live
ak_live_…key. Proxy requests through your backend.
Errors & retries
Switch on the error code in the standard envelope, and
back off on 429 / 5xx (see Rate limits). Pair
retries with an Idempotency-Key.
Webhooks
Verify webhook signatures with the Standard-Webhooks scheme — a complete Python and TypeScript verifier is in Webhooks → verifying signatures.
Stay in the loop
Want the native SDK when it lands? Email [email protected] and we'll
notify you.