Skip to main content
FOR DEVELOPERS

CutOptim Engine API

A cutting-optimization API: send parts and stock — 2D panels, 1D bars, timber or true-shape nesting of irregular parts — and get back the layout, cut plan and yield. By default the same request always returns the same plan.

See the full benchmark → · Measured, not claimed

POST /v1/optimize/nest
{
  "parts": [
    { "name": "bracket", "polygon": […], "qty": 12, … },
    { "name": "gusset", "polygon": […], "qty": 14, … },
    { "name": "plate", "polygon": […], "holes": […], "qty": 12, … },
    { "name": "flange", "source": { … }, "qty": 10, … }
  ],
  "stock": [{ "w": 2500, "h": 1250, "exclusions": […], … }],
  "options": { "minSeparation": 5, "edgeClearance": 10 }
}
200 sheets[0] · 2500 × 1250
1 sheetCount48/48 placed0.5632 density110 pierces
A real call to POST /v1/optimize/nest — the request, and the sheet that came back, drawn from the coordinates in the response.

Why build on it

DETERMINISTIC

The same input always returns the same output — no randomness, no clock in the algorithm. You can cache results and diff them in tests. The one opt-in exception, the time-limited nesting max search, says so in every response (deterministic: false).

A REAL CUT PLAN

Not just rectangles: the guillotine cut sequence, cut lines vs. saw passes, sawn length, and a flag telling you whether it is producible on a panel saw.

PANEL-SAW AWARE

Kerf, per-side trim, tolerance, cost mode, grain direction and grain matching, max cutting stages, rotation minimising — the same options the app exposes.

Build it, or call it

A cutting optimizer looks like a weekend project and turns into a long tail of edge cases: kerf and trim arithmetic, stock that runs out, rotation and grain rules, layouts that must be sawable edge to edge, polygons with holes — and a regression suite that proves a change never makes a plan worse. The Engine API is that work, already done and measured.

WHAT YOU SKIP

Writing and validating four optimizers — 2D guillotine panels, 1D linear stock, timber by cross-section and true-shape nesting — and keeping them correct as your requirements grow. Your team integrates one HTTP contract instead.

WHAT YOU CAN CHECK

Plan quality is published, not claimed: the open benchmark runs the engine on public academic instance sets and generated jobs, with the method and the raw results downloadable. Run the same instances against anything else you are considering.

WHAT IT TAKES TO START

A price on the page, a 14-day trial and a key from your dashboard — no sales call and no licence negotiation before you can test. The validate endpoints need no key at all.

WHAT STAYS YOURS

Your data model, your UI and your pricing rules. Synchronous calls store nothing; an asynchronous max job keeps its result only for a short retention window so you can poll it. A meta object on any part or sheet comes back verbatim, so the plan reconciles with your records.

See the full benchmark →

Need a ready-made ordering screen instead of building one?

The CutOptim Configurator runs on this engine →Connect your own shop or ERP →

Pricing

Studio
€49/month
3,000 requests / month — hard cap, no overage, no surprise bill
14-day trial · billed in EUR · once the cap is reached, calls return 402 until the month rolls over
Scale
€149/month
10,000 requests / month — hard cap, no overage, no surprise bill
No trial · billed in EUR · switch plans on your dashboard

Every request counts the same — nesting included · We email you at 90% of the quota and when it runs out.

Try it free: a public demo key on the API reference, and test keys with 1,000 requests a month that are never billed

Larger volumes. 10,000 requests a month is the standard plan, not a ceiling on what we can run. If you need more — higher volume, separate keys for staging and production, or a dedicated arrangement — tell us your numbers and we price it individually. Tell us your volume →

By subscribing you accept the Engine API Service Terms (in English).

The regular CutOptim plans (Free / Pro / Workshop) are unrelated to the API — the in-app optimizer stays included in them. See app pricing →

What goes in, what comes out

One real job per mode: the request body on top, and below it the plan that came back, drawn straight from the response.

