ARCNM

API reference

Parts & revisions

The Parts API manages parts and their revisions.

The Parts API manages parts and their revisions: create, list, fetch, update, and delete parts, and manage each part's revision history.

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 Parts

GET /api/v1/parts/

List the organization's parts, newest first.

count is the total across all pages. Page with cursor rather than offset when parts may be created while you walk — offset counts from the start of the result set, so a concurrent insert shifts every later page and rows get skipped or repeated.

Paginated. Pass cursor (from the previous response) to fetch the next page; limit caps the page size.

Parameters

Name In Type Required Description
q query string no Substring match
classification_id query string no Identifier of the classification.
folder_id query string no Only parts filed directly in this folder (excludes subfolders).
unfiled query boolean no Only parts not filed in any folder (folder_id IS NULL).
make_or_buy query string[] no Only parts sourced this way. Repeatable — several values are OR-ed, so passing every value is the same as passing none.
procurement_type query string[] no Only parts with one of these procurement types.
quoted query boolean no true → only parts with at least one succeeded calculation; false → only parts that have never been priced.
material_grade_id query string[] no Only parts whose NEWEST succeeded calculation used one of these material grades. A part carries no material of its own — the material is chosen per calculation — so this filters on the last run. Repeatable; several values are OR-ed.
sort query string no Ordering key. unit_cost and annual_spend rank by the newest succeeded calculation per part; parts with no successful calculation always sort last, whatever the direction. created_at, updated_at and part_number support cursor; the other three page by offset only, because their column is nullable or joined and a cursor over it cannot reach every row.
include_facets query boolean no Also return facets: the values available for each filter with their counts, computed over everything the OTHER active filters allow. Lets a client show counts and grey out choices that would return nothing.
cursor query string no Opaque position token from the previous page's next_cursor (or the Link / X-Next-Cursor response header). Omit it for the first page. Keep every other query parameter identical for the whole walk — a cursor replayed against different filters is rejected.
limit query integer no Maximum rows to return in one page.
order query asc | desc no Sort direction over the collection's ordering key. Use asc to reconcile a batch: rows come oldest-first, so work created while you page lands after your position instead of shifting rows under it.
created_after query string no Only rows created at or after this instant (RFC 3339, e.g. 2026-07-20T09:00:00Z). Inclusive.
created_before query string no Only rows created strictly before this instant (RFC 3339). Exclusive, so an after/before pair tiles a range without overlap.
offset query integer no Rows to skip. Superseded by cursor, which is stable under concurrent writes; kept for existing integrations. Bounded — past the cap, page with cursor.

Request

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

resp = requests.get(
    "https://api.arcnm.io/api/v1/parts/",
    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/", {
  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 Total number of parts matching the query.
data PartListItem[] The page of parts matching the query.
facets object Present only when include_facets is set. Maps each filter name to its selectable values with counts.
has_more boolean Whether more parts match beyond this page.
next_cursor string Position token for the next page — pass it back as cursor. Null on the last page, and null under a sort that cannot be keyset-paged (see sort). Prefer this over offset: it is stable while parts are being created.

Example response

{
  "count": 0,
  "data": [
    {
      "attributes": {},
      "base_uom": "EA",
      "classification_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "created_at": "2026-06-01T12:00:00Z",
      "default_currency": "EUR",
      "description": "string",
      "folder_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "lead_time_days": 0,
      "make_or_buy": "make",
      "org_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "part_number": "BRACKET-001",
      "preview_status": "string",
      "procurement_type": "in_house",
      "updated_at": "2026-06-01T12:00:00Z"
    }
  ],
  "facets": {},
  "has_more": false,
  "next_cursor": "string"
}

Create Part

POST /api/v1/parts/

Request body (application/json)

Field Type Required Description
attributes object no Free-form key/value metadata for the part.
base_uom string no Base unit of measure for the part (ISO unit code, e.g. EA, KG, M).
classification_id string no ID of the classification category this part belongs to, if any.
default_currency string no Default currency for the part's pricing (ISO 4217 code, e.g. EUR, USD).
description string no Human-readable description of the part.
folder_id string no ID of the workspace folder this part is filed in; null is unfiled.
lead_time_days integer no Expected lead time to obtain the part, in days.
make_or_buy string no Whether the part is manufactured in-house or purchased.
part_number string yes Stable identifier (≈ SAP MATNR). Unique per org.
procurement_type string no How the part is sourced (e.g. in-house production or external supplier).

Request

curl -X POST https://api.arcnm.io/api/v1/parts/ \
  -H "X-API-Key: $ARCNM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "part_number": "BRACKET-001"
  }'
