True-Shape-Nesting — unregelmäßige Polygone auf festen Platten, mit Ausschlusszonen (Laser / Plasma / Wasserstrahl)
POST
/v1/validate/2d
eine Anfrage prüfen, ohne zu rechnen — kostenlos, kein Schlüssel, kein Kontingent (2d / 1d / wood / nest)
POST
/v1/validate/1d
eine Anfrage prüfen, ohne zu rechnen — kostenlos, kein Schlüssel, kein Kontingent (2d / 1d / wood / nest)
POST
/v1/validate/wood
eine Anfrage prüfen, ohne zu rechnen — kostenlos, kein Schlüssel, kein Kontingent (2d / 1d / wood / nest)
POST
/v1/validate/nest
eine Anfrage prüfen, ohne zu rechnen — kostenlos, kein Schlüssel, kein Kontingent (2d / 1d / wood / nest)
GET
/v1/jobs/{id}
einen asynchronen Job der max-Engine abfragen — liefert seinen status und, sobald fertig, den Plan (kein Kontingent; nur Ihre eigenen Jobs)
POST
/v1/import/nest
Teileumrisse aus einer SVG- oder DXF-Datei lesen — Schlüssel erforderlich, verbraucht kein Kontingent
GET
/v1/usage
Verbrauch und Kontingent des KONTOS im laufenden Monat
GET
/v1/health
Liveness — kein Schlüssel, kein Rate-Limit, keine Datenbank
POST /v1/validate/{2d,1d,wood,nest} — response
valid
boolean
Always true on a 200 — a malformed body is a 400 with the exact bad field path instead. The body is the SAME one the matching optimize endpoint takes.
mode
string
"2d" | "1d" | "wood" | "nest" — the endpoint you called.
contractVersion
string
Shape version. Currently "1".
engineEnabled
boolean
NEST ONLY — whether the nesting engine is built into this deployment. Absent for the rectangular modes.
parts
object
{ rows, total } — part rows sent, and the total quantity after qty expansion. Check it against the part cap before you spend a call.
stock
object
{ rows, total } — the same for stock.
warnings
string[]
Approximate, SOLVE-FREE feasibility notes — e.g. a part that fits no stock (2D and nest: bounding box; wood: no matching section long enough). Empty ⇒ every part fits something. Ignores trim, kerf and material: a shape check, not a solve.
Einheiten
Die API ist einheitenneutral. Wählen Sie eine Einheit — Millimeter, Zoll, was auch immer —, verwenden Sie sie für jede Zahl, die Sie senden, und jede Zahl, die Sie zurückbekommen, steht in derselben Einheit. Serverseitig wird nichts umgerechnet, und kein Feldname legt eine Einheit fest.
Das gilt eingehend für die Maße von Teilen und Ausgangsmaterial, kerf, tolerance, trim und minOffcut und ausgehend für jede Koordinate, jede Position, jede Restlänge, jedes Reststück und jede Schnittlänge. Einheiten innerhalb einer Anfrage zu mischen ergibt einen Plan, der die Validierung besteht und physikalisch falsch ist — und der Server kann das nicht erkennen.
Koordinatensystem
Der Ursprung ist die linke obere Ecke der Platte: x wächst nach rechts entlang der Plattenbreite, y wächst nach unten entlang der Plattenhöhe. x und y eines Teils bezeichnen seine linke obere Ecke, und w und h sind die Maße wie platziert — bei rotated true bereits getauscht —, sodass das Rechteck x, y, w, h ohne weitere Rechnung die Grundfläche auf der Platte ist. Für die Rechtecke der Reststücke gilt dasselbe System.
Die Besäumung verschiebt Platzierungen: trim.left schiebt jedes Teil nach rechts und trim.top jedes Teil nach unten, weil die Teile innerhalb der nutzbaren Fläche verschachtelt und anschließend auf die volle Platte zurückversetzt werden. trim.right und trim.bottom verkleinern die nutzbare Fläche, ohne den Ursprung zu verschieben. w und h einer Platte sind immer die vollen Maße des Ausgangsmaterials, Besäumung eingeschlossen — deshalb zählt die Besäumung in yieldPct auch als Abfall.
Standard 1 — wird serverseitig aufgelöst; zählt auf das Limit von 2,000 Teilen
name
optionale Bezeichnung, wird bei jeder Platzierung mit zurückgegeben
rotatable
Standard true — darf das Teil um 90° gedreht werden
grainGroup
Mitglieder einer Gruppe bleiben auf einer Platte (Fasergruppen)
priority
Muss-Teil: erhält bei begrenztem Ausgangsmaterial den Vorrang auf der Platte (mit respectStock)
edgeBanding
Kantenanleimung je Kante: auf top / right / bottom / left jeweils eine Typreferenz angeben (ein freier String, Ihr eigener Code) — die Antwort summiert die Meter je Referenz. Nur Metadaten, verschiebt nie ein Teil. Nur 2D
material
Material-Kennung (ein freier String, Ihr eigener Code): Teile und Ausgangsmaterial mit demselben material werden nur miteinander gepackt. Anders als edgeBanding ändert es die Anordnung. Fehlt es, gibt es einen einzigen unbestimmten Pool. Funktioniert in jedem Modus
Felder des Ausgangsmaterials
w und h sind erforderlich. qty ist standardmäßig 1 und wirkt nur mit respectStock als hartes Limit. price gilt pro Platte und bestimmt totalPrice und den Kostenmodus. priority (boolean) verbraucht dieses Ausgangsmaterial zuerst; material (ein freier String) beschränkt es auf Teile desselben Materials.
Optionen
kerf
Sägeblattdicke (Standard 0)
tolerance
Schnitte akzeptieren, die um maximal diesen Wert überschreiten
Kandidaten nach dem niedrigsten Gesamtmaterialpreis bewerten; bei mehreren Materialgrößen mit Preis kombiniert es diese (2D) oder wählt die günstigste Länge (1D), um die Kosten zu senken, auch wenn dabei mehr Material verbraucht wird
respectStock
qty jeder Materialzeile als hartes Limit behandeln
minOffcut
nur Reststücke ausgeben, deren kurze Seite mindestens diesen Wert hat
maxCutStages
Stufenbegrenzung der Plattensäge — eine Anzahl von Schnittstufen, nicht die reine Baumtiefe
minimizeRotations
Layouts bevorzugen, die weniger Teile drehen
effort
'fast' | 'balanced' (Standard 'balanced'). Suchtiefe: 'balanced' führt das vollständige Multi-Strategie-Best-of aus; 'fast' überspringt die eine teure Flächenkombinationssuche pro Platte — auf großen Aufträgen merklich schneller, für den Preis weniger Prozentpunkte Auslastung, weiterhin guillotine-schneidbar und nie dichter als 'balanced'. Kleine Aufträge sind meist identisch. Nur mit der Engine heuristic
include tut zweierlei. BESCHNEIDEN — "cutPlan" und "offcuts" sind standardmäßig aktiv; ein vorhandenes Array behält nur die aufgeführten Beschneidungs-Tokens (ein leeres Array lässt beide weg). ADDITIVER EXPORT — "svg", "csv" und "dxf" fügen den jeweiligen Export der Antwort jeweils als STRING hinzu: svg eine eigenständige 2D-Layout-Zeichnung (nur 2D — eine 1d-/wood-Anfrage liefert stattdessen eine Warnung), dxf eine Zeichnung im Format R12/AC1009 auf den Layern STOCK/PARTS/LABELS, csv eine Schnittliste. Export-Tokens wirken sich nicht auf das Beschneiden aus, deshalb fügt include:["svg"] svg hinzu und lässt — da es kein Beschneidungs-Token nennt — cutPlan/offcuts weg; verwenden Sie ["cutPlan","offcuts","svg"], um alles zu behalten und svg zu ergänzen.
Opaque JSON of your own — an ERP article number, an order-line id, a customer ref. Echoed VERBATIM on every placed piece of that part. The optimizer never reads it, so it can never change a layout.
stock[].meta
object
The same on a stock row: echoed on every sheet / rod / nested sheet cut from it, so the plan reconciles with your system without a lookup table.
Die Option effort wägt Rechenzeit gegen Auslastung ab. Hier ist dieser Kompromiss, gemessen an einem anspruchsvollen Auftrag — jede Zahl stammt vom echten Packer.
Bei den meisten (kleineren) Aufträgen sind die beiden identisch; die Lücke öffnet sich erst bei großen Aufträgen wie diesem. balanced ist der Standard und nie dichter, als fast es erreichen kann.
Und schnell ist es ohnehin: selbst die größten Produktionsaufträge — 2.000 Teile und mehr — werden auf der Standard-Engine in einstelligen Sekunden gelöst, bequem innerhalb des API-Zeitbudgets.
cutLines vs sawPasses — cutLines fasst kollineare Schnitte zusammen (eine Anschlagseinstellung); sawPasses zählt jeden Durchgang. Zwei ehrliche Maße für denselben Plan — nicht der Anspruch, mit der Zählweise irgendeines Wettbewerbers übereinzustimmen.
guillotineValid / cutPlan — Lässt sich ein Layout nicht von Kante zu Kante schneiden, ist guillotineValid false und cutPlan null. Das ist eine echte Information — der Plan ist auf einer Plattensäge nicht herstellbar — und kein Fehler.
unplaced + warnings — Ein nicht erfüllbarer Auftrag antwortet mit 200, die betroffenen Teile stehen in unplaced und ein Hinweis in warnings. Ein Plan, mit dem Sie arbeiten können, ist mehr wert als ein Statuscode.
edgeBanding — Sobald ein Teil edgeBanding trägt, ergänzt die Antwort einen edgeBanding-Block: die laufenden Meter, die jede Typreferenz verbraucht, je Teil und als Auftragssumme. Es ist exakte Geometrie ohne Abfallzuschlag — den fügt die Werkstatt selbst hinzu — und setzt Eingaben in Millimetern voraus (÷1000 für Meter). Bei einem Auftrag ohne Kantenanleimung fehlt der Schlüssel vollständig.
materials / unmatchedMaterials — Sobald ein Teil oder Ausgangsmaterial material trägt, ergänzt die Antwort materials (eine Aufstellung je Material — material, sheetCount/rodCount, yieldPct, placed, total, totalPrice) und unmatchedMaterials (Bedarf, dessen Material kein passendes Ausgangsmaterial hat). Bei Holz reitet das Material stattdessen auf jedem Querschnittsabschnitt mit. Bei einem Auftrag ohne Material fehlen beide Schlüssel, und die Antwort bleibt byte-identisch.
Felder der Antwort
Feldnamen und Typen sind der Vertrag, deshalb bleiben die folgenden Tabellen in jeder Sprache englisch — ein übersetzter Feldname würde eine API dokumentieren, die es nicht gibt.
POST /v1/optimize/2d — top level
engine
string
Which engine ran: "heuristic", "balanced" or "max".
engineVersion
string
Algorithm identity — package version + a content hash of the algorithm source. Moves automatically on any packer change, and independently per engine.
contractVersion
string
Shape version, matching the /v1/ in the path. Currently "1".
deterministic
boolean
Always true. Present so a client can assert the guarantee it relies on.
sheets
array
One entry per sheet used, in cutting order.
metrics
object
Aggregate numbers for the whole job.
cutPlan
array | null
The sawing plan. null when guillotineValid is false; absent when excluded via include.
unplaced
array
Parts that did not fit, aggregated by name + size. Empty when everything fitted.
warnings
string[]
Free-text notes about the plan. Do not parse — branch on unplaced, guillotineValid and metrics.
guillotineValid
boolean
True when the layout is producible with edge-to-edge cuts, i.e. on a panel saw.
edgeBanding
object
Linear metres of edge banding, grouped by type reference. ABSENT unless a part requested banding via parts[].edgeBanding. 2D only.
materials
array
Per-material rollup. ABSENT unless a part or stock row carried material — a material-free job stays byte-identical. (OPEN-256)
unmatchedMaterials
array
Demand whose material has no matching stock at all. ABSENT when it does not happen. A missing-material report, not a did-not-fit one.
svg
string
Inline SVG of the 2D layout (self-contained, no external refs). Present ONLY when include contains "svg". 2D only. (OPEN-223)
csv
string
Inline CSV cut list. Present ONLY when include contains "csv".
dxf
string
Inline DXF (R12/AC1009) on layers STOCK/PARTS/LABELS. Present ONLY when include contains "dxf".
timing.solveMs
number
Milliseconds inside the packer, 2 decimals. Excludes parsing, auth and queueing.
sheets[]
w, h
number
FULL stock dimensions, trim included — not the usable area.
price
number | null
Price of the stock row this sheet came from, or null if none was given.
parts
array
Placements on this sheet.
offcuts
array
Usable leftover rectangles, filtered by options.minOffcut. Absent (not empty) when excluded via include.
meta
object
Present only when the stock row carried meta — echoed verbatim from stock[].meta. (OPEN-224)
sheets[].parts[]
name
string
The requested name, or the generated default "Part <row>".
x, y
number
Top-left corner of the part, from the top-left corner of the sheet.
w, h
number
Dimensions AS PLACED — already swapped when rotated is true. No client-side swap needed.
rotated
boolean
True if the part was turned 90° from the requested w×h. Informational only.
meta
object
Present only when the part carried meta — echoed verbatim from parts[].meta on every placed piece. (OPEN-224)
sheets[].offcuts[]
x, y, w, h
number
A leftover rectangle, in the same coordinate system as the placements.
metrics (2D)
sheetCount
integer
Sheets used. Equals sheets.length.
yieldPct
number
Placed part area ÷ total FULL sheet area × 100, 2 decimals. Trim and kerf count as waste.
placed
integer
Pieces placed, after qty expansion.
total
integer
Pieces requested, after qty expansion.
cutLines
integer
Collinear cuts merged: same axis, same coordinate, same stage counted once — one fence setting.
sawPasses
integer
Every cut, one per strip crossed — how many separate passes the saw makes.
cutLength
number
Total distance sawn, 3 decimals. Same under either counting convention. In your unit.
totalPrice
number
Sum of the used sheets’ prices, 2 decimals. 0 when no stock row carried a price.
unplaced[] (2D)
name
string
The part name.
w, h
number
As requested.
qty
integer
How many of this part could not be placed.
edgeBanding (2D — present only when a part is banded)
totalMeters
number
Order-wide total across every banded edge, 3 decimals. ⚠️ Assumes mm input: top/bottom edges run the part width, left/right the height, ×qty, ÷1000. In another unit it is your raw edge length ÷ 1000.
byType[]
{ reference, meters }
Order total split by the caller-supplied type reference, sorted by reference.
byPart[]
{ name, meters, byType }
One entry per requested part row that has any banded edge; its byType splits that part’s metres by reference.
cutPlan[]
sheet
integer
0-based index into sheets (2D) or rods (1D). Named sheet in both.
step
integer
1-based order within THIS sheet — it restarts at 1 on every sheet.
axis
"h" | "v"
"h": blade travels along x, separating top from bottom. "v": along y, separating left from right.
pos
number
The blade’s LOW-COORDINATE edge — the y value for "h", the x value for "v" — not its centre line. The kerf occupies pos to pos + kerf.
length
number
Distance the blade travels on this cut: the extent of the region crossed. Always 0 in 1D.
stage
integer
1-based machine pass. Increments only when the axis flips relative to the parent cut.
2D · edgeBanding
Sobald ein Teil edgeBanding trägt, ergänzt die Antwort einen edgeBanding-Block: die laufenden Meter, die jede Typreferenz verbraucht, je Teil und als Auftragssumme. Es ist exakte Geometrie ohne Abfallzuschlag — den fügt die Werkstatt selbst hinzu — und setzt Eingaben in Millimetern voraus (÷1000 für Meter). Bei einem Auftrag ohne Kantenanleimung fehlt der Schlüssel vollständig.
Sobald ein Teil oder Ausgangsmaterial material trägt, ergänzt die Antwort materials (eine Aufstellung je Material — material, sheetCount/rodCount, yieldPct, placed, total, totalPrice) und unmatchedMaterials (Bedarf, dessen Material kein passendes Ausgangsmaterial hat). Bei Holz reitet das Material stattdessen auf jedem Querschnittsabschnitt mit. Bei einem Auftrag ohne Material fehlen beide Schlüssel, und die Antwort bleibt byte-identisch.
The tag exactly as you sent it. Free text, matched exactly.
sheetCount | rodCount
integer
Stock consumed for this material — sheetCount on 2D and nest, rodCount on 1D.
yieldPct | density
number
This material’s own fill — yieldPct on the rectangular modes, density on nest (a polygon fill, not comparable to yieldPct).
placed, total
integer
Pieces placed and requested for this material, after qty expansion.
totalPrice
number
Sum of the prices of the stock used for this material.
unmatchedMaterials[] — demand with no matching stock
material
string
The tag that has no stock of its own anywhere in the request.
parts
array
The demand rows in that material, in the mode’s unplaced shape: name, w, h, qty on 2D; name, length, qty on 1D; name, qty on nest.
cutPlan — was ein step physisch bedeutet
Ein step ist eine Bewegung des Sägeblatts, und die Liste steht in der Reihenfolge, in der Sie tatsächlich sägen können: ein übergeordneter Schnitt vor den Schnitten innerhalb des Stücks, das er erzeugt hat — denn Sie können einen Streifen nicht ablängen, bevor Sie ihn längs herausgetrennt haben. axis "h" bedeutet, das Sägeblatt bewegt sich entlang x und trennt oben von unten; axis "v" bedeutet, es bewegt sich entlang y und trennt links von rechts. pos ist die Kante des Sägeblatts mit der NIEDRIGEREN Koordinate — der Wert y bei "h", der Wert x bei "v" —, nicht seine Mittellinie: kerf belegt pos bis pos + kerf, das Sägeblatt frisst also in die Richtung, in die die Koordinate wächst — bei "h" nach unten, bei "v" nach rechts. Das Material auf der niedrigen Seite der Linie — bei "h" darüber, bei "v" links davon — ist das Stück, das dieser Schnitt freigibt. length ist die Strecke, die das Sägeblatt bei diesem einen Schnitt zurücklegt: die Ausdehnung des Bereichs, den es durchquert, nicht die Breite der ganzen Platte.
stage ist ein Maschinendurchgang. Der Wert beginnt bei 1 und erhöht sich nur, wenn axis gegenüber dem übergeordneten Schnitt umschlägt — eine Platte längs in sechs Streifen aufzutrennen ist also eine Stufe, und diese Streifen abzulängen die nächste. Das ist der Plattensägen-Sinn von „dreistufigem Zuschnitt“, nicht die Tiefe des Schnittbaums, und genau das begrenzt maxCutStages. sheet ist ein 0-basierter Index in sheets, und step beginnt auf jeder Platte wieder bei 1, statt über den gesamten Auftrag durchzulaufen.
cutPlan ist null — nicht fehlend, nicht leer —, sobald guillotineValid false ist: ein Layout, das sich nicht von Kante zu Kante schneiden lässt, hat keine Schnittsequenz, die zurückgegeben werden könnte. Ganz aus der Antwort verschwindet es nur, wenn Sie es in include weggelassen haben.
Teile erhalten length (dazu qty, name, priority); das Ausgangsmaterial erhält length, qty und price. Teile und Ausgangsmaterial akzeptieren zusätzlich ein optionales material-Tag (Ausgangsmaterial auch priority) — material beschränkt ein Teil auf Ausgangsmaterial desselben Materials, und die Antwort ergänzt dann materials und unmatchedMaterials wie in 2D. Die Optionen sind kerf, tolerance, trim.start / trim.end, minimizeCost, respectStock und minOffcut. Die Antwort liefert rods statt sheets — jeweils mit den zugehörigen parts, der Restlänge und den offcuts.
rods ersetzt sheets, und guillotineValid gibt es nicht, weil ein Linearschnitt immer herstellbar ist. pos eines Teils ist der Abstand seines vorderen Endes von jenem Stabende, das trim.start abschneidet — das erste Teil beginnt also genau bei trim.start, und jedes folgende pos kommt um ein kerf weiter. remaining ist das NUTZBARE Reststück: das kerf des Schnitts, der es vom letzten Stück trennt, ist bereits abgezogen — es ist also die wiederverwertbare Länge, nicht die rohe Lücke. Es wird für jeden Stab ausgegeben, auch wenn der Wert unter minOffcut liegt: minOffcut filtert nur das Array offcuts, das höchstens einen Eintrag enthält. Im Schnittplan ist sheet der Index des Stabs, axis immer "v", stage immer 1 und length immer 0 — ein Ablängschnitt am Stab hat keine Verfahrstrecke zu melden, und genau deshalb enthalten die metrics in 1D cuts, aber kein cutLength.
Holz hat eine Identität, die ein blanker Stab nicht hat: Ein Teil 50×150 lässt sich aus Material 50×100 nicht herausschneiden, wie viel Länge auch übrig ist. Teile und Material führen deshalb sw und sh, die beiden Querschnittsseiten, in beliebiger Reihenfolge — 50×100 und 100×50 sind derselbe umgedrehte Balken und werden als ein Abschnitt behandelt. Der Auftrag wird nach Querschnitt aufgeteilt, jeder Abschnitt wird seinem eigenen Material zugeordnet und für sich gelöst, und ein Aufruf liefert das Ganze. Teile und Ausgangsmaterial akzeptieren zusätzlich ein optionales material-Tag (Ausgangsmaterial auch priority): Damit werden eine Eiche 50×100 und eine Kiefer 50×100 zu zwei getrennten Abschnitten, und jeder Abschnitt führt sein Material mit. Die Optionen sind dieselben wie bei 1D.
sections ersetzt auf oberster Ebene rods: Jeder Eintrag ist ein Querschnitt mit eigenen rods (in der Form identisch zu 1D) und eigenen metrics, sodass die Kennzahlen je Material vorliegen, ohne sie nachzurechnen. unmatched hat in 1D keine Entsprechung — es ist Bedarf, für dessen Querschnitt Sie gar kein Material angegeben haben. Das ist ein anderes Problem als unplaced (Teile, für die Material da war und die nicht gepasst haben) und verlangt eine andere Lösung, deshalb werden beide nie vermischt. metrics.total zählt jedes angefragte Stück, unmatched eingeschlossen. Im Schnittplan nennt jeder Schritt zusätzlich seinen section, und sheet ist der Stabindex INNERHALB dieses Abschnitts, kein auftragsweiter Zähler.
POST /v1/optimize/wood — top level (what differs from 1D)
sections
array
Replaces rods at the top level: one entry per cross-section, each matched to its own stock and solved on its own.
unmatched
array
Demand whose cross-section has NO stock at all. Deliberately separate from unplaced (had stock, did not fit) — the fix differs, so the two are never mixed.
unplaced
array
Did-not-fit demand, aggregated across the sections that DID have stock. Same shape as 1D.
metrics
object
Job-wide totals across every section (below).
cutPlan
array | null
As 1D, except every step also carries section, and sheet is the rod index WITHIN that section, not a job-wide counter.
csv, dxf
string
Inline export, present only when include names the token. svg is 2D-only — a wood request asking for it gets a warning instead.
sections[]
section
string
Normalised cross-section key, e.g. "50x100" — short side first, so 50×100 and 100×50 are one section.
sw, sh
number
The two cross-section sides: sw the SHORT one, sh the long one, whatever order they arrived in.
stockName
string | null
The name of the stock row this section was matched to, or null when that row carried none.
material
string
Present only when the section carries a material — an oak 50×100 and a pine 50×100 are two sections. (OPEN-256)
rods
array
Identical in shape to the 1D rods[] above, meta and offcuts included.
metrics
object
This section’s own totals: rodCount, yieldPct, placed, total, cuts, totalPrice — so the per-section figures need no recomputation.
unplaced
array
This section’s parts that had stock and still did not fit.
metrics (wood)
sectionCount
integer
Cross-sections solved. Equals sections.length.
rodCount
integer
Bars used across every section.
yieldPct
number
Placed length ÷ total FULL bar length × 100 over the whole job, 2 decimals.
placed
integer
Pieces placed, after qty expansion.
total
integer
Pieces REQUESTED, after qty expansion — unmatched ones included.
cuts
integer
Crosscuts across every used bar.
totalPrice
number
Sum of the used bars’ prices, 2 decimals.
toleranceAcceptedCount
integer
Pieces that fitted only because options.tolerance allowed an overshoot.
unmatched[]
section
string
The cross-section key nothing in stock matched.
sw, sh
number
That cross-section’s two sides.
material
string
Present when the cross-section DOES exist in stock but only in a different material. (OPEN-256)
parts
array
The demand rows in that section, in the 1D unplaced shape: name, length, qty.
qty
integer
Total pieces in this section that had no stock at all.
Die drei Modi oben packen Rechtecke. POST /v1/optimize/nest packt BELIEBIGE POLYGONE: Ein Teil ist ein Umriss (polygon, mit optionalen inneren holes), keine Breite×Höhe, sodass sich Teile in die konkaven Aussparungen der anderen verschachteln und die Kerbluft, die eine Bounding Box verschwendet, zurückgewonnen wird — bei einem repräsentativen Auftrag 6 Platten, wo dieselben Teile per Bounding Box 9 brauchen. Es ist eine andere Klasse von Algorithmus (eine geometrische Kollisions-Engine, nicht der Guillotine-Packer), für das Laser-, Plasma- und Wasserstrahlschneiden. Zwei Dinge, die die rechteckige API nicht ausdrücken kann, sind dabei: Ausschlusszonen je Platte (stock[].exclusions — ein Defekt, die Aufstandsfläche einer Spannpratze, ein vorbedruckter Bereich; eine Zone mit quality 0 ist für jedes Teil ein Sperrbereich) und True-Shape-Löcher. Die material-Partitionierung und die meta-Durchreichung funktionieren wie überall sonst. Das Beispiel unten ist ein echter, aufgezeichneter Aufruf — acht Teile auf einer einzigen Platte mit einer ausgeschlossenen beschädigten Ecke.
POST /v1/optimize/nest — request (top level)
parts
array
One or more NestPart (see below). Required.
stock
array
One or more NestStock sheet types (see below). Required.
options
object
Solve options (see below). Optional.
engine
string
"lbf" (default, single-pass, instant) or "sparrow" (advertised for a future higher-density build; currently served by lbf with a warning).
include
string[]
Additive inline export of the ACHIEVED nest: "svg" a self-contained styled drawing (one titled band per sheet, parts as filled polygons with holes, exclusion zones hatched), "dxf" an R12/AC1009 document on layers STOCK/PARTS/HOLES/ZONES/LABELS. Unit-agnostic, exactly like the request coordinates. The geometry in sheets[] is returned either way.
parts[] (NestPart)
polygon
number[][]
The part outline: an ordered ring of ≥3 [x, y] vertices. Given closed (first == last) or open; winding order is not required — it is oriented internally. Required UNLESS the row carries source.
source
object
OPEN-262 — read the outline out of an SVG or DXF FILE instead of listing coordinates (fields below). EXACTLY ONE of polygon / source: both, or neither, is a 400.
holes
number[][][]
Optional interior holes — a part with a cut-out. Each hole is a ring like polygon. NOT accepted alongside source: the file already carries its own holes, and two sources of truth for one geometry is not a thing we resolve silently.
qty
integer
Copies to place. Default 1.
allowedRotations
number[] | "continuous"
Allowed rotations in DEGREES (e.g. [0,90,180,270]). Omit or "continuous" for free rotation.
minQuality
integer
The part may only be placed where sheet quality ≥ this. Default 1 → it avoids every quality-0 exclusion zone. Raise it to keep the part off inferior-but-not-forbidden zones too.
priority
boolean
Must-cut: wins sheet space when stock is capped (options.respectStock).
material
string
OPEN-256 — a part of material X nests only on material-X sheets; the job is partitioned by material.
name
string
Optional label, echoed on every placement. Defaults to "Part <1-based row index>".
meta
object
OPEN-224 — opaque JSON (your ERP ids), echoed verbatim on every placed copy. Never affects the layout.
stock[] (NestStock)
w, h
number
Rectangular sheet size. Give w & h OR polygon, not both.
Default 1. A HARD cap only when options.respectStock is true.
price
number
Per-sheet price, for cost mode + totalPrice.
exclusions
object[]
OPEN-233 — per-sheet excluded / inferior zones. Each: { polygon: number[][], quality?: integer }. quality 0 (the default) = a hard no-go region for any part; a higher quality only excludes parts whose minQuality demands at least that. This is what the rectangular API cannot express.
material
string
OPEN-256 — this sheet serves only material-matching parts.
meta
object
OPEN-224 — echoed on every sheet cut from this stock row.
options (NestOptions)
minSeparation
number
Minimum clearance between parts and between a part and any hazard (sheet edge / exclusion zone). Use for kerf / beam / torch width. Default 0.
seed
integer
Determinism: a fixed seed → a reproducible layout. Omit and the server pins a fixed default so the response stays reproducible.
minimizeCost
boolean
Rank plans by total sheet price rather than sheet count.
respectStock
boolean
Treat each stock qty as a hard cap.
simplifyTolerance
number
Polygon simplification tolerance (max area deviation as a fraction). Speeds up dense DXF outlines with hundreds of vertices. 0 disables.
timeBudgetMs
integer
Wall-clock budget for the metaheuristic (engine "sparrow"). Ignored by "lbf" (single-pass).
Jeder Eintrag in sheets ist eine genutzte Platte; ein platziertes Teil trägt die starre Transformation (rotation in Grad, dann Translation x/y), NICHT ein erneut ausgegebenes Polygon — drehen Sie Ihren Eingabe-Umriss um rotation um seinen Ursprung und addieren Sie (x, y), um die Platzierung exakt zu rekonstruieren. rotation kann negativ sein; die Rekonstruktion ist unabhängig vom Vorzeichen exakt. ⚠️ density ist die platzierte POLYGON-Fläche geteilt durch die genutzte Plattenfläche — die ehrliche Füllung, bei der konkave Aussparungen als leer zählen — und ist NICHT mit dem yieldPct eines rechteckigen Packers vergleichbar (der jede Bounding Box als voll zählt und deshalb bei einem schlechteren Ergebnis höher ausfällt); die über beide vergleichbare Kennzahl ist sheetCount bei denselben Teilen. Das Layout ist deterministisch: Setzen Sie options.seed, um es zu reproduzieren. exclusions wird auf jeder Platte für das Rendering mit zurückgegeben.
POST /v1/optimize/nest — top level
engine
string
Which nesting engine ran: "lbf" or "sparrow".
engineVersion
string
The nesting engine's algorithm identity (jagua-rs revision + build hash). Versions independently of the rectangular engines.
contractVersion
string
Nest contract version, currently "1". Versions independently of the /v1/ rectangular contract — it is a different path and engine family.
deterministic
boolean
Always true — guaranteed by the pinned seed.
sheets
array
One entry per used sheet.
metrics
object
Job totals (see below).
unplaced
array
Demand that could not be placed — a plan-plus-warning, not an error.
warnings
string[]
e.g. an engine substitution ("sparrow" served by "lbf"), unplaced parts, or a material with no matching stock.
materials
array
OPEN-256 per-material rollup — present only when parts/stock carry material.
unmatchedMaterials
array
Parts whose material has no matching stock — present only when it happens.
imported
object
OPEN-262 — what the request’s source files contributed (fields above). ABSENT for a coordinates-only job, which is what keeps such a request byte-identical to before the feature existed.
svg, dxf
string
The achieved nest as an inline drawing — present ONLY when include contains that token. svg is self-contained (no external refs); dxf is R12/AC1009.
timing
object
{ solveMs: number } — the solve time; environment-dependent.
sheets[] (nest)
w, h
number
Present for rectangular sheets.
polygon
number[][]
Present for arbitrary-outline sheets instead of w/h.
price
number | null
The stock row's price, or null.
density
number
This sheet's fill = placed polygon area / sheet area.
parts
array
Placements on this sheet (see below).
exclusions
object[]
The zones that applied to this sheet, echoed for rendering.
material
string
Present when the sheet carried a material (OPEN-256).
meta
object
Echoed from the stock row's meta (OPEN-224).
sheets[].parts[] (nest — placed)
name
string
The requested name, or the generated default.
sheet
integer
0-based index into sheets.
x, y
number
Translation, applied AFTER rotation about the part's origin.
rotation
number
⚠️ Degrees, applied about the part's own origin FIRST. A placed part carries this rigid transform, NOT a re-emitted polygon: rotate your input outline by rotation, then add (x, y) to reconstruct the placement exactly. May be negative; the reconstruction is exact regardless of sign.
material
string
The material this copy nested from (OPEN-256).
meta
object
The part's opaque passthrough (OPEN-224).
metrics (nest)
sheetCount
integer
Sheets used. Equals sheets.length. ⚠️ The honest, cross-comparable metric between nesting and the rectangular modes.
density
number
⚠️ Placed POLYGON area / used sheet area — the honest fill (concave pockets count as empty). NOT comparable to a rectangular packer's yieldPct, which counts each bounding box as solid and so reads higher for a worse result.
placed
integer
Part copies placed, after qty expansion.
total
integer
Part copies requested, after qty expansion.
totalPrice
number
Sum of used sheet prices.
unplaced[] (nest)
name
string
The part name.
qty
integer
How many copies could not be placed.
rods[]
length
number
FULL bar length as supplied in stock.
price
number | null
Price of the stock row, or null.
remaining
number
USABLE off-cut left on this bar, 3 decimals — the kerf of the cut that frees it from the last piece is already deducted (OPEN-257), so it is the reclaimable length, not the raw gap. Reported even when below minOffcut.
parts
array
Placements, in cutting order along the bar.
offcuts
number[]
At most one entry: [remaining] (the kerf-corrected usable off-cut, OPEN-257) when it is > 0 and ≥ minOffcut, else []. Absent when excluded via include.
meta
object
Present only when the stock row carried meta — echoed from stock[].meta (OPEN-224). Applies to 1D and wood rods.
rods[].parts[]
name
string
The requested name, or the generated default.
pos
number
Offset of the part’s NEAR end from the bar end that trim.start trims.
length
number
The part length, as requested.
meta
object
Present only when the part carried meta — echoed from parts[].meta (OPEN-224).
metrics (1D)
rodCount
integer
Bars used. Equals rods.length.
yieldPct
number
Placed length ÷ total FULL bar length × 100, 2 decimals. Trim and kerf count as waste.
placed
integer
Pieces placed, after qty expansion.
total
integer
Pieces requested, after qty expansion.
cuts
integer
Total crosscuts across all used bars — one per placed piece.
totalPrice
number
Sum of used bar prices, 2 decimals.
toleranceAcceptedCount
integer
Pieces that fitted only because options.tolerance allowed an overshoot.
unplaced[] (1D)
name
string
The part name.
length
number
As requested.
qty
integer
How many could not be placed.
Teile aus einer Datei (SVG · DXF)
Ein Teil muss nicht als Koordinaten ankommen. Legen Sie ein SVG- oder DXF-Dokument in parts[].source, und der Server liest den Umriss — samt seiner Löcher — mit demselben Parser heraus, den die CutOptim-App verwendet, wenn Sie eine Zeichnung auf ihren Nesting-Modus ziehen. Die Datei ersetzt AUSSCHLIESSLICH die Geometrie: qty, material, allowedRotations, minQuality, priority und meta verhalten sich genau wie bei einem polygon-Teil, eine bereits als CAD-Dateien vorliegende Teilebibliothek braucht also keinen eigenen Kurven- und Bogen-Abtaster. Eine source beschreibt EIN Teil; eine Zeichnung mit mehreren getrennten Bauteilen ergibt 400 und verweist auf den Import-Endpoint unten. Die Antwort trägt dann einen imported-Block: wie viele Zeilen aus einer Datei kamen, wie viele Stützpunkte sie erzeugt haben und welche Einheiten diese Dateien deklariert haben — gemeldet, nie angewendet, denn diese API rechnet nichts um.
Nichts wird gespeichert. Die Bytes existieren nur als Anfragerumpf, werden im Arbeitsspeicher verarbeitet und sind fort, sobald die Antwort geschrieben ist: keine Festplatte, keine Datenbank, keine temporäre Datei, keine Logzeile. Es gibt hinterher nichts zu löschen und nichts bleibt zurück — dieselbe Zustandslosigkeit, die jeder andere Endpoint einhält.
Feldnamen und Typen sind der Vertrag, deshalb bleiben die folgenden Tabellen in jeder Sprache englisch — ein übersetzter Feldname würde eine API dokumentieren, die es nicht gibt.
The file TEXT — not base64, not a URL, not a multipart upload. Both formats are text documents, so they travel inside the JSON body like any other field. At most 4,000,000 characters per file and 8,000,000 across one request; over either is a 413.
format
"svg" | "dxf"
Omit and the server sniffs the content (an <svg tag ⇒ svg, otherwise dxf). An explicit value ALWAYS wins — including over a filename whose extension disagrees, which is the case worth setting it for.
filename
string
Used for format detection AND as the part name when the row has no name of its own (extension stripped). It never touches a filesystem — there is no file on our side to name.
flattenTolerance
number
Curve and arc flattening tolerance, in the FILE’s own coordinate unit. Default 0.2. Larger = fewer vertices; this is the lever when a dense outline trips the 2,000-vertex per-ring cap.
imported — what the files contributed (response, absent without a source)
parts
integer
Part ROWS whose geometry came from a file.
vertices
integer
Total vertices those files produced after flattening, outlines and holes together — the number to watch against the per-ring cap.
units
string[]
⚠️ Units the files DECLARED (a DXF $INSUNITS), not units we applied. Empty when none declared one. More than one entry also raises a warning: mixing a millimetre drawing with an inch one produces a plan that validates and is physically wrong, and the server must not "fix" that by converting — no field in this API asserts a unit.
POST /v1/import/nest — eine Datei, alle Umrisse
Enthält eine einzelne Zeichnung mehrere verschiedene Teile, importieren Sie sie zuerst: dieser Endpoint liefert jeden geschlossenen Umriss, den größten zuerst, genau in der Form, die eine parts[]-Zeile erwartet. Übernehmen Sie die benötigten, ergänzen Sie Ihr eigenes qty und material und senden Sie das an /v1/optimize/nest. So sehen Sie auch, was in einer Datei steckt, bevor Sie eine Berechnung dafür ausgeben. Er verlangt einen Schlüssel — beliebige Geometrie abzutasten ist echte Rechenarbeit, und anonyme Rechenzeit ist ein schlechtes Geschäft —, reserviert aber nichts: Ihr Kontingent bleibt unberührt und es kommen keine Rate-Limit-Header zurück, genau wie beim Abfragen eines Jobs.
The file text. Required. Same 4,000,000-character cap as parts[].source.
format
"svg" | "dxf"
Omit to sniff; an explicit value wins over the filename extension.
filename
string
Used for detection and to NAME the results: a file with one outline keeps the bare name, several are numbered "<name> 1", "<name> 2", …
flattenTolerance
number
As on parts[].source. Default 0.2.
POST /v1/import/nest — response
format
"svg" | "dxf"
The parser that actually ran — the useful bit when you let the server sniff.
parts[]
{ name, polygon, holes? }
One entry per closed outline, LARGEST FIRST. Each is already in the shape a parts[] row wants: paste it in and add your own qty / material / allowedRotations. Deterministic — the same bytes always give the same vertices in the same order.
vertices
integer
Total vertices after flattening. Compare it against the 2,000-per-ring cap before you build a large request.
sourceUnit
"mm" | "in"
A DXF $INSUNITS declaration, when the file carries one. REPORTED, NEVER APPLIED. Absent for SVG (the format has no unit) and for a DXF that declares none.
warnings
string[]
What the parser could not honour — an SVG transform= attribute (CAD part exports are flat, so we do not apply them), or geometry that never closed into a contour. Empty means the file was read whole.
engineEnabled
boolean
Whether THIS deployment can also SOLVE a nest. Importing is pure parsing and works everywhere; where the nesting engine is not built in, /v1/optimize/nest answers 503 and this flag says so up front. Same field /v1/validate/nest carries.
contractVersion
string
Nest contract version. Currently "1".
Engines
heuristic(Standard) — der Guillotine-Packer mit mehreren Strategien. Höchste Auslastung, jedes Layout auf der Säge schneidbar, immer ein vollständiger cutPlan.
balanced — ein MaxRects-Packer mit freier Verschachtelung. Bei großen Aufträgen deutlich schneller (gemessen ~25× bei 2.000 Teilen) bei geringem Verlust an Auslastung, und seine Layouts sind häufig nicht guillotine-schneidbar (guillotineValid: false, cutPlan: null). Er berücksichtigt tolerance, minimizeCost, grainGroup, maxCutStages und minimizeRotations nicht — wird eine davon gesetzt, weist eine Warnung darauf hin, dass sie ignoriert wurde.
max — die asynchrone Baumsuche-Stufe (nur 2D): Sie erreicht das bewiesene Optimum bei weit mehr Aufträgen, zum Preis von Sekunden bis zu einer Minute je Berechnung. Weiterhin deterministisch und guillotine-schneidbar. Sie gibt keinen Plan direkt zurück — siehe Async-Jobs unten. Sie modelliert EIN Bestandsformat in voller Plattengröße mit unbegrenztem Vorrat und einem festen 3-stufigen Guillotine-Muster: eine zweite Bestandszeile, trim, respectStock, material oder grainGroup werden mit 400 abgelehnt, bevor ein Aufruf reserviert wird; tolerance, minimizeCost, maxCutStages, minimizeRotations, firstCut und effort werden angenommen, aber mit einer Warnung ignoriert, und ein max-Ergebnis meldet keine Reststücke. Schicken Sie solche Aufträge an heuristic.
Async-Jobs (engine = max)
Eine max-Berechnung dauert Sekunden bis zu einer Minute, deshalb gibt POST /v1/optimize/2d mit engine:"max" keinen Plan zurück — es liefert 202 Accepted mit einer jobId, und der Aufruf wird bei der Übermittlung gezählt. Fragen Sie GET /v1/jobs/{id} ab, bis status "succeeded" ist (result enthält dieselbe 2D-Response, die eine synchrone Berechnung liefert) oder "failed" (error enthält die Meldung). Das Abfragen verbraucht kein Kontingent; Sie sehen nur Ihre eigenen Jobs. Wo die Stufe in einer Installation nicht aktiviert ist, schlägt engine:"max" mit 503 fehl (fail closed).
field
type
meaning
jobId
string
The 202 body's id. Poll GET /v1/jobs/{id}.
status
string
queued → running → succeeded | failed.
mode · engine
string
Always "2d" and "max".
pollAfterMs
integer
202 only — suggested delay before the first poll.
result
object
Present once succeeded — the same shape as a synchronous 2D response.
error
string
Present once failed — the reason.
quota
object
202 only — reserved, used and limit: the one call metered at submission, and where the ACCOUNT stands this month.
createdAt
string
Poll only — when the job was submitted (ISO-8601).
finishedAt
string | null
Poll only — when the worker finished; null while queued or running.
Determinismus & Versionierung
Jede Antwort enthält engineVersion. Der Algorithmus ist deterministisch, deshalb ändert eine Verbesserung die Ausgabe für dieselbe Eingabe — was ein Breaking Change ist, wenn Sie cachen. Legen Sie das Verhalten fest, indem Sie engine explizit senden und engineVersion beobachten; die Pfadversion /v1/ ändert sich nur, wenn sich die Struktur der Antwort ändert.
Jede Engine wird unabhängig versioniert — eine Änderung an der einen verschiebt die Version der anderen nie.
Fehler
400
invalid_request
Schema-Fehler. details.path verweist auf das betreffende Feld.
401
unauthorized
API-Schlüssel fehlt oder ist unbekannt.
402
quota_exceeded
Monatskontingent erreicht. Retry-After gibt die Sekunden bis zum Monatswechsel an.
403
key_revoked
Der Schlüssel existiert, darf aber nicht verwendet werden: Er wurde widerrufen, oder das Engine-API-Abonnement des Kontos ist nicht mehr aktiv. Die message sagt, was von beidem.
404
not_found
Diese Route gibt es nicht — dasselbe erhalten Sie für den richtigen Pfad mit der falschen Methode.
413
too_large
Eingabe über einem Limit (siehe Limits).
429
busy
Kapazität momentan ausgeschöpft. Retry-After in Sekunden — das zählt nie auf Ihr Kontingent.
500
internal
Unerwarteter Fehler, oder das Auth-Backend ist nicht erreichbar (Anfragen werden dann abgewiesen — fail closed).
503
service_unavailable
Eine angeforderte Engine kann derzeit nicht bedient werden — die Nesting-Engine oder die asynchrone max-Engine. Bei max gibt es zwei Ursachen, und die message sagt welche: Die Stufe ist in dieses Deployment nicht eingebaut, oder sie ist eingebaut, aber der Worker, der die Jobs löst, antwortet nicht. Fail-closed vor der Reservierung eines Aufrufs, kostet also nie etwas.
504
solve_timeout
Die Berechnung hat ihre harte Zeitgrenze überschritten. Auf den rechteckigen Pfaden setzt der Proxy sie durch; bei /v1/optimize/nest setzt die Engine ihr eigenes, kürzeres Budget durch und antwortet mit solve_timeout im normalen Umschlag.
Fehler-Body
Jeder Fehler, den die Engine selbst erzeugt, verwendet denselben Umschlag. Verzweigen Sie über error — ein stabiler Code —, niemals über message, dessen Wortlaut sich zwischen Releases ändern kann. details ist bei invalid_request vorhanden, wo path das betreffende Feld benennt, und bei too_large, wo max und got das Limit und Ihren gesendeten Wert angeben.
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
{
"error": "invalid_request",
"message": "parts[0].h: must be greater than 0",
"details": { "path": "parts[0].h" }
}
402 und 429 tragen beide einen Retry-After-Header in Sekunden. Bei 402 zählt er bis zum Zurücksetzen des Kontingents am 1. des Folgemonats um 00:00 UTC herunter; bei 429 ist es ein kurzer Back-off, und ein 429 verbraucht nie Kontingent — der reservierte Aufruf wird zurückgegeben.
Ein Routing-Fehler antwortet mit not_found — ein Code, der bewusst außerhalb der Liste oben steht, weil ihn der Router erzeugt und nicht der API-Vertrag. Sie erhalten 404 und nicht 405, wenn der Pfad stimmt, die Methode aber nicht: alle vier Optimierungs-Endpoints nehmen ausschließlich POST.
Auf den rechteckigen Pfaden kommt 504 vom Reverse-Proxy, nicht von der Engine — der Body gehört deshalb dem Proxy und ist nicht dieser JSON-Umschlag; innerhalb der unten genannten Eingabelimits sollte er unerreichbar sein. /v1/optimize/nest ist die Ausnahme: Diese Berechnung ist ein Subprozess mit eigenem Budget, das bewusst unter der Proxy-Grenze liegt — ein Timeout dort verwendet also diesen Umschlag, mit dem Code solve_timeout.
Rate-Limit-Header
Ein erfolgreicher Optimierungsaufruf liefert X-RateLimit-Limit (das Monatslimit des KONTOS – alle Schlüssel des Kontos teilen sich eines) und X-RateLimit-Remaining (die dem Konto in diesem Monat verbleibenden Aufrufe, diesen eingerechnet). Gesendet werden sie ausschließlich von den Optimierungs-Endpoints: der Zähler wird als Teil der Freigabe einer Berechnung reserviert, deshalb haben /v1/usage und /v1/health nichts zu melden.
X-RateLimit-Limit
integer
The ACCOUNT’s monthly quota — the same number GET /v1/usage returns as limit, not a per-key cap (049).
X-RateLimit-Remaining
integer
Calls left this month on the ACCOUNT, after this one.
Nur lesend: verbraucht keinen Aufruf und sendet keine Rate-Limit-Header. ⚠️ used und limit beziehen sich auf das KONTO, nicht auf den Schlüssel, mit dem Sie aufgerufen haben: jeder aktive Schlüssel des Kontos schöpft aus einem gemeinsamen Kontingent, mehr Schlüssel bedeuten also nicht mehr Kontingent. used zählt den laufenden UTC-Kalendermonat über alle hinweg, remaining ist limit minus used und wird nie negativ, periodEnd ist der Rücksetztag als reines YYYY-MM-DD-Datum, und keyPrefix ist das nicht geheime Anzeigepräfix des verwendeten Schlüssels. Der Schlüssel selbst wird von keinem Endpoint zurückgegeben — gespeichert ist nur sein Hash, ein verlorener Schlüssel wird also ersetzt, nicht wiederhergestellt.
plan
string
Tier slug frozen onto the key when it was created.
used
integer
Calls counted in the current UTC calendar month across EVERY key on the ACCOUNT — revoked keys included, so revoking a key cannot un-spend what it spent (053).
limit
integer
The ACCOUNT’s cap: the largest monthly quota frozen onto any of its ACTIVE keys (049). Not a per-key allowance — more keys do not add quota.
remaining
integer
limit − used, never negative.
periodEnd
string
Reset day as YYYY-MM-DD — a date, not a timestamp.
Kein Schlüssel, kein Kontingent, keine Datenbank. Der Endpoint berührt bewusst nichts Zustandsbehaftetes, damit ein Ausfall des Schlüsselspeichers den Dienst für einen Orchestrator nicht tot aussehen lässt. engines listet die ids, die diese Installation in engine akzeptiert, und engineVersion ist die Version der Standard-Engine.
status
string
Always "healthy" when the process answers.
service
string
Always "cutoptim-engine".
contractVersion
string
Shape version. Currently "1".
engineVersion
string
The DEFAULT engine’s version, not a per-engine list.
engines
string[]
SYNCHRONOUS engine ids this deployment accepts in engine — ["heuristic","balanced"]. The async max tier is reported separately in maxEngines, never here.
modes
string[]
Optimize paths this deployment serves: "2d", "1d", "wood", plus "nest" only where the nesting engine is built in. Endpoint discovery without reading this page.
nestEngines
string[]
Nesting engine ids this deployment can serve — ["lbf"] on the production API, [] where the Rust nesting stage is not built in.
maxEngines
string[]
The async tree-search tier — ["max"] where it is enabled, [] otherwise. Health never advertises a capability it cannot serve.
uptimeSec
integer
Whole seconds since process start.
Limits
2,000 Teile pro Anfrage (Gesamtmenge, nach Auflösung von qty)
50 Materialzeilen · Request-Body bis 1 MB
10 aktive Schlüssel pro Konto — sie teilen sich EIN monatliches Kontingent; Schlüssel trennen Umgebungen und Integrationen, sie erhöhen das Kontingent nicht
10 MB Anfragerumpf auf den beiden nest-Pfaden, die eine Zeichnung tragen können (/v1/optimize/nest und /v1/import/nest); eine source-Datei höchstens 4.000.000 Zeichen, 8.000.000 pro Anfrage
die Parallelität ist serverseitig begrenzt — ein Burst erhält 429, niemals eine langsame Warteschlange. Die schlüssellosen Validate-Endpunkte haben zusätzlich eine Obergrenze je Adresse (429 mit Retry-After); mit Schlüssel wird nie so gedrosselt. Ein Konto darf gleichzeitig 5 max-Jobs in queued/running halten.
OpenAPI-Spezifikation
Ein maschinenlesbares OpenAPI 3.1-Dokument beschreibt alle zwölf Endpoints, jeden Request-Body, jede Antwortstruktur und jeden Fehler. Richten Sie Ihren Client-Generator darauf, statt diese Seite abzuschreiben. Das Dokument selbst ist ausschließlich englisch: es besteht aus Contract-Tokens, und OpenAPI besitzt keinen Lokalisierungsmechanismus.
A two-page summary of the Engine API — the four modes (2D, 1D, wood and true-shape nest), a request and response, determinism and pricing. Print-ready, with a QR back to the docs.