Goes inPOST /v1/optimize/2d
{
  "parts": [
    { "name": "Side", "w": 720, "h": 560, "qty": 6 },
    { "name": "Bottom", "w": 764, "h": 560, "qty": 3 },
    { "name": "Top", "w": 764, "h": 560, "qty": 3 },
    { "name": "Shelf", "w": 762, "h": 520, "qty": 3 },
    { "name": "Rail", "w": 764, "h": 100, "qty": 6 },
    { "name": "Plinth", "w": 764, "h": 120, "qty": 6 },
    { "name": "Door", "w": 397, "h": 716, "qty": 6, "rotatable": false },
    { "name": "Drawer front", "w": 796, "h": 176, "qty": 3 }
  ],
  "stock": [
    { "w": 2800, "h": 2070, "qty": 5, "price": 38.5 }
  ],
  "options": { "kerf": 4, "trim": { "left": 10, "right": 10, "top": 10, "bottom": 10 } }
}
Uses a public demo key — rate-limited, small jobs only, never billed.
Comes out200 · sheets[].parts
Sheets
2
sheetCount
Yield
80.31%
yieldPct
Parts placed
36 / 36
placed
Cut lines
39
cutLines
Material cost
77
totalPrice

A base-cabinet run on standard chipboard. The doors keep their grain (rotatable: false); every other part may turn.

Want the picture from the API itself? For 2D and nesting, add "svg" to include and the response carries the drawing.

Every drawing is made from the coordinates in the response — nothing is placed by hand. The four jobs are solved by the same engine the API runs, and our test suite re-solves them so the numbers stay true.

What the API does

Four cutting modes

One call each for 2D panels, 1D linear stock, timber with cross-section matching, and true-shape nesting of irregular polygons — POST /v1/optimize/2d, /1d, /wood and /nest.

True-shape nesting

POST /v1/optimize/nest packs arbitrary polygons (with holes) onto fixed sheets, interlocking parts into each other’s concave pockets — 6 sheets where the same parts by bounding box need 9. For laser, plasma and waterjet. Per-sheet exclusion zones (a defect, a clamp) come with it.

Material-aware

Tag parts and stock with a material and the optimizer partitions the job: each material is cut only from its own stock. On every mode; a per-material rollup comes back.

Edge banding

Name a banding type per edge (2D) and the response totals the running metres per type — per part and per order. Metadata: it never moves a part.

Grain matching

Name the parts whose figure must run on — a drawer front over two doors — in a matched set (matchedSets, 2D), and they are cut side by side from one piece of board, one kerf apart. Every member comes back with its set and position, and the CSV, SVG and DXF exports mark them too.

Inline export (SVG · DXF · CSV)

Ask for include:["svg","csv","dxf"] and the response carries the layout as a ready-made file, inline — a standalone 2D SVG drawing, an R12/AC1009 DXF, or a CSV cut list. No storage, no second call.

Metadata passthrough

Attach a meta object — your ERP article number, order-line id, customer ref — to any part or stock row and it comes back verbatim on every placed piece and every sheet/rod, so the plan reconciles with your system.

Free validation

POST /v1/validate/{2d,1d,wood,nest} schema-validates the same body without solving — no key, no quota. Check a payload will not be rejected and get feasibility warnings before you spend a call.

Cost or waste

minimizeCost ranks by the lowest total bill across priced stock sizes, mixing formats; the default minimizes material. Both run the same guillotine algorithm.

Stock priority & limited stock

Mark stock to use up first, treat quantities as a hard cap with respectStock, and flag must-cut parts that win board space when material is short.

A real cut plan

Not just rectangles: the guillotine cut sequence with per-step stop positions, cut lines vs. saw passes, sawn length, and a producible-on-a-panel-saw flag.

Panel-saw parameters

kerf, per-side trim, tolerance, grain direction, matched sets, maxCutStages and rotation minimising — the same options the app exposes.

Deterministic & OpenAPI

The same input always returns the same output — cache and diff it (the opt-in, time-limited nesting max search reports deterministic: false). A pinnable engine version and an OpenAPI 3.1 document describe the whole contract.

Parts from CAD files

Send an SVG or DXF instead of coordinates: parts[].source reads the outline and its holes out of the drawing, and POST /v1/import/nest splits a multi-part file first. Nothing is stored — the file is parsed in memory and is gone with the response.

MCP server for AI assistants

Claude Code, Cursor, VS Code and Claude Desktop call the engine as tools through https://api.cutoptim.com/mcp — with the same API key and quota as REST. It also runs locally as the npm package @cutoptim/mcp.

MCP guide →

Two speeds: quote now, save material later

Most integrations need both — an answer while a customer waits, and a tighter plan when the job goes to the machine. You choose per call.

INSTANT

The synchronous engines — heuristic for 2D, 1D and timber, lbf for nesting — answer inside the HTTP request, deterministically, so the plan behind a quote is the plan behind the order.

MAX