import requests

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "part_number": "BRACKET-001"
    },
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/parts/", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "part_number": "BRACKET-001"
  }),
})
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
attributes object Free-form key/value metadata for the part.
base_uom string Base unit of measure for the part (ISO unit code, e.g. EA, KG, M).
classification_id string ID of the classification category this part belongs to, if any.
created_at string Timestamp when the part was created (UTC, ISO 8601).
default_currency string Default currency for the part's pricing (ISO 4217 code, e.g. EUR, USD).
description string Human-readable description of the part.
folder_id string ID of the workspace folder this part is filed in; null is unfiled.
id string Unique identifier of the part.
lead_time_days integer Expected lead time to obtain the part, in days.
make_or_buy string Whether the part is manufactured in-house or purchased.
org_id string ID of the organization that owns the part.
part_number string Stable identifier (≈ SAP MATNR). Unique per org.
procurement_type string How the part is sourced (e.g. in-house production or external supplier).
updated_at string Timestamp when the part was last updated (UTC, ISO 8601).

Example response

{
  "attributes": {},
  "base_uom": "EA",
  "classification_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "created_at": "2026-06-01T12:00:00Z",
  "default_currency": "EUR",
  "description": "string",
  "folder_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "lead_time_days": 0,
  "make_or_buy": "make",
  "org_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "part_number": "BRACKET-001",
  "procurement_type": "in_house",
  "updated_at": "2026-06-01T12:00:00Z"
}

Delete Part

DELETE /api/v1/parts/{part_id}

Parameters

Name In Type Required Description
part_id path string yes Identifier of the part.

Request

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

