ARCNM

Recipes

Recipe — cut a job nest

Take a job nest's sheets to the cutting machine over the API: DXF or SVG per sheet, a zip of them all, and the JSON nest plan an integration reads sheets from.

A job nest lays a backlog of sheet-metal parts out on shared sheets. This recipe takes those sheets to the machine over the API — and the sheet a single calculation's own price laid its part out on the same way — so a CAM system, an MES or an agent can do it without the dashboard.

Every export reads parts:read. Nothing here changes a calculation's price or a job nest's result: an export is a read of what was stored.


1. Export a job nest's sheets

GET /nest-runs/{run_id}/export writes the sheets of every solved material and thickness of the job nest. Each distinct layout is one sheet; the manifest and the plan say how many identical sheets it stands for.

Query Values What you get
format dxf (default), svg, json DXF or SVG per sheet, or the JSON nest plan
sheet all (default), or one key <group>:<index> every sheet — a zip (DXF/SVG) or the whole plan (JSON) — or that one sheet's file
exploded false (default), true DXF only: plain closed polylines in place, no block references
revision omitted (the active revision), or a number the sheets as laid out in that revision of every material and thickness — 1 is the job nest's own layout; every adjustment posted through POST /nest-runs/{run_id}/groups/{group_id}/revisions is the next
# every sheet as DXF: a zip with plan.json and manifest.csv
curl -o nest.zip \
  "https://api.arcnm.io/api/v1/nest-runs/$RUN_ID/export?format=dxf" \
  -H "X-API-Key: $ARCNM_API_KEY"

# one sheet, for a machine that reads no blocks
curl -o sheet-0-0.dxf \
  "https://api.arcnm.io/api/v1/nest-runs/$RUN_ID/export?format=dxf&sheet=0:0&exploded=true" \
  -H "X-API-Key: $ARCNM_API_KEY"
import requests

resp = requests.get(
    f"https://api.arcnm.io/api/v1/nest-runs/{run_id}/export",
    params={"format": "json"},
    headers={"X-API-Key": "YOUR_API_KEY"},
)
resp.raise_for_status()
plan = resp.json()
for sheet in plan["sheets"]:
    print(sheet["key"], sheet["repeat"], "x", sheet["container"]["key"], sheet["count"], "parts")
const resp = await fetch(
  `https://api.arcnm.io/api/v1/nest-runs/${runId}/export?format=svg&sheet=0:0`,
  { headers: { "X-API-Key": process.env.ARCNM_API_KEY! } },
)
const svg = await resp.text()

The file name travels in Content-Disposition (nest-run-<run id>-sheet-<group>-<index>.dxf, nest-run-<run id>-dxf.zip, an exploded DXF nest-run-<run id>-dxf-exploded.zip, nest-run-<run id>-plan.json). A job nest that is still running exports what is solved so far; one with nothing solved yet answers nest_run_nothing_to_export (409), a sheet key it has not nest_run_sheet_not_found (404) — see Errors.

2. Export a calculation's own sheet

GET /calculations/{calculation_id}/sheet-nest/export writes the sheet the calculation's own price laid its part out on — the part alone, as many copies as its price put on one sheet. It takes format and exploded as above; there is one sheet, so no sheet and no zip. A calculation that stored no sheet layout answers sheet_layout_not_found (404).

3. The DXF

  • R2010, $INSUNITS 4: every coordinate is a millimetre. The sheet's origin is a corner, x along the sheet's length, y across its width.
  • Layers: SHEET (the sheet's rectangle), MARGIN (the usable area, dashed), REMNANT (the reusable rest the sheet leaves, when it does), CUT_OUTER (outer contours), CUT_INNER (holes), LABEL (the part reference and order reference at each copy, and the sheet's title).
  • One block per part, one insert per copy. The block PART_P1 holds the part's contour and holes as closed lightweight polylines in the part's own frame. Each INSERT places one copy: a mirrored copy is reflected across the part's own x axis (yscale −1), then turned counter-clockwise by rotation, then set at insert.
  • exploded=true writes each copy's contours as closed polylines in place, all in the world coordinate system, and no blocks — for a cutting system that does not read block references, or reads a reflected one in its own coordinate system.
  • What the drawing says about itself: the header's custom properties (NEST_RUN_ID or NEST_CALCULATION_ID, NEST_SHEET, NEST_SHEETS_TO_CUT, NEST_MATERIAL, NEST_GAUGE_MM, NEST_CONTAINER, NEST_SHEET_MM, NEST_PARTS, NEST_UTILISATION, NEST_TOLERANCE) and a title above the sheet state the same.
  • Tolerance: contours are within 0.2 mm of the unfolded flat pattern; arcs are polylines. Check a contour against the part's drawing before the first cut, as you would any nest.