Send the job with engine: "max" and poll GET /v1/jobs/{id} for the result. On 2D panels it searches toward the proven optimum; on true-shape nesting it spends a time budget (options.timeBudgetMs) looking for fewer sheets and never returns more than the instant answer.

The response has the same shape either way. On 2D the max engine accepts a narrower set of options than heuristic (the reference lists them), and a nesting job with exclusion zones is still served by lbf.

Which engine serves which mode

The endpoint you POST to picks the mode; the engine parameter picks the algorithm. The default heuristic engine serves 2D, 1D and timber; balanced is 2D only; the asynchronous max engine serves 2D panels and true-shape nesting; and nesting defaults to its own lbf engine. Same engine as the app, over HTTP.

Mode · endpointEngine · algorithm2D panels/v1/optimize/2d1D linear/v1/optimize/1dTimber · cross-section/v1/optimize/woodTrue-shape nest/v1/optimize/nestheuristicdefault · synchronousbalancedopt-in · 2D onlymaxasync · 2D + nestlbfnesting · defaultOn 1D and timber, balanced simply aliases the heuristic (the response says so).
  • heuristic — The default — a guillotine multi-strategy packer. Highest yield, every layout is saw-cuttable, and it always returns a cut plan. It serves 2D, 1D and timber.
  • balanced — An opt-in MaxRects free-nester for 2D. Much faster on very large jobs for slightly less yield, but its layouts often cannot be sawn edge-to-edge, so they carry no cut plan.
  • max — The asynchronous tier: you submit the job and poll GET /v1/jobs/{id} for the result. On 2D it is a tree search that reaches the proven optimum on far more jobs, at seconds-to-a-minute per solve — still deterministic and saw-cuttable. On true-shape nesting it runs lbf first, then spends a time budget looking for a layout with fewer sheets and never returns more; that search is time-limited, so its nests say deterministic: false.
  • lbf — The true-shape nesting default. It packs irregular polygons into each other’s pockets for laser, plasma and waterjet — instantly and deterministically. max (above) can then search the same job for fewer sheets.

Which endpoint for which material: flat sheets — plywood, MDF, glass, acrylic, sheet metal — go to /v1/optimize/2d; bars, tube, pipe and profile to /v1/optimize/1d; structural timber (a 50×150 only from 50×150) to /v1/optimize/wood; irregular polygons for laser, plasma and waterjet to /v1/optimize/nest.

One call, a full plan

curl https://api.cutoptim.com/v1/optimize/2d \
  -H "Authorization: Bearer co_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "parts": [
      { "name": "Door",    "w": 600, "h": 400, "qty": 4 },
      { "name": "Shelf",   "w": 800, "h": 300, "qty": 6 }
    ],
    "stock":   [{ "w": 2440, "h": 1220, "price": 42 }],
    "options": { "kerf": 3, "effort": "balanced" },
    "engine":  "heuristic"
  }'

Comes back as:

{
  "metrics": { "sheetCount": 1, "yieldPct": 80.62, "placed": 10, "total": 10,
               "cutLines": 10, "sawPasses": 13, "cutLength": 10720, "totalPrice": 42 },
  "sheets":  [ … ],
  "cutPlan": [{ "sheet": 0, "step": 1, "axis": "h", "pos": 400, "length": 2440, "stage": 1 }, … ],
  "guillotineValid": true,
  "engineVersion": "1.0.0+10e0c941",
  "deterministic": true
}

Full request and response shape, every option, all error codes and every engine:API reference → · Integration guide →

Fast or dense? Pick with one option

The effort option trades solve time against yield. Here is that trade, measured on one demanding job — every figure comes from the real packer.

Effort switch: material yield vs solve timeEffort switch: material yield vs solve time. fast: 350 boards · 76.2% · ≈1.9 s. balanced: 330 boards · 80.8% · ≈4.8 s. max: reserved — denser needs a slower search. On most (smaller) jobs the two are identical; the gap only opens on large jobs like this one. balanced is the default and is never denser than fast can reach.Effort switch: material yield vs solve timeOne demanding job — about 1,550 parts on a 2.07 × 5.6 m board. Every figure measured on the real packer.74%76%78%80%82%84%02 s4 s6 ssolve time · faster →material yield · denser ↑⇄ the effort switch+4.6 pts yield · −20 boards−5.7% material · ≈2.5× slowerfast350 boards · 76.2% · ≈1.9 s★ balanced · default330 boards · 80.8% · ≈4.8 smaxreserveddenser needs aslower search
On most (smaller) jobs the two are identical; the gap only opens on large jobs like this one. balanced is the default and is never denser than fast can reach.