resp = requests.delete(
    "https://api.arcnm.io/api/v1/parts/{part_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/{part_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 resource was deleted.

Example response

{
  "message": "string"
}

Get Part

GET /api/v1/parts/{part_id}

Parameters

Name In Type Required Description
part_id path string yes Identifier of the part.

Request

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

resp = requests.get(
    "https://api.arcnm.io/api/v1/parts/{part_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/{part_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
attributes object Free-form key/value metadata for the part.
base_uom string Base unit of measure for the part (ISO unit code, e.g. EA, KG, M).
classification_id string ID of the classification category this part belongs to, if any.
created_at string Timestamp when the part was created (UTC, ISO 8601).
default_currency string Default currency for the part's pricing (ISO 4217 code, e.g. EUR, USD).
description string Human-readable description of the part.
folder_id string ID of the workspace folder this part is filed in; null is unfiled.
id string Unique identifier of the part.
lead_time_days integer Expected lead time to obtain the part, in days.
make_or_buy string Whether the part is manufactured in-house or purchased.
org_id string ID of the organization that owns the part.
part_number string Stable identifier (≈ SAP MATNR). Unique per org.
procurement_type string How the part is sourced (e.g. in-house production or external supplier).
updated_at string Timestamp when the part was last updated (UTC, ISO 8601).

Example response

{
  "attributes": {},
  "base_uom": "EA",
  "classification_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "created_at": "2026-06-01T12:00:00Z",
  "default_currency": "EUR",
  "description": "string",
  "folder_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "lead_time_days": 0,
  "make_or_buy": "make",
  "org_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "part_number": "BRACKET-001",
  "procurement_type": "in_house",
  "updated_at": "2026-06-01T12:00:00Z"
}

Update Part

PATCH /api/v1/parts/{part_id}

Parameters

Name In Type Required Description
part_id path string yes Identifier of the part.

Request body (application/json)

Field Type Required Description
attributes object no Free-form key/value metadata for the part.
base_uom string no Base unit of measure for the part (ISO unit code, e.g. EA, KG, M).
classification_id string no ID of the classification category this part belongs to, if any.
default_currency string no Default currency for the part's pricing (ISO 4217 code, e.g. EUR, USD).
description string no Human-readable description of the part.
folder_id string no ID of the workspace folder this part is filed in; null is unfiled.
lead_time_days integer no Expected lead time to obtain the part, in days.
make_or_buy string no Whether the part is manufactured in-house or purchased.
procurement_type string no How the part is sourced (e.g. in-house production or external supplier).

Request

curl -X PATCH https://api.arcnm.io/api/v1/parts/{part_id} \
  -H "X-API-Key: $ARCNM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "attributes": {},
    "base_uom": "EA",
    "classification_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "default_currency": "string",
    "description": "string",
    "folder_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "lead_time_days": 0,
    "make_or_buy": "string",
    "procurement_type": "string"
  }'
import requests

resp = requests.patch(
    "https://api.arcnm.io/api/v1/parts/{part_id}",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "attributes": {},
        "base_uom": "EA",
        "classification_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "default_currency": "string",
        "description": "string",
        "folder_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "lead_time_days": 0,
        "make_or_buy": "string",
        "procurement_type": "string"
    },
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/parts/{part_id}", {
  method: "PATCH",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "attributes": {},
    "base_uom": "EA",
    "classification_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "default_currency": "string",
    "description": "string",
    "folder_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "lead_time_days": 0,
    "make_or_buy": "string",
    "procurement_type": "string"
  }),
})
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
attributes object Free-form key/value metadata for the part.
base_uom string Base unit of measure for the part (ISO unit code, e.g. EA, KG, M).
classification_id string ID of the classification category this part belongs to, if any.
created_at string Timestamp when the part was created (UTC, ISO 8601).
default_currency string Default currency for the part's pricing (ISO 4217 code, e.g. EUR, USD).
description string Human-readable description of the part.
folder_id string ID of the workspace folder this part is filed in; null is unfiled.
id string Unique identifier of the part.
lead_time_days integer Expected lead time to obtain the part, in days.
make_or_buy string Whether the part is manufactured in-house or purchased.
org_id string ID of the organization that owns the part.
part_number string Stable identifier (≈ SAP MATNR). Unique per org.
procurement_type string How the part is sourced (e.g. in-house production or external supplier).
updated_at string Timestamp when the part was last updated (UTC, ISO 8601).

Example response

{
  "attributes": {},
  "base_uom": "EA",
  "classification_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "created_at": "2026-06-01T12:00:00Z",
  "default_currency": "EUR",
  "description": "string",
  "folder_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "lead_time_days": 0,
  "make_or_buy": "make",
  "org_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "part_number": "BRACKET-001",
  "procurement_type": "in_house",
  "updated_at": "2026-06-01T12:00:00Z"
}

Part Faces Url

GET /api/v1/parts/{part_id}/faces-url

Per-face-tagged glTF (cost-driver heatmap model) for a Part.

Same dataset-resolution + {url, status} contract as /parts/{id}/preview-url but serves faces_glb_storage_key — the model where every B-rep face is its own primitive tagged with face_uuid. Only produced for STEP inputs; the frontend falls back to the opaque preview when url is None.