4. The SVG

The same geometry, viewBox in millimetres, y up inside the sheet group (a translate and scale(1 -1)), each DXF layer a <g> of that class. Every outer contour carries data-part, data-line and data-order, so a viewer can name what it shows.

5. The JSON nest plan (schema v1)

The plan is the export as data: what the DXF draws, readable by an integration that lays the parts out itself or checks a file.

{
  "v": 1,
  "units": "mm",
  "source": {"kind": "run", "run_id": "…", "environment_id": "…", "created_at": "…", "finished_at": "…"},
  "tolerance": {"contour_mm": 0.2, "arcs": "polylines", "note": "Contours within 0.2 mm of the unfolded flat pattern; arcs as polylines."},
  "parts": [
    {
      "ref": "P1",
      "name": "bracket",
      "line_id": "…",
      "calculation_id": "…",
      "order_ref": "4711",
      "quantity": 12,
      "placed": 12,
      "net_area_mm2": 21840.5,
      "outline": [[0, 0], [300, 0], [300, 120], [0, 120]],
      "holes": [[[40, 40], [80, 40], [80, 80], [40, 80]]]
    }
  ],
  "sheets": [
    {
      "key": "0:0",
      "index": 0,
      "group": 0,
      "repeat": 2,
      "container": {"kind": "format", "key": "3000 x 1500", "length_mm": 3000, "width_mm": 1500},
      "material": "S235JR",
      "gauge_mm": 3,
      "margin_mm": 10,
      "spacing_mm": 5,
      "count": 17,
      "utilisation": 0.71,
      "remnant": {"x_mm": 2100, "y_mm": 0, "length_mm": 900, "width_mm": 1500},
      "placements": [
        {"part": "P1", "line_id": "…", "order_ref": "4711", "x": 10, "y": 10, "rot_deg": 90, "mirrored": false}
      ]
    }
  ]
}
Field Meaning
v, units The schema version (1) and the unit of every length (mm).
source What the plan is of: kind run (with run_id, environment_id, created_at, finished_at) or calculation (with calculation_id).
tolerance What the contours are good to.
parts[] One per job-nest line (or the one part): ref names it in placements and in the DXF block PART_<ref>; outline runs counter-clockwise, each ring of holes clockwise, in the part's own frame; quantity copies ordered, placed on the sheets; line_id re-enters a quote as nest_item_id.
sheets[] key names the sheet in sheet= and in file names (<group>:<index>; 0 for a calculation's sheet); group the material and thickness it belongs to; repeat identical sheets it stands for; container what it is cut from (format or remnant, the key you stated, its size); material, gauge_mm; margin_mm and spacing_mm every copy keeps; count copies on the sheet; utilisation their net area over the sheet's; remnant the reusable rest, when one is left.
placements[] One per copy: part, and where it sits — mirrored across its own x axis first when mirrored, then turned rot_deg counter-clockwise about its origin, then set at (x, y).

A placement's contour on the sheet is therefore, for each point (px, py) of the part's outline: flip py when mirrored, rotate by rot_deg, add (x, y). That is exactly the DXF insert's transform.

6. Labels for the rests

Once the job nest is released (PATCH /nest-runs/{run_id} with counts_toward_savings: true), the reusable rests its sheets leave are remnants of the environment. Print their rack labels in one go:

curl -o rests.svg \
  "https://api.arcnm.io/api/v1/nest-runs/$RUN_ID/remnant-labels?lang=de" \
  -H "X-API-Key: $ARCNM_API_KEY"

One SVG, one label per rest, sized in millimetres (100 × 50 mm each) — print at 100 %. Each label carries the size, thickness, material, pieces, origin and date, and a Code 128 barcode of the piece's code, the first 12 hex digits of its id. A single piece's label is GET /remnants/{remnant_id}/label. When the piece comes off the rack, the scanner's reading finds it again in any state:

curl "https://api.arcnm.io/api/v1/remnants/by-code/3F9A0C12B7D4" \
  -H "X-API-Key: $ARCNM_API_KEY"

404 nest_run_no_rests says the job nest put nothing into stock — not released yet, no reusable rest, or an environment that does not credit remnants (then a release books no stock at all).

7. From an agent

The MCP tools arcnm_nest_run_export and arcnm_sheet_nest_export answer the plan inline for format="json" (past 256 KB, without the contours) and, for DXF and SVG, each sheet's download link — the same routes as above, to fetch with the API key. See MCP for agents.