And it is fast either way: even the largest production jobs — 2,000 parts and more — solve in single-digit seconds on the default engine, comfortably inside the API time budget.

Solutions by industry

The same engine, positioned for the way one trade cuts. Each page shows the endpoint, a request and a response, and the fields that matter for that material.

The engine works on geometry, not on a material catalogue: sheet metal and plate, wood-based panels, glass, plastics and acrylic, composites, foam, cardboard and paper all go through the same endpoints. The material only changes the numbers you send — kerf or part spacing, edge clearance, stock sizes.

Downloadable resource
Engine API one-pager

The why, what and how of the CutOptim Engine API on two pages — the four modes, a real request and its plan, how to try it free, and the two plans. Print-ready, with a QR back to this page.

PDF2 pagesFree
Download the PDF

Frequently Asked Questions

Does CutOptim have an API?
Yes — the CutOptim Engine API exposes the same cutting engine over HTTP, for an ERP, a quoting tool or machine software, in all three modes the app has: 2D panels, 1D linear, and timber with cross-section matching.
Is there an API for laser, plasma or waterjet cutting?
Yes — true-shape nesting of irregular polygons is the fourth Engine API mode, POST /v1/optimize/nest. You send each part as a polygon outline (with optional holes) plus the stock sheets; the engine interlocks the parts into each other’s concave pockets and returns the placement of every copy, so a laser, plasma or waterjet job packs far tighter than a bounding box — on a representative 272-part job, 6 sheets where the same parts by bounding box need 9. Per-sheet exclusion zones (a defect, a clamp) and continuous rotation come with it; the spacing between parts (minSeparation) and the clearance at the sheet edge (edgeClearance) are set separately, and the response totals the sheets used per stock size — mixing sizes where that is cheaper — and gives each sheet’s cut length and pierce count, and its used width and height from the sheet corner (for charging part of a sheet; the least-filled sheet is compacted into that corner). The app has the same nesting as its own Nesting mode.
Is the Engine API deterministic?
Yes. The same input returns the same output, so responses are cacheable and testable, and the engine version can be pinned for reproducible results. The one opt-in exception is the nesting max engine: its search is time-limited, so it reports deterministic: false in every response.
What does an optimize response contain?
The full layout, a guillotine cut plan with per-step stop positions, and the metrics (sheet count, yield, cut lines, saw passes, sawn length). The 2D endpoint also returns edge-banding metres per type, and every endpoint accepts a material tag and returns a per-material rollup. You can also ask for the layout as an inline SVG, DXF or CSV, and attach a meta object to parts and stock that is echoed back verbatim.
Can the API give me a drawing, not just coordinates?
Yes. Add include:["svg","csv","dxf"] to an optimize request and the response carries the layout as a ready-made file, inline: a self-contained 2D SVG drawing, an R12/AC1009 DXF, or a CSV cut list. No storage and no second call. SVG is 2D only; a 1D or wood request returns a warning instead.
Can I attach my own IDs to parts and read them back?
Yes. Any part or stock row may carry a meta object — your ERP article number, order-line id or customer ref — and it comes back verbatim on every placed piece and every sheet or rod, so the cut plan reconciles with your own system. It never affects the layout.
Can I check a request without spending a call?
Yes. POST /v1/validate/2d, /1d or /wood schema-validates the same body the matching optimize endpoint takes without solving — no key and no quota. A 400 names the exact bad field, and you get feasibility warnings (a part that fits no stock) before you spend a real call.
Are there SDKs, webhooks or asynchronous jobs?
Yes. Official SDKs for TypeScript (npm @cutoptim/engine), Python (PyPI cutoptim) and PHP (Composer cutoptim/engine) are open source on github.com/cutoptim, generated from the OpenAPI 3.1 specification — for any other language, point a code generator at the same document. Most optimize calls are plain synchronous HTTP that return the finished plan directly. The one exception is the asynchronous max engine, for 2D panels and for true-shape nesting: POST /v1/optimize/2d or /v1/optimize/nest with engine:"max" returns 202 Accepted with a jobId, and you poll GET /v1/jobs/{id} until it finishes — for when a better plan is worth seconds to a few minutes of solve time. Instead of polling, register a webhook on your dashboard: it sends a signed POST when the job finishes.
What are the request limits?
Up to 2,000 parts, 50 stock rows and a 1 MB request body per call. Even the largest production jobs solve in single-digit seconds, comfortably inside the time budget.
Manage API keys