part_revision_id (optional query param) pins resolution to a specific revision so the heatmap's face_uuids line up with the cost drivers from a calc on THAT revision. Without it, the newest revision's dataset is served (a re-upload after the calc would otherwise blank the heatmap — the GLB's face_uuids would derive from different STEP bytes than the drivers).

Parameters

Name In Type Required Description
part_id path string yes Identifier of the part.
part_revision_id query string no Identifier of the part revision.

Request

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

resp = requests.get(
    "https://api.arcnm.io/api/v1/parts/{part_id}/faces-url",
    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/{part_id}/faces-url", {
  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
data_source_id string Identifier of the resolved CAD file; null when no dataset was found.
expires_at string UTC ISO-8601 instant at which the presigned URL expires; null unless status is 'ok'. Refresh the URL before this moment.
expires_in_s integer Lifetime of the presigned URL in seconds; null unless status is 'ok'.
status string Preview readiness state (e.g. ok, pending, failed, no_dataset).
url string Presigned URL to the GLB preview; null unless status is 'ok'.

Example response

{
  "data_source_id": "string",
  "expires_at": "string",
  "expires_in_s": 0,
  "status": "string",
  "url": "string"
}

Part Preview Url

GET /api/v1/parts/{part_id}/preview-url

Engine-agnostic GLB preview for a Part.

Resolves the part's most-recent revision's primary CAD dataset and hands back a presigned URL for its glTF/GLB. The frontend uses this on the parts overview and part detail pages so the 3D model is surfaced before any calculation has run.

Returns {url, status} (status semantics match /datasets/{ds_id}/preview-url). The frontend treats the same payload identically across all surfaces — that is the "globally unified" 3D preview contract.

Parameters

Name In Type Required Description
part_id path string yes Identifier of the part.

Request

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

resp = requests.get(
    "https://api.arcnm.io/api/v1/parts/{part_id}/preview-url",
    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/{part_id}/preview-url", {
  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
data_source_id string Identifier of the resolved CAD file; null when no dataset was found.
expires_at string UTC ISO-8601 instant at which the presigned URL expires; null unless status is 'ok'. Refresh the URL before this moment.
expires_in_s integer Lifetime of the presigned URL in seconds; null unless status is 'ok'.
status string Preview readiness state (e.g. ok, pending, failed, no_dataset).
url string Presigned URL to the GLB preview; null unless status is 'ok'.

Example response

{
  "data_source_id": "string",
  "expires_at": "string",
  "expires_in_s": 0,
  "status": "string",
  "url": "string"
}

List Revisions

GET /api/v1/parts/{part_id}/revisions

List a part's revisions, newest first.

count is the total across all pages; data is one page of it.

Paginated. Pass cursor (from the previous response) to fetch the next page; limit caps the page size.

Parameters

Name In Type Required Description
part_id path string yes Identifier of the part.
cursor query string no Opaque position token from the previous page's next_cursor (or the Link / X-Next-Cursor response header). Omit it for the first page. Keep every other query parameter identical for the whole walk — a cursor replayed against different filters is rejected.
limit query integer no Maximum rows to return in one page.
order query asc | desc no Sort direction over the collection's ordering key. Use asc to reconcile a batch: rows come oldest-first, so work created while you page lands after your position instead of shifting rows under it.
created_after query string no Only rows created at or after this instant (RFC 3339, e.g. 2026-07-20T09:00:00Z). Inclusive.
created_before query string no Only rows created strictly before this instant (RFC 3339). Exclusive, so an after/before pair tiles a range without overlap.

Request

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

resp = requests.get(
    "https://api.arcnm.io/api/v1/parts/{part_id}/revisions",
    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/{part_id}/revisions", {
  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
count integer Total number of revisions matching the query.
data PartRevisionPublic[] The page of revisions matching the query.
has_more boolean Whether more revisions match beyond this page.
next_cursor string Position token for the next page — pass it back as cursor. Null on the last page.

Example response

{
  "count": 0,
  "data": [
    {
      "attributes": {},
      "created_at": "2026-06-01T12:00:00Z",
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "parent_revision_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "part_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "revision_code": "string",
      "updated_at": "2026-06-01T12:00:00Z"
    }
  ],
  "has_more": false,
  "next_cursor": "string"
}

Create Revision

POST /api/v1/parts/{part_id}/revisions

Parameters

Name In Type Required Description
part_id path string yes Identifier of the part.

Request body (application/json)

Field Type Required Description
attributes object no Free-form key/value metadata for the revision.
change_request_id string no ID of the change request that triggered this revision, if any.
parent_revision_id string no ID of the revision this one was derived from, recording its lineage.
revision_code string yes Customer-facing revision label (A, B, 01, 02, …).

Request

curl -X POST https://api.arcnm.io/api/v1/parts/{part_id}/revisions \
  -H "X-API-Key: $ARCNM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "revision_code": "string"
  }'
import requests

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/{part_id}/revisions",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "revision_code": "string"
    },
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/parts/{part_id}/revisions", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "revision_code": "string"
  }),
})
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.
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 201

