API reference
Subcontractors
The Subcontractors API manages the suppliers a part can be bought from: create, list, update, and delete them, and suppress or restore individual presets.
The Subcontractors API manages the suppliers a part can be bought from: create, list, update, and delete them, and suppress or restore individual presets.
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 Subcontractors
GET /api/v1/subcontractors
Your organization's subcontractors, name order — the platform
presets (hardening, plating, galvanizing, anodizing, painting,
marking; preset_key set) and your own.
Request
curl -X GET https://api.arcnm.io/api/v1/subcontractors \
-H "X-API-Key: $ARCNM_API_KEY"
import requests
resp = requests.get(
"https://api.arcnm.io/api/v1/subcontractors",
headers={"X-API-Key": "YOUR_API_KEY"},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/subcontractors", {
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 Subcontractor
POST /api/v1/subcontractors
Add a subcontractor to your organization.
lead_time_days is stored for planning surfaces; prices are
unaffected. Capabilities say which external operations this shop
offers — a costing environment that prices an operation none of its
member subcontractors offer carries a subcontract_unsourced note
on the result (never a veto).
Request body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
capabilities |
SubcontractorCapability[] | no | |
is_active |
boolean | no | Inactive subcontractors keep their history but stop counting as a source. |
lead_time_days |
integer | no | Typical door-to-door lead time. Stored for planning surfaces; prices are unaffected. |
name |
string | yes | The shop you order from. |
notes |
string | no | |
region |
string | no | Region / city, free text. |
Request
curl -X POST https://api.arcnm.io/api/v1/subcontractors \
-H "X-API-Key: $ARCNM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "string"
}'
import requests
resp = requests.post(
"https://api.arcnm.io/api/v1/subcontractors",
headers={"X-API-Key": "YOUR_API_KEY"},
json={
"name": "string"
},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/subcontractors", {
method: "POST",
headers: {
"X-API-Key": process.env.ARCNM_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"name": "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 |
|---|---|---|
capabilities |
SubcontractorCapability[] | |
created_at |
string | |
id |
string | |
is_active |
boolean | Inactive subcontractors keep their history but stop counting as a source. |
lead_time_days |
integer | Typical door-to-door lead time. Stored for planning surfaces; prices are unaffected. |
name |
string | The shop you order from. |
notes |
string | |
preset_key |
string | |
region |
string | Region / city, free text. |
updated_at |
string |
Example response
{
"capabilities": [
{
"lot_minimum_eur": 0,
"operation_kind": "string",
"order_fee_eur": 0,
"pricing_unit": "string"
}
],
"created_at": "2026-06-01T12:00:00Z",
"hidden": false,
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"is_active": true,
"lead_time_days": 0,
"name": "string",
"notes": "string",
"preset_key": "string",
"region": "EU",
"updated_at": "2026-06-01T12:00:00Z"
}
Delete Subcontractor
DELETE /api/v1/subcontractors/{sub_id}
Remove a subcontractor. Its environment memberships go with it; rate rows that named it keep their price and lose only the name (provenance FK is SET NULL — a price you entered stays a price).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
sub_id |
path | string | yes | Identifier of the sub. |
Request
curl -X DELETE https://api.arcnm.io/api/v1/subcontractors/{sub_id} \
-H "X-API-Key: $ARCNM_API_KEY"
import requests
resp = requests.delete(
"https://api.arcnm.io/api/v1/subcontractors/{sub_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/subcontractors/{sub_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 result of the operation. |
Example response
{
"message": "string"
}
Update Subcontractor
PATCH /api/v1/subcontractors/{sub_id}
Edit a subcontractor's identity, lead time, or capabilities.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
sub_id |
path | string | yes | Identifier of the sub. |
Request body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
capabilities |
SubcontractorCapability[] | no | |
is_active |
boolean | no | |
lead_time_days |
integer | no | |
name |
string | no | |
notes |
string | no | |
region |
string | no |
Request
curl -X PATCH https://api.arcnm.io/api/v1/subcontractors/{sub_id} \
-H "X-API-Key: $ARCNM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"capabilities": [
{
"lot_minimum_eur": 0,
"operation_kind": "string",
"order_fee_eur": 0,
"pricing_unit": "string"
}
],
"is_active": true,
"lead_time_days": 0,
"name": "string",
"notes": "string",
"region": "EU"
}'
import requests
resp = requests.patch(
"https://api.arcnm.io/api/v1/subcontractors/{sub_id}",
headers={"X-API-Key": "YOUR_API_KEY"},
json={
"capabilities": [
{
"lot_minimum_eur": 0,
"operation_kind": "string",
"order_fee_eur": 0,
"pricing_unit": "string"
}
],
"is_active": True,
"lead_time_days": 0,
"name": "string",
"notes": "string",
"region": "EU"
},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/subcontractors/{sub_id}", {
method: "PATCH",
headers: {
"X-API-Key": process.env.ARCNM_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"capabilities": [
{
"lot_minimum_eur": 0,
"operation_kind": "string",
"order_fee_eur": 0,
"pricing_unit": "string"
}
],
"is_active": true,
"lead_time_days": 0,
"name": "string",
"notes": "string",
"region": "EU"
}),
})
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 |
|---|---|---|
capabilities |
SubcontractorCapability[] | |
created_at |
string | |
hidden |
boolean | |
id |
string | |
is_active |
boolean | Inactive subcontractors keep their history but stop counting as a source. |
lead_time_days |
integer | Typical door-to-door lead time. Stored for planning surfaces; prices are unaffected. |
name |
string | The shop you order from. |
notes |
string | |
preset_key |
string | |
region |
string | Region / city, free text. |
updated_at |
string |
Example response
{
"capabilities": [
{
"lot_minimum_eur": 0,
"operation_kind": "string",
"order_fee_eur": 0,
"pricing_unit": "string"
}
],
"created_at": "2026-06-01T12:00:00Z",
"hidden": false,
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"is_active": true,
"lead_time_days": 0,
"name": "string",
"notes": "string",
"preset_key": "string",
"region": "EU",
"updated_at": "2026-06-01T12:00:00Z"
}
Unsuppress Subcontractor Preset
DELETE /api/v1/subcontractors/presets/{preset_key}/suppression
Show a hidden preset again — it rejoins the default environment (a new membership row; the closed one keeps its window).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
preset_key |
path | string | yes |
Request
curl -X DELETE https://api.arcnm.io/api/v1/subcontractors/presets/{preset_key}/suppression \
-H "X-API-Key: $ARCNM_API_KEY"
import requests
resp = requests.delete(
"https://api.arcnm.io/api/v1/subcontractors/presets/{preset_key}/suppression",
headers={"X-API-Key": "YOUR_API_KEY"},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/subcontractors/presets/{preset_key}/suppression", {
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 result of the operation. |
Example response
{
"message": "string"
}
Suppress Subcontractor Preset
POST /api/v1/subcontractors/presets/{preset_key}/suppression
Hide a platform subcontractor preset ("I don't buy this in"): it leaves the default environment (SCD2) and stays out of it until shown again or the platform set is restored. Your own subcontractors are deleted, not hidden.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
preset_key |
path | string | yes |
Request body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
reason |
string | no |
Request
curl -X POST https://api.arcnm.io/api/v1/subcontractors/presets/{preset_key}/suppression \
-H "X-API-Key: $ARCNM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"reason": "string"
}'
import requests
resp = requests.post(
"https://api.arcnm.io/api/v1/subcontractors/presets/{preset_key}/suppression",
headers={"X-API-Key": "YOUR_API_KEY"},
json={
"reason": "string"
},
)
resp.raise_for_status()
print(resp.json())
const resp = await fetch("https://api.arcnm.io/api/v1/subcontractors/presets/{preset_key}/suppression", {
method: "POST",
headers: {
"X-API-Key": process.env.ARCNM_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"reason": "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 |
|---|---|---|
message |
string | Human-readable result of the operation. |
Example response
{
"message": "string"
}