Concepts
Materials & overrides
Resolve any material reference to a canonical grade, then override the catalogue per tenant so every quote lands on the metal you actually buy, at your price.
Material is one of the largest line items in a machined part, so every quote has to land on the grade you actually buy — not a generic "steel". ARCNM ships a canonical catalogue of material grades and a resolver that maps your references — Werkstoffnummer, AISI/SAE code, trade name, or your own SKU — onto it.
There are three layers:
- The platform catalogue — a read-only set of canonical grades (1.4301, AISI 304, Ti-6Al-4V, …), each with a density, ISO machining group, and a stable URN. Shared by every tenant.
- Your custom grades — grades you register for materials the catalogue doesn't carry. First-class rows with their own URN, density and ISO group: selectable, resolvable and priceable exactly like catalogue grades, visible only to your organization.
- Your overrides — per-tenant rows that map an internal code or trade name onto a grade (canonical or custom).
Discover a grade
Resolve the material you mean before you quote. Three read paths, all
on the parts:read scope.
Search the catalogue
GET /api/v1/materials/grades searches across primary code,
display code, name, URN, and every alias — so AISI 304, SUS304,
and S30400 all return 1.4301. Filter by category or iso_group,
and page with limit / offset.
curl "https://api.arcnm.io/api/v1/materials/grades?q=AISI%20304&limit=5" \
-H "X-API-Key: $ARCNM_API_KEY"
# → { "count": 1, "data": [ { "id": "…", "urn": "urn:material:din:1.4301",
# "primary_code": "1.4301", "name": "X5CrNi18-10", "iso_machining_group": "P", … } ] }
Resolve a single reference
When you have one string from a drawing or an ERP export, POST /api/v1/materials/lookup returns the best canonical match (or
404 if nothing matches). Resolve a whole drawing's worth of candidates
in one round-trip with POST .../lookup/batch (up to 100; misses come
back in-band so you can correlate by position).
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": "1.4301" }'
Fetch by id or URN
GET .../grades/{grade_id} and GET .../grades/by-urn/{urn} return the
full grade with its aliases. GET .../materials/standards lists the
standards bodies (DIN, AISI, …) the catalogue is keyed against.
Use a material in a calculation
Hand ARCNM either reference when you quote — the typed
material_grade_id (from a lookup) or a free-form material_ref:
{
"part_revision_id": "1f…",
"costing_environment_id": "env_2a…",
"material_ref": "1.4301"
}
material_grade_id wins if both are supplied. A reference that can't be
resolved comes back as material_unresolved
(422) — resolve it with /lookup first, or add an override.
Register a custom grade
When you buy a material the platform catalogue doesn't carry, register
your own grade (parts:write). It behaves exactly like a catalogue
grade — selectable, resolvable, priceable per environment — but stays
private to your organization:
POST /api/v1/materials/grades
{
"category": "carbon_steel",
"designation": "WS-42-Blank",
"name": "Works standard 42 bright steel",
"iso_machining_group": "P",
"density_kg_per_m3": 7850
}
Density and the ISO 513 group are required — they are what makes the
grade priceable. The response carries the grade's stable URN
(urn:arc:mat:carbon_steel:org:ws-42-blank): pass it (or the
material_grade_id) to any calculation, and set a €/kg for it through
the environment rates API like any other grade. A designation that
already resolves to a catalogue grade is refused with 409 — use the
canonical grade, or map an override onto it. Update with
PATCH .../grades/{id} (designation and category are immutable);
delete is refused while prices or calculations still reference the
grade — deactivate it with {"is_active": false} instead.
Override the catalogue
When your shop floor calls a grade by an internal code, create an
override (parts:write):
- Map an internal code → a grade. Your
INOX-A2resolves to 1.4301 for everyone on the org. Works for canonical and custom grades alike.
POST /api/v1/materials/overrides
{
"material_grade_id": "…",
"internal_code": "INOX-A2",
"trade_name": "Acme Stainless A2"
}
List, patch, and delete them under .../materials/overrides. Once
created, your codes resolve through /lookup and on every
material_ref you pass to a calculation. (A legacy URN-only override —
one with no material_grade_id — still resolves for display, but only
a registered grade can price a calculation.)
Material master data — properties, provenance, pricing
Every grade is a master record with three layers, resolved in this order (the same split an ERP material master makes between client-level basic data and plant-level views):
- Catalogue figures — each canonical grade ships with reference
mechanical properties for the common stock delivery condition:
yield_mpa(min yield Rp0.2/ReH),tensile_mpa(min tensile Rm),hardness_hb(Brinell, delivery condition),elongation_pct(min elongation A). They are reference values from the issuing standards; supplier certificates remain the source of truth for a given lot. - Your values — override any property per grade; your value wins and the response still carries the shadowed catalogue figure.
- €/kg per environment — prices live in the environment rate tables. When no rate row exists for a grade, a platform default applies (per material family); the master record shows which.
GET /api/v1/materials/grades/{grade_id}/master
{
"grade": { "primary_code": "1.4301", … },
"override": { "internal_code": "INOX-A2", … },
"effective_properties": [
{ "key": "yield_mpa", "value": 210.0, "unit": "MPa",
"source": "org", "canonical_value": 190.0 },
{ "key": "tensile_mpa", "value": 500.0, "unit": "MPa",
"source": "canonical" }
],
"pricing": {
"default_price_per_kg": 4.0,
"environments": [
{ "env_name": "Werk Süd", "price_per_kg": 4.35,
"source": "env_rate", "valid_from": "2026-01-01" },
{ "env_name": "Sandbox", "price_per_kg": 4.0,
"source": "platform_default" }
]
}
}
Set your layer with a single upsert (parts:write) — patch semantics,
null clears a value back to the catalogue figure:
PUT /api/v1/materials/grades/{grade_id}/override
{
"internal_code": "INOX-A2",
"properties": { "yield_mpa": 210, "hardness_hb": null }
}
Property overrides do not change €/kg — set prices through the
environment rates API. GET /api/v1/materials/pricing-coverage returns,
in one call, which grades carry an environment rate and where — anything
absent prices at the platform default.
They do reach the costing engine. A property is either read by a named part of the engine or explicitly declared display-only, and the API says which per key:
GET /api/v1/materials/attribute-vocabulary
[
{ "key": "tensile_mpa", "unit": "MPa", "scope": "grade",
"basis": "minimum", "display_only": false,
"consumer": "physics.handlers.press_brake — the air-bend force screen …" },
{ "key": "charpy_j_m20c", "unit": "J", "scope": "grade",
"basis": "minimum", "display_only": true,
"consumer": "display-only: impact toughness is what the EN 10025 subgrade letters encode …" }
]
scope is grade for the per-grade vocabulary you can override, and
group for the keys the workpiece-material group states and every grade
on it inherits (thermal figures, sheet-forming parameters, the
laser_cuttable / weldability_class / heat_treatable route gates).
The same consumer statement rides on each entry of
effective_properties, so a value that moves no number says so where it
is read. Density and the workpiece group stay typed columns on the grade
record — they are not part of this vocabulary.
See also
- API → Materials — every field, filter, and override route.
- Concepts → Cost & lot-size — where material mass lands in the price.
- Recipe → ERP integration — feed your ERP's material codes in.