Field Type Description
attributes object Free-form key/value metadata for the revision.
created_at string Timestamp when the revision was created (UTC, ISO 8601).
id string Unique identifier of the revision.
parent_revision_id string ID of the revision this one was derived from, recording its lineage.
part_id string ID of the part this revision belongs to.
revision_code string Customer-facing revision label (A, B, 01, 02, …).
updated_at string Timestamp when the revision was last updated (UTC, ISO 8601).

Example response

{
  "attributes": {},
  "created_at": "2026-06-01T12:00:00Z",
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "parent_revision_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "part_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "revision_code": "string",
  "updated_at": "2026-06-01T12:00:00Z"
}

Delete Revision

DELETE /api/v1/parts/{part_id}/revisions/{revision_id}

Parameters

Name In Type Required Description
part_id path string yes Identifier of the part.
revision_id path string yes Identifier of the revision.

Request

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

resp = requests.delete(
    "https://api.arcnm.io/api/v1/parts/{part_id}/revisions/{revision_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/{part_id}/revisions/{revision_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 resource was deleted.

Example response

{
  "message": "string"
}

Get Revision

GET /api/v1/parts/{part_id}/revisions/{revision_id}

Parameters

Name In Type Required Description
part_id path string yes Identifier of the part.
revision_id path string yes Identifier of the revision.

Request

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

resp = requests.get(
    "https://api.arcnm.io/api/v1/parts/{part_id}/revisions/{revision_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/{part_id}/revisions/{revision_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
attributes object Free-form key/value metadata for the revision.
created_at string Timestamp when the revision was created (UTC, ISO 8601).
id string Unique identifier of the revision.
parent_revision_id string ID of the revision this one was derived from, recording its lineage.
part_id string ID of the part this revision belongs to.
revision_code string Customer-facing revision label (A, B, 01, 02, …).
updated_at string Timestamp when the revision was last updated (UTC, ISO 8601).

Example response

{
  "attributes": {},
  "created_at": "2026-06-01T12:00:00Z",
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "parent_revision_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "part_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "revision_code": "string",
  "updated_at": "2026-06-01T12:00:00Z"
}

Update Revision

PATCH /api/v1/parts/{part_id}/revisions/{revision_id}

Parameters

Name In Type Required Description
part_id path string yes Identifier of the part.
revision_id path string yes Identifier of the revision.

Request body (application/json)

Field Type Required Description
attributes object no Free-form metadata to merge onto the revision, as a JSON object.

Request

curl -X PATCH https://api.arcnm.io/api/v1/parts/{part_id}/revisions/{revision_id} \
  -H "X-API-Key: $ARCNM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "attributes": {}
  }'
import requests

resp = requests.patch(
    "https://api.arcnm.io/api/v1/parts/{part_id}/revisions/{revision_id}",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "attributes": {}
    },
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/parts/{part_id}/revisions/{revision_id}", {
  method: "PATCH",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "attributes": {}
  }),
})
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
attributes object Free-form key/value metadata for the revision.
created_at string Timestamp when the revision was created (UTC, ISO 8601).
id string Unique identifier of the revision.
parent_revision_id string ID of the revision this one was derived from, recording its lineage.
part_id string ID of the part this revision belongs to.
revision_code string Customer-facing revision label (A, B, 01, 02, …).
updated_at string Timestamp when the revision was last updated (UTC, ISO 8601).

