API reference
Materials
The Materials API looks up material grades and manages per-tenant overrides.
The Materials API looks up material grades and manages per-tenant overrides: search grades, resolve one by URN, and create, update, or delete cost overrides.
Auto-generated from the public OpenAPI spec — this page never drifts from the running API. Base URL
https://api.arcnm.io. Authenticate with theX-API-Keyheader (see Authentication).
List Grades
GET /api/v1/materials/grades
List the material grades available to you.
That is the standards catalogue plus any grade your organization has registered for itself.
q searches across primary_code, display_code, name,
urn AND every alias's code/display_code. A user typing
"AISI 304", "SUS304" or "S30400" therefore finds 1.4301 from this
single endpoint — no need to fall back to POST /lookup.
Returns the total matching row count (not page size) so the frontend can paginate properly.
Paginated. Pass
cursor(from the previous response) to fetch the next page;limitcaps the page size.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
category |
query | carbon_steel | alloy_steel | stainless_steel | tool_steel | cast_iron | aluminium | copper_alloy | nickel_alloy | titanium_alloy | magnesium_alloy | zinc_alloy | thermoplastic | thermoset | elastomer | composite | other |
no | Filter by material category (e.g. stainless_steel, aluminium). |
iso_group |
query | P | M | K | N | S | H |
no | Filter by ISO 513 machining group (P, M, K, N, S, H). |
q |
query | string | no | Free-text search across grade codes, names, URNs, and aliases. |
include_inactive |
query | boolean | no | Include grades your organization has deactivated. They stay out of the list by default; set this to find one again and reactivate it. |
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. |
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/materials/grades \
-H "X-API-Key: $ARCNM_API_KEY"
import requests
resp = requests.get(
"https://api.arcnm.io/api/v1/materials/grades",
headers={"X-API-Key": "YOUR_API_KEY"},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/materials/grades", {
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 grades matching the query (not the page size). |
data |
MaterialGradePublic[] | The material grades on this page. |
has_more |
boolean | Whether more grades 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": [
{
"aliases": [
{}
],
"attributes": {},
"category": "carbon_steel",
"created_at": "2026-06-01T12:00:00Z",
"density_kg_per_m3": 0,
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"is_active": true,
"iso_machining_group": "P",
"name": "string",
"org_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"primary_code": "string",
"primary_standard_code": "en10027-1",
"primary_standard_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"successor_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"updated_at": "2026-06-01T12:00:00Z",
"urn": "string"
}
],
"has_more": false,
"next_cursor": "string"
}
Create Org Grade
POST /api/v1/materials/grades
Register a material grade private to your organization.
For a material the standards catalogue does not carry — a house designation, an internal blank, a supplier-specific grade. Only your organization can see or resolve it, and it prices exactly like a catalogue grade: give it a €/kg rate on an environment, or let the category default stand until you do.
The designation is fixed once registered, and one that already resolves for you — a catalogue code, a standard alias, or another of your own grades — is refused.
Request body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
attributes |
object | no | Free-form key/value metadata: yield_mpa, tensile_mpa, coating, … |
category |
carbon_steel | alloy_steel | stainless_steel | tool_steel | cast_iron | aluminium | copper_alloy | nickel_alloy | titanium_alloy | magnesium_alloy | zinc_alloy | thermoplastic | thermoset | elastomer | composite | other |
yes | Broad material family the grade belongs to (e.g. carbon_steel, aluminium). |
density_kg_per_m3 |
number | yes | Material density in kilograms per cubic metre — steel is about 7850, aluminium about 2700. Mind the unit: a value in g/cm³ is 1000x too small and is rejected. |
designation |
string | yes | Your designation for the grade (e.g. 'WS-42-Blank'). Letters, digits, dots and hyphens; rendered as entered, stored URN-safe. Must not collide with a catalogue code. |
iso_machining_group |
P | M | K | N | S | H |
yes | ISO 513 machining group (P/M/K/N/S/H) — required; drives cutting data. |
name |
string | yes | Human-readable name of the material. |
Request
curl -X POST https://api.arcnm.io/api/v1/materials/grades \
-H "X-API-Key: $ARCNM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"category": "carbon_steel",
"designation": "string",
"name": "string",
"iso_machining_group": "P",
"density_kg_per_m3": 0
}'
import requests
resp = requests.post(
"https://api.arcnm.io/api/v1/materials/grades",
headers={"X-API-Key": "YOUR_API_KEY"},
json={
"category": "carbon_steel",
"designation": "string",
"name": "string",
"iso_machining_group": "P",
"density_kg_per_m3": 0
},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/materials/grades", {
method: "POST",
headers: {
"X-API-Key": process.env.ARCNM_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"category": "carbon_steel",
"designation": "string",
"name": "string",
"iso_machining_group": "P",
"density_kg_per_m3": 0
}),
})
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 |
|---|---|---|
aliases |
MaterialGradeAliasPublic[] | Cross-references mapping this grade's code across other standards and trade names. |
attributes |
object | Free-form key/value metadata for extra mechanical and physical properties. |
category |
carbon_steel | alloy_steel | stainless_steel | tool_steel | cast_iron | aluminium | copper_alloy | nickel_alloy | titanium_alloy | magnesium_alloy | zinc_alloy | thermoplastic | thermoset | elastomer | composite | other |
Broad material family the grade belongs to (e.g. steel, aluminium, polymer). |
created_at |
string | Timestamp when the grade record was created. |
density_kg_per_m3 |
number | Material density in kilograms per cubic metre. |
id |
string | Unique identifier of the material grade. |
is_active |
boolean | Whether the grade is currently active and selectable; false when retired. |
iso_machining_group |
P | M | K | N | S | H |
ISO 513 machining group (P/M/K/N/S/H) used to gauge machinability. |
name |
string | Human-readable name of the material grade. |
org_id |
string | Null → platform-catalogue grade shared by every organization; set → this organization's private grade. |
primary_code |
string | Standards-compliant cased display code; the same value as display_code. |
primary_standard_code |
en10027-1 | en10027-2 | en10025 | en10083 | en10084 | en10088 | en10346 | en-iso-4957 | en573-1 | en573-2 | en1412 | din17007 | en1560 | en1561 | en1563 | iso1043-1 | iso1043-2 | iso18064 | uns | aisi-sae | jis | astm | eclass | unspsc | org |
URN-safe code of the primary standard (en10027-2, iso1043-1, …). Hydrated by the routes layer so frontends can render a badge without a second round-trip. |
primary_standard_id |
string | Identifier of the standard that defines this grade's primary code. |
successor_grade_id |
string | Identifier of the grade that supersedes this one; null when still current. |
updated_at |
string | Timestamp when the grade record was last updated. |
urn |
string | Canonical URN that uniquely and stably identifies this grade across systems. |
Example response
{
"aliases": [
{
"code": "string",
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"is_canonical": false,
"is_preferred_display": true,
"material_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"standard_code": "en10027-1",
"standard_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
],
"attributes": {},
"category": "carbon_steel",
"created_at": "2026-06-01T12:00:00Z",
"density_kg_per_m3": 0,
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"is_active": true,
"iso_machining_group": "P",
"name": "string",
"org_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"primary_code": "string",
"primary_standard_code": "en10027-1",
"primary_standard_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"successor_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"updated_at": "2026-06-01T12:00:00Z",
"urn": "string"
}
Delete Org Grade
DELETE /api/v1/materials/grades/{grade_id}
Delete an org-private grade. Refused (409) while environment
material prices or calculations still reference it — deactivate it
instead (PATCH {is_active: false}) to keep history intact.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
grade_id |
path | string | yes | Identifier of the grade. |
Request
curl -X DELETE https://api.arcnm.io/api/v1/materials/grades/{grade_id} \
-H "X-API-Key: $ARCNM_API_KEY"
import requests
resp = requests.delete(
"https://api.arcnm.io/api/v1/materials/grades/{grade_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/materials/grades/{grade_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 Grade
GET /api/v1/materials/grades/{grade_id}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
grade_id |
path | string | yes | Identifier of the grade. |
Request
curl -X GET https://api.arcnm.io/api/v1/materials/grades/{grade_id} \
-H "X-API-Key: $ARCNM_API_KEY"
import requests
resp = requests.get(
"https://api.arcnm.io/api/v1/materials/grades/{grade_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/materials/grades/{grade_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 |
|---|---|---|
aliases |
MaterialGradeAliasPublic[] | Cross-references mapping this grade's code across other standards and trade names. |
attributes |
object | Free-form key/value metadata for extra mechanical and physical properties. |
category |
carbon_steel | alloy_steel | stainless_steel | tool_steel | cast_iron | aluminium | copper_alloy | nickel_alloy | titanium_alloy | magnesium_alloy | zinc_alloy | thermoplastic | thermoset | elastomer | composite | other |
Broad material family the grade belongs to (e.g. steel, aluminium, polymer). |
created_at |
string | Timestamp when the grade record was created. |
density_kg_per_m3 |
number | Material density in kilograms per cubic metre. |
id |
string | Unique identifier of the material grade. |
is_active |
boolean | Whether the grade is currently active and selectable; false when retired. |
iso_machining_group |
P | M | K | N | S | H |
ISO 513 machining group (P/M/K/N/S/H) used to gauge machinability. |
name |
string | Human-readable name of the material grade. |
org_id |
string | Null → platform-catalogue grade shared by every organization; set → this organization's private grade. |
primary_code |
string | Standards-compliant cased display code; the same value as display_code. |
primary_standard_code |
en10027-1 | en10027-2 | en10025 | en10083 | en10084 | en10088 | en10346 | en-iso-4957 | en573-1 | en573-2 | en1412 | din17007 | en1560 | en1561 | en1563 | iso1043-1 | iso1043-2 | iso18064 | uns | aisi-sae | jis | astm | eclass | unspsc | org |
URN-safe code of the primary standard (en10027-2, iso1043-1, …). Hydrated by the routes layer so frontends can render a badge without a second round-trip. |
primary_standard_id |
string | Identifier of the standard that defines this grade's primary code. |
successor_grade_id |
string | Identifier of the grade that supersedes this one; null when still current. |
updated_at |
string | Timestamp when the grade record was last updated. |
urn |
string | Canonical URN that uniquely and stably identifies this grade across systems. |
Example response
{
"aliases": [
{
"code": "string",
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"is_canonical": false,
"is_preferred_display": true,
"material_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"standard_code": "en10027-1",
"standard_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
],
"attributes": {},
"category": "carbon_steel",
"created_at": "2026-06-01T12:00:00Z",
"density_kg_per_m3": 0,
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"is_active": true,
"iso_machining_group": "P",
"name": "string",
"org_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"primary_code": "string",
"primary_standard_code": "en10027-1",
"primary_standard_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"successor_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"updated_at": "2026-06-01T12:00:00Z",
"urn": "string"
}
Update Org Grade
PATCH /api/v1/materials/grades/{grade_id}
Partial update of an org-private grade. designation and
category are immutable (both are baked into the URN); use
is_active: false to retire a grade from pickers without
deleting history.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
grade_id |
path | string | yes | Identifier of the grade. |
Request body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
attributes |
object | no | Free-form key/value metadata attached to the grade. |
density_kg_per_m3 |
number | no | Material density in kilograms per cubic metre. Mind the unit: a value in g/cm³ is 1000x too small and is rejected. |
is_active |
boolean | no | Set false to retire the grade from pickers without deleting history. |
iso_machining_group |
P | M | K | N | S | H |
no | ISO 513 machining group (P/M/K/N/S/H). |
name |
string | no | Human-readable name of the material. |
Request
curl -X PATCH https://api.arcnm.io/api/v1/materials/grades/{grade_id} \
-H "X-API-Key: $ARCNM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"attributes": {},
"density_kg_per_m3": 0,
"is_active": true,
"iso_machining_group": "P",
"name": "string"
}'
import requests
resp = requests.patch(
"https://api.arcnm.io/api/v1/materials/grades/{grade_id}",
headers={"X-API-Key": "YOUR_API_KEY"},
json={
"attributes": {},
"density_kg_per_m3": 0,
"is_active": True,
"iso_machining_group": "P",
"name": "string"
},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/materials/grades/{grade_id}", {
method: "PATCH",
headers: {
"X-API-Key": process.env.ARCNM_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"attributes": {},
"density_kg_per_m3": 0,
"is_active": true,
"iso_machining_group": "P",
"name": "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 |
|---|---|---|
aliases |
MaterialGradeAliasPublic[] | Cross-references mapping this grade's code across other standards and trade names. |
attributes |
object | Free-form key/value metadata for extra mechanical and physical properties. |
category |
carbon_steel | alloy_steel | stainless_steel | tool_steel | cast_iron | aluminium | copper_alloy | nickel_alloy | titanium_alloy | magnesium_alloy | zinc_alloy | thermoplastic | thermoset | elastomer | composite | other |
Broad material family the grade belongs to (e.g. steel, aluminium, polymer). |
created_at |
string | Timestamp when the grade record was created. |
density_kg_per_m3 |
number | Material density in kilograms per cubic metre. |
id |
string | Unique identifier of the material grade. |
is_active |
boolean | Whether the grade is currently active and selectable; false when retired. |
iso_machining_group |
P | M | K | N | S | H |
ISO 513 machining group (P/M/K/N/S/H) used to gauge machinability. |
name |
string | Human-readable name of the material grade. |
org_id |
string | Null → platform-catalogue grade shared by every organization; set → this organization's private grade. |
primary_code |
string | Standards-compliant cased display code; the same value as display_code. |
primary_standard_code |
en10027-1 | en10027-2 | en10025 | en10083 | en10084 | en10088 | en10346 | en-iso-4957 | en573-1 | en573-2 | en1412 | din17007 | en1560 | en1561 | en1563 | iso1043-1 | iso1043-2 | iso18064 | uns | aisi-sae | jis | astm | eclass | unspsc | org |
URN-safe code of the primary standard (en10027-2, iso1043-1, …). Hydrated by the routes layer so frontends can render a badge without a second round-trip. |
primary_standard_id |
string | Identifier of the standard that defines this grade's primary code. |
successor_grade_id |
string | Identifier of the grade that supersedes this one; null when still current. |
updated_at |
string | Timestamp when the grade record was last updated. |
urn |
string | Canonical URN that uniquely and stably identifies this grade across systems. |
Example response
{
"aliases": [
{
"code": "string",
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"is_canonical": false,
"is_preferred_display": true,
"material_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"standard_code": "en10027-1",
"standard_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
],
"attributes": {},
"category": "carbon_steel",
"created_at": "2026-06-01T12:00:00Z",
"density_kg_per_m3": 0,
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"is_active": true,
"iso_machining_group": "P",
"name": "string",
"org_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"primary_code": "string",
"primary_standard_code": "en10027-1",
"primary_standard_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"successor_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"updated_at": "2026-06-01T12:00:00Z",
"urn": "string"
}
Get Grade Master
GET /api/v1/materials/grades/{grade_id}/master
The material master record for one grade.
SAP-style split: the grade row is the client-level basic data
(canonical catalogue, or your org-private grade), the override is
your organization's layer (SKU, trade name, property overrides), and
pricing is the plant-level costing view — the €/kg each of your
costing environments would actually use today, each entry labelled
env_rate (that environment's own material rate wins) or
platform_default (the seed fallback applies). Reuses the calc
path's own resolver, so display and pricing cannot disagree.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
grade_id |
path | string | yes | Identifier of the grade. |
Request
curl -X GET https://api.arcnm.io/api/v1/materials/grades/{grade_id}/master \
-H "X-API-Key: $ARCNM_API_KEY"
import requests
resp = requests.get(
"https://api.arcnm.io/api/v1/materials/grades/{grade_id}/master",
headers={"X-API-Key": "YOUR_API_KEY"},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/materials/grades/{grade_id}/master", {
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 |
|---|---|---|
effective_properties |
MaterialPropertyValue[] | Merged property view in vocabulary order — your values win over catalogue figures, each entry labelled with its source. |
grade |
MaterialGradePublic | The grade record (canonical catalogue or your org-private grade), aliases included. |
override |
OrgMaterialOverridePublic | Your organization's override row for this grade; null when none exists. |
pricing |
MaterialMasterPricing | Per-environment €/kg with provenance, plus the platform fallback. |
Example response
{
"effective_properties": [
{
"basis": "minimum",
"canonical_value": 0,
"key": "string",
"source": "canonical",
"unit": "string",
"value": 0
}
],
"grade": {
"aliases": [
{
"code": "string",
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"is_canonical": false,
"is_preferred_display": true,
"material_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"standard_code": "en10027-1",
"standard_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
],
"attributes": {},
"category": "carbon_steel",
"created_at": "2026-06-01T12:00:00Z",
"density_kg_per_m3": 0,
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"is_active": true,
"iso_machining_group": "P",
"name": "string",
"org_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"primary_code": "string",
"primary_standard_code": "en10027-1",
"primary_standard_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"successor_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"updated_at": "2026-06-01T12:00:00Z",
"urn": "string"
},
"override": {
"attributes": {},
"created_at": "2026-06-01T12:00:00Z",
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"internal_code": "string",
"material_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"notes": "string",
"org_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"trade_name": "string",
"updated_at": "2026-06-01T12:00:00Z",
"urn": "string"
},
"pricing": {
"default_basis": "category",
"default_basis_key": "other",
"default_currency": "EUR",
"default_price_per_kg": 0,
"environments": [
{
"currency": "EUR",
"env_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"env_name": "string",
"env_region": "string",
"price_per_kg": 0,
"source": "env_rate",
"valid_from": "2026-06-01",
"valid_to": "2026-06-01"
}
]
}
}
Upsert Grade Override
PUT /api/v1/materials/grades/{grade_id}/override
Upsert your organization's master-data layer for a grade.
Creates the org's override row for the grade when none exists,
otherwise updates it in place. Identification fields
(internal_code, trade_name, notes) follow patch
semantics — only keys present in the body are touched, null
clears. properties is validated against the closed vocabulary
(yield_mpa, tensile_mpa, hardness_hb, elongation_pct; sanity-ranged);
a numeric value overrides the catalogue figure, null clears your
override so the catalogue figure applies again.
Property overrides are quoting/display master data — they do NOT change the physics inputs (density, ISO 513 group stay canonical) and they do NOT change €/kg (that lives in the environment rates).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
grade_id |
path | string | yes | Identifier of the grade. |
Request body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
internal_code |
string | no | Org-internal SKU / part code for this material; null clears it. |
notes |
string | no | Free-text notes attached to this material by the organization; null clears them. |
properties |
object | no | Property overrides keyed by the closed vocabulary (yield_mpa, tensile_mpa, hardness_hb, elongation_pct). A numeric value overrides the catalogue figure; null clears your override so the catalogue figure applies again. Keys not mentioned are left unchanged. |
trade_name |
string | no | Vendor trade name (e.g. 'Inconel 718'); null clears it. |
Request
curl -X PUT https://api.arcnm.io/api/v1/materials/grades/{grade_id}/override \
-H "X-API-Key: $ARCNM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"internal_code": "string",
"notes": "string",
"properties": {},
"trade_name": "string"
}'
import requests
resp = requests.put(
"https://api.arcnm.io/api/v1/materials/grades/{grade_id}/override",
headers={"X-API-Key": "YOUR_API_KEY"},
json={
"internal_code": "string",
"notes": "string",
"properties": {},
"trade_name": "string"
},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/materials/grades/{grade_id}/override", {
method: "PUT",
headers: {
"X-API-Key": process.env.ARCNM_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"internal_code": "string",
"notes": "string",
"properties": {},
"trade_name": "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 attached to this material by the organization. |
created_at |
string | Timestamp when the override was created. |
id |
string | Unique identifier of the override. |
internal_code |
string | Org-internal SKU / part code for this material. |
material_grade_id |
string | Identifier of the canonical grade this override extends; null when fully org-private. |
notes |
string | Free-text notes attached to this material by the organization. |
org_id |
string | Identifier of the organization that owns this override. |
trade_name |
string | Vendor trade name (e.g. 'Inconel 718'). |
updated_at |
string | Timestamp when the override was last updated. |
urn |
string | Canonical or org-private URN identifying the material. |
Example response
{
"attributes": {},
"created_at": "2026-06-01T12:00:00Z",
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"internal_code": "string",
"material_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"notes": "string",
"org_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"trade_name": "string",
"updated_at": "2026-06-01T12:00:00Z",
"urn": "string"
}
Get Grade By Urn
GET /api/v1/materials/grades/by-urn/{urn}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
urn |
path | string | yes | Material grade URN to resolve (e.g. urn:material:cen:1.4301). |
Request
curl -X GET https://api.arcnm.io/api/v1/materials/grades/by-urn/{urn} \
-H "X-API-Key: $ARCNM_API_KEY"
import requests
resp = requests.get(
"https://api.arcnm.io/api/v1/materials/grades/by-urn/{urn}",
headers={"X-API-Key": "YOUR_API_KEY"},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/materials/grades/by-urn/{urn}", {
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 |
|---|---|---|
aliases |
MaterialGradeAliasPublic[] | Cross-references mapping this grade's code across other standards and trade names. |
attributes |
object | Free-form key/value metadata for extra mechanical and physical properties. |
category |
carbon_steel | alloy_steel | stainless_steel | tool_steel | cast_iron | aluminium | copper_alloy | nickel_alloy | titanium_alloy | magnesium_alloy | zinc_alloy | thermoplastic | thermoset | elastomer | composite | other |
Broad material family the grade belongs to (e.g. steel, aluminium, polymer). |
created_at |
string | Timestamp when the grade record was created. |
density_kg_per_m3 |
number | Material density in kilograms per cubic metre. |
id |
string | Unique identifier of the material grade. |
is_active |
boolean | Whether the grade is currently active and selectable; false when retired. |
iso_machining_group |
P | M | K | N | S | H |
ISO 513 machining group (P/M/K/N/S/H) used to gauge machinability. |
name |
string | Human-readable name of the material grade. |
org_id |
string | Null → platform-catalogue grade shared by every organization; set → this organization's private grade. |
primary_code |
string | Standards-compliant cased display code; the same value as display_code. |
primary_standard_code |
en10027-1 | en10027-2 | en10025 | en10083 | en10084 | en10088 | en10346 | en-iso-4957 | en573-1 | en573-2 | en1412 | din17007 | en1560 | en1561 | en1563 | iso1043-1 | iso1043-2 | iso18064 | uns | aisi-sae | jis | astm | eclass | unspsc | org |
URN-safe code of the primary standard (en10027-2, iso1043-1, …). Hydrated by the routes layer so frontends can render a badge without a second round-trip. |
primary_standard_id |
string | Identifier of the standard that defines this grade's primary code. |
successor_grade_id |
string | Identifier of the grade that supersedes this one; null when still current. |
updated_at |
string | Timestamp when the grade record was last updated. |
urn |
string | Canonical URN that uniquely and stably identifies this grade across systems. |
Example response
{
"aliases": [
{
"code": "string",
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"is_canonical": false,
"is_preferred_display": true,
"material_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"standard_code": "en10027-1",
"standard_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
],
"attributes": {},
"category": "carbon_steel",
"created_at": "2026-06-01T12:00:00Z",
"density_kg_per_m3": 0,
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"is_active": true,
"iso_machining_group": "P",
"name": "string",
"org_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"primary_code": "string",
"primary_standard_code": "en10027-1",
"primary_standard_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"successor_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"updated_at": "2026-06-01T12:00:00Z",
"urn": "string"
}
Lookup
POST /api/v1/materials/lookup
Exact resolve of a material reference to a single canonical grade.
On a near-miss this still 404s (back-compat), but the error now carries
up to five ranked candidates in its details so a caller can pick
and retry without a second call. For a fuzzy 'did you mean' list that never
dead-ends, use POST /materials/suggest instead.
Request body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
query |
string | yes | URN, EN/UNS/AISI/JIS code, trade name, or org internal code. |
standard |
en10027-1 | en10027-2 | en10025 | en10083 | en10084 | en10088 | en10346 | en-iso-4957 | en573-1 | en573-2 | en1412 | din17007 | en1560 | en1561 | en1563 | iso1043-1 | iso1043-2 | iso18064 | uns | aisi-sae | jis | astm | eclass | unspsc | org |
no | Optional hint — restrict alias search to this standard. |
Request
curl -X POST https://api.arcnm.io/api/v1/materials/lookup \
-H "X-API-Key: $ARCNM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "string"
}'
import requests
resp = requests.post(
"https://api.arcnm.io/api/v1/materials/lookup",
headers={"X-API-Key": "YOUR_API_KEY"},
json={
"query": "string"
},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/materials/lookup", {
method: "POST",
headers: {
"X-API-Key": process.env.ARCNM_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"query": "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 |
|---|---|---|
grade |
MaterialGradePublic | The canonical material grade the query resolved to. |
matched_via |
urn | legacy_urn | primary_code | alias | org_override | org_private |
Path the resolver used: urn |
standard_used |
en10027-1 | en10027-2 | en10025 | en10083 | en10084 | en10088 | en10346 | en-iso-4957 | en573-1 | en573-2 | en1412 | din17007 | en1560 | en1561 | en1563 | iso1043-1 | iso1043-2 | iso18064 | uns | aisi-sae | jis | astm | eclass | unspsc | org |
Material standard the match resolved against; null if not standard-specific. |
Example response
{
"grade": {
"aliases": [
{
"code": "string",
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"is_canonical": false,
"is_preferred_display": true,
"material_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"standard_code": "en10027-1",
"standard_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
],
"attributes": {},
"category": "carbon_steel",
"created_at": "2026-06-01T12:00:00Z",
"density_kg_per_m3": 0,
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"is_active": true,
"iso_machining_group": "P",
"name": "string",
"org_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"primary_code": "string",
"primary_standard_code": "en10027-1",
"primary_standard_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"successor_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"updated_at": "2026-06-01T12:00:00Z",
"urn": "string"
},
"matched_via": "urn",
"standard_used": "en10027-1"
}
Lookup Batch
POST /api/v1/materials/lookup/batch
Bulk-resolve up to 100 queries in one round-trip.
Drawing analysis emits N candidate strings per part; the worker
and the frontend typeahead both call this endpoint instead of N
individual /lookup requests. Misses are returned in-band with
result=null so callers can correlate hits/misses by position.
Request body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
queries |
string[] | yes | Material query strings to resolve in one round-trip (1–100). |
standard |
en10027-1 | en10027-2 | en10025 | en10083 | en10084 | en10088 | en10346 | en-iso-4957 | en573-1 | en573-2 | en1412 | din17007 | en1560 | en1561 | en1563 | iso1043-1 | iso1043-2 | iso18064 | uns | aisi-sae | jis | astm | eclass | unspsc | org |
no | Optional hint applied to every query in the batch. |
Request
curl -X POST https://api.arcnm.io/api/v1/materials/lookup/batch \
-H "X-API-Key: $ARCNM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"queries": [
"string"
]
}'
import requests
resp = requests.post(
"https://api.arcnm.io/api/v1/materials/lookup/batch",
headers={"X-API-Key": "YOUR_API_KEY"},
json={
"queries": [
"string"
]
},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/materials/lookup/batch", {
method: "POST",
headers: {
"X-API-Key": process.env.ARCNM_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"queries": [
"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 |
|---|---|---|
entries |
MaterialLookupBatchEntry[] | One result slot per query, in the order the queries were supplied. |
matched_count |
integer | Number of queries in the batch that resolved to a grade. |
miss_count |
integer | Number of queries in the batch that did not resolve. |
Example response
{
"entries": [
{
"query": "string",
"result": {
"grade": {},
"matched_via": "urn",
"standard_used": "en10027-1"
}
}
],
"matched_count": 0,
"miss_count": 0
}
List Overrides
GET /api/v1/materials/overrides
Request
curl -X GET https://api.arcnm.io/api/v1/materials/overrides \
-H "X-API-Key: $ARCNM_API_KEY"
import requests
resp = requests.get(
"https://api.arcnm.io/api/v1/materials/overrides",
headers={"X-API-Key": "YOUR_API_KEY"},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/materials/overrides", {
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. |
Create Override
POST /api/v1/materials/overrides
Request body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
attributes |
object | no | Free-form key/value metadata attached to this material by the organization. |
internal_code |
string | no | Org-internal SKU / part code for this material. |
material_grade_id |
string | no | Canonical grade this override extends. NULL → fully org-private material not in the global catalogue (requires urn populated). |
notes |
string | no | Free-text notes attached to this material by the organization. |
trade_name |
string | no | Vendor trade name (e.g. 'Inconel 718'). |
urn |
string | no | Canonical or org-private URN (urn:arc:mat:…:…). |
Request
curl -X POST https://api.arcnm.io/api/v1/materials/overrides \
-H "X-API-Key: $ARCNM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"attributes": {},
"internal_code": "string",
"material_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"notes": "string",
"trade_name": "string",
"urn": "string"
}'
import requests
resp = requests.post(
"https://api.arcnm.io/api/v1/materials/overrides",
headers={"X-API-Key": "YOUR_API_KEY"},
json={
"attributes": {},
"internal_code": "string",
"material_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"notes": "string",
"trade_name": "string",
"urn": "string"
},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/materials/overrides", {
method: "POST",
headers: {
"X-API-Key": process.env.ARCNM_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"attributes": {},
"internal_code": "string",
"material_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"notes": "string",
"trade_name": "string",
"urn": "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. |
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 attached to this material by the organization. |
created_at |
string | Timestamp when the override was created. |
id |
string | Unique identifier of the override. |
internal_code |
string | Org-internal SKU / part code for this material. |
material_grade_id |
string | Identifier of the canonical grade this override extends; null when fully org-private. |
notes |
string | Free-text notes attached to this material by the organization. |
org_id |
string | Identifier of the organization that owns this override. |
trade_name |
string | Vendor trade name (e.g. 'Inconel 718'). |
updated_at |
string | Timestamp when the override was last updated. |
urn |
string | Canonical or org-private URN identifying the material. |
Example response
{
"attributes": {},
"created_at": "2026-06-01T12:00:00Z",
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"internal_code": "string",
"material_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"notes": "string",
"org_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"trade_name": "string",
"updated_at": "2026-06-01T12:00:00Z",
"urn": "string"
}
Delete Override
DELETE /api/v1/materials/overrides/{override_id}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
override_id |
path | string | yes | Identifier of the override. |
Request
curl -X DELETE https://api.arcnm.io/api/v1/materials/overrides/{override_id} \
-H "X-API-Key: $ARCNM_API_KEY"
import requests
resp = requests.delete(
"https://api.arcnm.io/api/v1/materials/overrides/{override_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/materials/overrides/{override_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"
}
Update Override
PATCH /api/v1/materials/overrides/{override_id}
Partial update. Only fields explicitly present in the body are
applied — pass null to clear a field, omit to leave unchanged.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
override_id |
path | string | yes | Identifier of the override. |
Request body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
attributes |
object | no | Free-form key/value metadata attached to this material by the organization. |
internal_code |
string | no | Org-internal SKU or part code for this material. |
material_grade_id |
string | no | Identifier of the canonical grade this override extends; null when fully org-private. |
notes |
string | no | Free-text notes attached to this material by the organization. |
trade_name |
string | no | Vendor trade name for this material (e.g. 'Inconel 718'). |
urn |
string | no | Canonical or org-private URN identifying the material. |
Request
curl -X PATCH https://api.arcnm.io/api/v1/materials/overrides/{override_id} \
-H "X-API-Key: $ARCNM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"attributes": {},
"internal_code": "string",
"material_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"notes": "string",
"trade_name": "string",
"urn": "string"
}'
import requests
resp = requests.patch(
"https://api.arcnm.io/api/v1/materials/overrides/{override_id}",
headers={"X-API-Key": "YOUR_API_KEY"},
json={
"attributes": {},
"internal_code": "string",
"material_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"notes": "string",
"trade_name": "string",
"urn": "string"
},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/materials/overrides/{override_id}", {
method: "PATCH",
headers: {
"X-API-Key": process.env.ARCNM_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"attributes": {},
"internal_code": "string",
"material_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"notes": "string",
"trade_name": "string",
"urn": "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 attached to this material by the organization. |
created_at |
string | Timestamp when the override was created. |
id |
string | Unique identifier of the override. |
internal_code |
string | Org-internal SKU / part code for this material. |
material_grade_id |
string | Identifier of the canonical grade this override extends; null when fully org-private. |
notes |
string | Free-text notes attached to this material by the organization. |
org_id |
string | Identifier of the organization that owns this override. |
trade_name |
string | Vendor trade name (e.g. 'Inconel 718'). |
updated_at |
string | Timestamp when the override was last updated. |
urn |
string | Canonical or org-private URN identifying the material. |
Example response
{
"attributes": {},
"created_at": "2026-06-01T12:00:00Z",
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"internal_code": "string",
"material_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"notes": "string",
"org_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"trade_name": "string",
"updated_at": "2026-06-01T12:00:00Z",
"urn": "string"
}
Pricing Coverage
GET /api/v1/materials/pricing-coverage
What every grade costs, and which environments set that price.
One round-trip for the master-data list: entries carries the €/kg
of each grade an environment has its own rate for, and defaults
carries the platform price per category that every other grade is
charged at. Uses the same effective-dating / currency predicates as
the calculation path, so the prices shown can never disagree with the
price actually charged.
Request
curl -X GET https://api.arcnm.io/api/v1/materials/pricing-coverage \
-H "X-API-Key: $ARCNM_API_KEY"
import requests
resp = requests.get(
"https://api.arcnm.io/api/v1/materials/pricing-coverage",
headers={"X-API-Key": "YOUR_API_KEY"},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/materials/pricing-coverage", {
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 |
|---|---|---|
defaults |
MaterialCategoryDefaultPrice[] | The platform price per kilogram for every material category — what a grade costs wherever no environment rate applies. |
entries |
MaterialPricingCoverageEntry[] | One entry per grade that has at least one active environment rate. |
environments |
MaterialCoverageEnvironment[] | Your organization's costing environments. |
Example response
{
"defaults": [
{
"basis": "category",
"basis_key": "string",
"category": "carbon_steel",
"currency": "EUR",
"price_per_kg": 0
}
],
"entries": [
{
"grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"priced_env_ids": [
"3fa85f64-5717-4562-b3fc-2c963f66afa6"
],
"prices": [
{}
]
}
],
"environments": [
{
"currency": "EUR",
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"name": "string"
}
]
}
List Standards
GET /api/v1/materials/standards
Request
curl -X GET https://api.arcnm.io/api/v1/materials/standards \
-H "X-API-Key: $ARCNM_API_KEY"
import requests
resp = requests.get(
"https://api.arcnm.io/api/v1/materials/standards",
headers={"X-API-Key": "YOUR_API_KEY"},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/materials/standards", {
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. |
Suggest
POST /api/v1/materials/suggest
Fuzzy material lookup that never dead-ends on a 404.
Resolves an exact canonical grade when the query is unambiguous, and
ALWAYS returns ranked candidates — so a partial code ('S3040'), a trade
name, or a generic term ('Stahl', 'stainless') gets a 'did you mean' list
to pick from. Pass a candidate's urn back as material_ref to price
against it.
Request body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
category |
carbon_steel | alloy_steel | stainless_steel | tool_steel | cast_iron | aluminium | copper_alloy | nickel_alloy | titanium_alloy | magnesium_alloy | zinc_alloy | thermoplastic | thermoset | elastomer | composite | other |
no | Optional category filter for the candidates. |
limit |
integer | no | Maximum ranked candidates to return. |
query |
string | yes | Free-form material text: a code, partial code, trade name, or generic term. |
standard |
en10027-1 | en10027-2 | en10025 | en10083 | en10084 | en10088 | en10346 | en-iso-4957 | en573-1 | en573-2 | en1412 | din17007 | en1560 | en1561 | en1563 | iso1043-1 | iso1043-2 | iso18064 | uns | aisi-sae | jis | astm | eclass | unspsc | org |
no | Optional standard hint applied to the exact-match pass. |
Request
curl -X POST https://api.arcnm.io/api/v1/materials/suggest \
-H "X-API-Key: $ARCNM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "string"
}'
import requests
resp = requests.post(
"https://api.arcnm.io/api/v1/materials/suggest",
headers={"X-API-Key": "YOUR_API_KEY"},
json={
"query": "string"
},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/materials/suggest", {
method: "POST",
headers: {
"X-API-Key": process.env.ARCNM_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"query": "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 |
|---|---|---|
candidates |
MaterialCandidate[] | Ranked near-matches, best first; empty only when nothing in the catalogue is close. |
query |
string | The query string, echoed back. |
resolved |
MaterialLookupResult | The exact canonical grade when the query resolves unambiguously; null on a fuzzy-only match. |
Example response
{
"candidates": [
{
"category": "carbon_steel",
"grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"matched_on": "string",
"name": "string",
"primary_code": "string",
"score": 0,
"urn": "string"
}
],
"query": "string",
"resolved": {
"grade": {
"aliases": [
{}
],
"attributes": {},
"category": "carbon_steel",
"created_at": "2026-06-01T12:00:00Z",
"density_kg_per_m3": 0,
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"is_active": true,
"iso_machining_group": "P",
"name": "string",
"org_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"primary_code": "string",
"primary_standard_code": "en10027-1",
"primary_standard_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"successor_grade_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"updated_at": "2026-06-01T12:00:00Z",
"urn": "string"
},
"matched_via": "urn",
"standard_used": "en10027-1"
}
}