Example response

{
  "attributes": {},
  "created_at": "2026-06-01T12:00:00Z",
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "parent_revision_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "part_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "revision_code": "string",
  "updated_at": "2026-06-01T12:00:00Z"
}

List Datasets

GET /api/v1/parts/{part_id}/revisions/{revision_id}/datasets

Parameters

Name In Type Required Description
part_id path string yes Identifier of the part.
revision_id path string yes Identifier of the revision.

Request

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

resp = requests.get(
    "https://api.arcnm.io/api/v1/parts/{part_id}/revisions/{revision_id}/datasets",
    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/{part_id}/revisions/{revision_id}/datasets", {
  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.

Attach Dataset

POST /api/v1/parts/{part_id}/revisions/{revision_id}/datasets

Attach an existing DataSource row to a revision.

For a fresh file upload, prefer POST .../datasets/upload which creates the DataSource + link in one shot.

Parameters

Name In Type Required Description
part_id path string yes Identifier of the part.
revision_id path string yes Identifier of the revision.

Request body (application/json)

Field Type Required Description
attributes object no Free-form metadata for the attachment, as a JSON object.
data_source_id string yes Identifier of the uploaded data source to attach to the revision.
is_primary boolean no Whether this dataset is the primary one for the revision.
role string no Role of the file on the revision (e.g. cad_3d for a 3D CAD model, drawing_2d for a 2D drawing).

Request

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

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/{part_id}/revisions/{revision_id}/datasets",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "data_source_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    },
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/parts/{part_id}/revisions/{revision_id}/datasets", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "data_source_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.
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 201

Field Type Description
attributes object Free-form key/value metadata for the file attachment.
content_type string MIME type of the uploaded file (e.g. application/pdf).
created_at string Timestamp when the file was attached (UTC, ISO 8601).
data_source_id string ID of the underlying stored file this attachment points to.
filename string Original filename of the uploaded file.
id string Unique identifier of the uploaded file attached to the revision.
is_active boolean Whether this is the current file; superseded re-uploads are marked inactive.
is_primary boolean Whether this is the primary CAD file used for analysis on the revision.
part_revision_id string ID of the revision this file is attached to.
role string The file's role on the revision (e.g. 3D CAD, 2D drawing, spec).
size_bytes integer Size of the uploaded file in bytes.

Example response

{
  "attributes": {},
  "content_type": "string",
  "created_at": "2026-06-01T12:00:00Z",
  "data_source_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "filename": "bracket.step",
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "is_active": true,
  "is_primary": true,
  "part_revision_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "role": "primary",
  "size_bytes": 204800
}

Detach Dataset

DELETE /api/v1/parts/{part_id}/revisions/{revision_id}/datasets/{dataset_link_id}

Parameters

Name In Type Required Description
part_id path string yes Identifier of the part.
revision_id path string yes Identifier of the revision.

Request

curl -X DELETE https://api.arcnm.io/api/v1/parts/{part_id}/revisions/{revision_id}/datasets/{dataset_link_id} \
  -H "X-API-Key: $ARCNM_API_KEY"
import requests

resp = requests.delete(
    "https://api.arcnm.io/api/v1/parts/{part_id}/revisions/{revision_id}/datasets/{dataset_link_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/{part_id}/revisions/{revision_id}/datasets/{dataset_link_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 dataset was detached.

Example response

{
  "message": "string"
}

Update Dataset

PATCH /api/v1/parts/{part_id}/revisions/{revision_id}/datasets/{dataset_link_id}

Edit a dataset link.

Currently supports two fields:

  • filename: rename the underlying DataSource.
  • is_primary: promote/demote within the parent revision. The "exactly one primary" invariant is maintained server-side: when promoting, every other link on the same revision is demoted in the same transaction so concurrent primaries can't co-exist.

Parameters

Name In Type Required Description
part_id path string yes Identifier of the part.
revision_id path string yes Identifier of the revision.
dataset_link_id path string yes Identifier of the dataset link.

Request body (application/json)

Field Type Required Description
filename string no New original filename for the uploaded file.
is_primary boolean no Set true to make this the primary CAD file for analysis on the revision.

Request

curl -X PATCH https://api.arcnm.io/api/v1/parts/{part_id}/revisions/{revision_id}/datasets/{dataset_link_id} \
  -H "X-API-Key: $ARCNM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "filename": "bracket.step",
    "is_primary": true
  }'
import requests

resp = requests.patch(
    "https://api.arcnm.io/api/v1/parts/{part_id}/revisions/{revision_id}/datasets/{dataset_link_id}",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "filename": "bracket.step",
        "is_primary": True
    },
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/parts/{part_id}/revisions/{revision_id}/datasets/{dataset_link_id}", {
  method: "PATCH",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "filename": "bracket.step",
    "is_primary": true
  }),
})
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
attributes object Free-form key/value metadata for the file attachment.
content_type string MIME type of the uploaded file (e.g. application/pdf).
created_at string Timestamp when the file was attached (UTC, ISO 8601).
data_source_id string ID of the underlying stored file this attachment points to.
filename string Original filename of the uploaded file.
id string Unique identifier of the uploaded file attached to the revision.
is_active boolean Whether this is the current file; superseded re-uploads are marked inactive.
is_primary boolean Whether this is the primary CAD file used for analysis on the revision.
part_revision_id string ID of the revision this file is attached to.
role string The file's role on the revision (e.g. 3D CAD, 2D drawing, spec).
size_bytes integer Size of the uploaded file in bytes.

Example response

{
  "attributes": {},
  "content_type": "string",
  "created_at": "2026-06-01T12:00:00Z",
  "data_source_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "filename": "bracket.step",
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "is_active": true,
  "is_primary": true,
  "part_revision_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "role": "primary",
  "size_bytes": 204800
}

Upload Dataset

POST /api/v1/parts/{part_id}/revisions/{revision_id}/datasets/upload

Upload a file directly onto a revision, in one shot.

Stores the file and links it to the revision. No calculation is enqueued — use /calculations/upload for the calculate-on-upload flow.

Parameters

Name In Type Required Description
part_id path string yes Identifier of the part.
revision_id path string yes Identifier of the revision.
role query string no Role of the file on the revision (e.g. cad_3d for a 3D model, drawing_2d for a 2D drawing).
is_primary query boolean no Whether this dataset becomes the primary one for its role on the revision.

Request body (multipart/form-data)

Field Type Required Description
file string yes The CAD model or drawing file to attach to the revision.

Request

curl -X POST https://api.arcnm.io/api/v1/parts/{part_id}/revisions/{revision_id}/datasets/upload \
  -H "X-API-Key: $ARCNM_API_KEY" \
  -F "[email protected]"
import requests

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/{part_id}/revisions/{revision_id}/datasets/upload",
    headers={"X-API-Key": "YOUR_API_KEY"},
    files={
        "file": open("file.bin", "rb"),
    },
)
resp.raise_for_status()
print(resp.json())
const form = new FormData()
form.append("file", file) // a File or Blob

const resp = await fetch("https://api.arcnm.io/api/v1/parts/{part_id}/revisions/{revision_id}/datasets/upload", {
  method: "POST",
  headers: { "X-API-Key": process.env.ARCNM_API_KEY! },
  body: form,
})
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.
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 201

Field Type Description
attributes object Free-form key/value metadata for the file attachment.
content_type string MIME type of the uploaded file (e.g. application/pdf).
created_at string Timestamp when the file was attached (UTC, ISO 8601).
data_source_id string ID of the underlying stored file this attachment points to.
filename string Original filename of the uploaded file.
id string Unique identifier of the uploaded file attached to the revision.
is_active boolean Whether this is the current file; superseded re-uploads are marked inactive.
is_primary boolean Whether this is the primary CAD file used for analysis on the revision.
part_revision_id string ID of the revision this file is attached to.
role string The file's role on the revision (e.g. 3D CAD, 2D drawing, spec).
size_bytes integer Size of the uploaded file in bytes.

Example response

{
  "attributes": {},
  "content_type": "string",
  "created_at": "2026-06-01T12:00:00Z",
  "data_source_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "filename": "bracket.step",
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "is_active": true,
  "is_primary": true,
  "part_revision_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "role": "primary",
  "size_bytes": 204800
}

Part Preview Urls Batch

POST /api/v1/parts/preview-urls

Presign the previews for many parts in ONE request.

A list view needs a thumbnail per row, and the per-part endpoint made that one HTTP call per row: a 50-row page fired 35 of them, which on the Free tier (60 weighted calls/minute) exhausted the whole budget on a single page load — the tail 429'd, the thumbnails broke, and the client's expired-URL retry turned that into a loop. Measured on production 2026-07-28.

Same payload per part as GET /{part_id}/preview-url, keyed by part id. An id the caller cannot see is simply absent from the response rather than 404-ing the batch, so one stale row in a list never blanks the rest.

Request body (application/json)

Field Type Required Description
part_ids string[] yes Parts to resolve preview URLs for. Ask only for the rows you are about to render.

Request

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

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/preview-urls",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "part_ids": [
            "3fa85f64-5717-4562-b3fc-2c963f66afa6"
        ]
    },
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/parts/preview-urls", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "part_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
previews PartPreviewUrlBatchItem[] One entry per resolvable part, in the order requested. Ids the caller cannot see are omitted rather than failing the batch.

Example response

{
  "previews": [
    {
      "data_source_id": "string",
      "expires_at": "string",
      "expires_in_s": 0,
      "part_id": "string",
      "status": "string",
      "url": "string"
    }
  ]
}

Which of these part numbers already exist?

POST /api/v1/parts/resolve-numbers

Read-only pre-flight for a bulk upload: given the part numbers you are about to send, says which already exist in this workspace, where each one currently lives, and what it last cost — so a conflict can be resolved by the user BEFORE the first byte is uploaded and before anything is metered. No side effects.

Request body (application/json)

Field Type Required Description
folder_id string no The folder you intend to upload into, if any.
part_numbers string[] yes Candidate part numbers, exactly as they will be sent to /calculations/upload-and-quote. They are matched verbatim — see the endpoint description for why nothing is normalised here.

Request

curl -X POST https://api.arcnm.io/api/v1/parts/resolve-numbers \
  -H "X-API-Key: $ARCNM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "part_numbers": [
      "string"
    ]
  }'
import requests

resp = requests.post(
    "https://api.arcnm.io/api/v1/parts/resolve-numbers",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "part_numbers": [
            "string"
        ]
    },
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/parts/resolve-numbers", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.ARCNM_API_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "part_numbers": [
      "string"
    ]
  }),
})
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
results ResolvedPartNumber[] One entry per requested number, in the order requested.

Example response

{
  "results": [
    {
      "already_in_requested_folder": false,
      "current_folder_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "current_folder_name": "string",
      "exists": true,
      "last_calculated_at": "2026-06-01T12:00:00Z",
      "last_currency": "string",
      "last_unit_cost": 0,
      "part_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "part_number": "BRACKET-001"
    }
  ]
}