Engine API
Dacă doar tai panouri, nu ai nevoie de această pagină. Optimizatorul din CutOptim face deja tot ce este descris aici. Engine API este același motor, doar fără ecran, pentru situația în care alt software are nevoie de planuri de tăiere fără ca o persoană să deschidă aplicația.
Tot ce face CutOptim în browserul tău pornește de la un singur calcul: având aceste piese și acest material de bază, care este cel mai bun mod de a le tăia? Engine API expune exact acel calcul prin internet, astfel încât un alt program să poată pune întrebarea și să primească răspunsul înapoi — fără browser, fără clicuri, fără ca nimeni să fie autentificat.
Asta este toată ideea. Nu este un optimizator nou, nu este un optimizator mai bun și nu este un plan mai mare. Este același motor, accesibil pentru software în loc de o persoană.
Este pentru mine?
Pentru marea majoritate a utilizatorilor CutOptim, răspunsul sincer este nu. Dacă ziua ta de lucru înseamnă să deschizi CutOptim, să introduci piesele și materialul de bază și să tipărești sau să exporți planul, aplicația este produsul, iar această pagină nu te privește.
Engine API este pentru o singură situație: planurile de tăiere trebuie să apară în interiorul unui software pe care îl folosești deja, fără ca nimeni să intre pe CutOptim. În practică, asta înseamnă una din două persoane:
- Folosești deja un software în care planul de tăiere își are locul. Un ERP care ține comenzile, o aplicație de ofertare care calculează prețul lucrărilor sau software-ul propriu al unei mașini. În loc ca un operator să reintroducă aceeași listă de piese în CutOptim, acel program întreabă direct motorul și afișează planul acolo unde se lucrează deja.
- Se construiește un software pentru tine. De un programator intern, de o firmă locală de software sau de furnizorul mașinii tale. Engine API este ceea ce conectează ei.
Folosirea Engine API înseamnă că cineva scrie software care îl apelează. Nu există interfață, nu există niciun tabel de completat și nu ai nimic de instalat — este un serviciu pentru programe, iar munca este făcută de cine scrie acel program. Dacă nimeni de partea ta nu scrie cod, aplicația este ceea ce îți trebuie.
Dacă nu ești sigur de care parte a liniei te afli, un test bun: ar putea apărea planul fără ca nimeni să îl ceară? Dacă da, API-ul este relevant. Dacă întotdeauna o persoană decide să facă un plan de tăiere, aplicația este deja instrumentul potrivit.
Ce face
Software-ul tău trimite aceleași două lucruri pe care le-ai introduce în aplicație — o listă de piese și o listă de material de bază — ca JSON. Motorul trimite înapoi un răspuns complet:
- Layoutul complet. Fiecare piesă, poziționată pe o anumită placă sau bară, inclusiv dacă a fost rotită.
- Un plan de tăiere. Nu doar o imagine cu dreptunghiuri: secvența reală de tăiere ghilotină, în ordine, astfel încât planul să poată fi executat pe un ferăstrău pentru panouri.
- Cifrele. Câte plăci sau bare consumă lucrarea, procentul de randament, câte tăieri sunt necesare și prețul total al materialului folosit. Pentru panouri primești și cele două numere oneste de tăieri — linii de tăiere, care unifică tăierile ce împart aceeași reglare a opritorului, și treceri de ferăstrău, care numără fiecare trecere — plus lungimea totală tăiată.
- Opțional, desenul. Cere
include: ["svg","csv","dxf"], iar răspunsul poartă în plus layoutul ca fișier gata făcut — un desen SVG 2D de sine stătător, un DXF R12/AC1009 sau o listă de tăiere CSV — inline în JSON, fără stocare și fără un al doilea apel. (SVG este doar 2D.) În cererile 2D poți cere șilabels(date de etichetă pe piesă),planHash(o amprentă a planului),pdf(PDF-ul planului de tăiere) șilabelsPdf(PDF-ul etichetelor) — PDF-urile codate base64, desenate cu același cod ca aplicația. - Propriii tăi identificatori, returnați. Atașează un obiect
meta— un număr de articol, o linie de comandă, o referință de client — oricărei piese sau oricărui rând de material, iar el revine neschimbat pe fiecare piesă plasată și pe fiecare placă sau bară, astfel încât planul să se potrivească cu propriul tău sistem. Acesta este câmpul de folosit când vrei să trimiți toate plăcile tale, să marchezi fiecare cu propriul tău cod și să citești înapoi ce placă a ales optimizatorul — pui codul înstock[].metași îl primești identic pesheets[].meta. Nu influențează niciodată plasarea. Nu folosi câmpulmaterialpentru identificare:materialeste o partiționare strictă — o piesă este tăiată doar din material de bază care poartă aceeași etichetămaterial—, așa că etichetarea fiecărui rând de material, lăsând piesele neetichetate, face ca toate piesele să revină caunmatched, iar rezultatul să fie gol.
Sunt patru moduri de optimizare, toate corespunzând aplicației — unul pentru plăci 2D, unul pentru material 1D liniar (bare, profile, țeavă), unul pentru lemn, al cărui material are o secțiune, și nesting-ul true-shape (POST /v1/optimize/nest), care aranjează poligoane arbitrare pentru tăiere cu laser, plasmă și jet de apă (modul Nesting al aplicației). Fiecare endpoint de optimizare are și un endpoint gratuit de validare, care verifică o cerere fără să o rezolve (vezi mai jos).
Endpointuri
URL-ul de bază este https://api.cutoptim.com. Endpointurile de optimizare și de consum poartă o cheie în antetul Authorization: Bearer <key>; endpointurile de validare și de disponibilitate nu au nevoie de cheie.
| Endpoint | Ce face |
|---|---|
POST /v1/optimize/2d |
optimizare 2D pentru panouri |
POST /v1/optimize/1d |
optimizare 1D / liniară — bare, profile, țeavă |
POST /v1/optimize/wood |
Optimizarea lemnului — 1D cu potrivirea secțiunii |
POST /v1/optimize/nest |
Nesting true-shape — poligoane neregulate pentru laser, plasmă și jet de apă |
POST /v1/validate/2d · /1d · /wood · /nest |
Validează o cerere fără s-o rezolve — gratuit, fără cheie, fără cotă |
GET /v1/jobs/{id} |
Interoghează o lucrare asincronă a motorului max — doar propriile lucrări, fără cotă |
POST /v1/import/nest |
Citește conturul pieselor dintr-un fișier SVG sau DXF — necesită o cheie, nu consumă cotă |
GET /v1/usage |
consumul și cota CONTULUI în luna curentă (toate cheile împart una) |
GET /v1/health |
verificare de disponibilitate — fără cheie |
Cele mai multe apeluri primesc direct rezultatul final. Singura excepție este motorul asincron max (vezi Trei motoare mai jos): o trimitere max returnează un id de lucrare, iar tu interoghezi GET /v1/jobs/{id} până când planul este gata.
Endpointurile de validare preiau același corp ca endpointul de optimizare corespunzător și îl verifică fără a rula rezolvarea: o cerere malformată revine ca un 400 care numește exact câmpul greșit, iar una bine formată returnează valid: true plus avertismente de fezabilitate (de exemplu, o piesă care nu încape în niciun material). Nu costă nimic și nu au nevoie de cheie, așa că îți poți valida payload-urile în timp ce construiești integrarea — încă înainte de a avea o cheie — și poți confirma că o cerere nu va fi respinsă fără să consumi unul dintre apelurile tale lunare.
Direcția fibrei la panouri
Placajul și plăcile furniruite au fibră, iar o piesă vizibilă trebuie tăiată cu fibra mergând în direcția corectă. Pe POST /v1/optimize/2d, trimite grain pe un rând de stoc — "w" sau "h", latura plăcii de-a lungul căreia merge fibra — și grain pe o piesă, latura piesei de-a lungul căreia trebuie să meargă. Fiecare astfel de piesă este plasată cu fibra de-a lungul fibrei plăcii sale: rotită cu 90° când asta este necesar (rotated: true pe plasare, ca la orice rotire), iar rotatable este ignorat pentru ea. O piesă fără grain se rotește în continuare liber, și pe un rând de stoc fără grain (MDF, melaminat); o piesă CU grain își păstrează și pe un astfel de rând orientarea pe care i-o dau rândurile cu fibră — material separă plăcile cu fibră de cele simple. O piesă care ar încăpea doar rotită la 90° împotriva fibrei apare în unplaced la dimensiunea trimisă, o linie din warnings o numește, iar POST /v1/validate/2d o semnalează înainte să se consume un apel.
Rândurile de stoc ale căror fibre merg în direcții diferite pot sta într-o singură cerere — un 2440 × 1220 cu "w" și un 1220 × 2440 cu "h" — iar fiecare placă revine în orientarea propriului rând, cu grain repetat în sheets[]. Cu material, o piesă este ținută de o fibră doar când propriul ei material are o placă cu fibră. grain-ul unei piese, fără stoc cu fibră în cerere, nu are niciun efect, iar o linie din warnings spune asta. options.trim și un options.firstCut forțat se aplică fiecărei plăci în orientarea propriului rând, inclusiv pe un rând a cărui fibră merge în cealaltă direcție. Modul Direcția fibrei din aplicația CutOptim rulează același cod. (Începând cu 2026-10-02.)
Potrivirea fibrei la panouri (seturi cu fibră potrivită)
Direcția fibrei păstrează fibra fiecărei piese în direcția corectă. Unele fronturi cer mai mult: un front de sertar deasupra a două uși al cărui desen continuă de la una la alta, ca și cum cele trei ar fi încă o singură placă. Pe POST /v1/optimize/2d, dă acelor rânduri de piese un id și numește-le în matchedSets:
{
"parts": [
{ "id": "DF", "name": "Drawer front", "w": 48.125, "h": 6 },
{ "id": "DOOR", "name": "Door", "w": 24, "h": 30, "qty": 2 },
{ "name": "Shelf", "w": 22.5, "h": 11.25, "qty": 4 }
],
"stock": [{ "w": 96, "h": 48, "qty": 2, "grain": "w" }],
"options": { "kerf": 0.125 },
"matchedSets": [
{ "id": "base-1", "name": "Base cabinet fronts", "grain": "w",
"layout": { "dir": "rows", "lines": [["DF"], ["DOOR", "DOOR"]] } }
]
}
- Ce este un set.
layout.lineslistează membrii dupăparts[].id. Cudir: "rows"fiecare linie este un rând de membri una lângă alta, iar rândurile se așază de sus în jos, deci[["DF"], ["DOOR", "DOOR"]]este un front de sertar deasupra a două uși; cu"cols"fiecare linie este o coloană, iar coloanele stau una lângă alta. O piesă poate apărea de mai multe ori într-un set (Door, Door), dar poate aparține unui singur set.qty(implicit 1) este câte instanțe îți trebuie — trei corpuri identice înseamnăqty: 3— iarqty-ul propriu al pieselor trebuie să acopere fiecare instanță. Un set are cel puțin 2 și cel mult 24 de membri, iar o cerere acceptă cel mult 50 de seturi. - Cum se taie. Setul trece prin optimizator ca un singur dreptunghi — blocul — și revine ca membrii lui, la exact un kerf distanță, dintr-o singură bucată de placă.
grain-ul setului ("w"sau"h", de-a lungul lățimii sau înălțimii blocului) decide direcția fiecărui membru;grain-ul propriu al unui membru nu este folosit în interiorul setului, iar un avertisment numește orice membru pe care îl înlocuiește. Fărăgrainpe set, blocul se poate roti atunci când fiecare membru esterotatable.installGapeste distanța dintre membri pe corp (implicit: kerf-ul); pe placă ei rămân la un kerf distanță. - Ce revine. Fiecare membru plasat poartă
matchedSet:id-ul setului, ceinstanceeste șipositionîn ordinea de citire pe fața corpului — de sus în jos, de la stânga la dreapta, începând de la 1 — plus unhintprecum"left"sau"right"acolo unde nu e ambiguu. Răspunsul adaugă un rezumatmatchedSets, câte o intrare pe set:letter(A, B … în ordinea cererii), câte instanțe au fost tăiate ca bloc (asBlock), împărțite sau lăsate neplasate, dimensiunea blocului șiwarningsale setului. Când un bloc nu încape pe nicio placă,onMiss: "split"(implicit) plasează membrii unul câte unul cu un avertisment, iaronMiss: "unplaced"îi listează înunplaced. - Avertismente, nu erori. O dimensiune care nu se aliniază este un avertisment pe set, nu un refuz. Fiecare linie începe cu codul ei —
align:(liniile nu sunt la același nivel),gap:(kerf-ul este mai lat decâtinstallGap),grain:,split:,unplaced:,unmatched:(nu există stoc din materialul setului),priority:șigrainGroup:— iaralignșigapsunt judecate la 1/64 din unitatea ta sau un sfert de kerf, care dintre ele e mai mică. Un set care nu poate fi aranjat deloc — un id de membru pe care nu-l poartă nicio piesă, un id referit pe două piese, mai puțin de doi membri, prea puține piese pentruqty— este un400care numește câmpul exact, înainte ca un apel să fie taxat. parts[].idpoate fi trimis în siguranță. Doar un id la care se referă un set este verificat (un șir imprimabil nevid de cel mult 64 de caractere sau un întreg, pe exact o piesă). Orice alt id este ignorat, oricât ar conține, deci numerele de articol din ERP pot rămâne pe rânduri. Și nimic nu se schimbă pentru o cerere fără seturi: doar un arraymatchedSetsnevid activează funcția — absent,null,[]sau orice valoare care nu este array primește exact același răspuns ca înainte.- Exporturi. Cu seturi,
csvprimește la final coloaneleSetșiPosition,svgtipărește codul de poziție (A1, A2 …) în etichetele pieselor și desenează cadrul fiecărui set într-un grup separatmatched-sets—options.setOutlines: falselasă grupul deoparte — iardxfpoartă codul de poziție pe stratul LABELS.pdfșilabelsPdfnu marchează seturile: desenează membrii ca piese obișnuite, iarwarningsspune asta; marcajele setului sunt însheets[].parts[].matchedSet,csvșisvg. - Motoare și endpointuri. Motoarele
heuristicșibalancedaranjează seturi (balancednu ierarhizeazăpriority, deci subrespectStockun set își poate pierde locul acolo, cu un avertismentpriority:). Motorulmaxrefuză unmatchedSetsnevid cu un400al căruidetails.unsupportedîl numește, înainte ca un apel să fie taxat; unul gol este o lucraremaxobișnuită.matchedSetsșiparts[].idsunt doar pentru 2D: endpointurile 1D, wood și nest le ignoră. grainGroupeste depreciat. Este încă acceptat și funcționează exact ca înainte: piesele care împart un grup sunt ținute pe o singură placă. Nu le-a plasat niciodată una lângă alta, deci nu dă fibră continuă între ele — pentru asta, foloseștematchedSets.
Potrivirea fibrei din aplicația CutOptim aranjează seturile cu același nucleu.
De ce lemnul are endpoint propriu
Materialul liniar cunoaște o singură dimensiune, lungimea, așa că orice bară poate servi oricărei piese. La lemn nu este așa: o piesă 50×150 nu poate ieși dintr-o bară 50×100, oricâtă lungime ar rămâne. De aceea endpointul pentru lemn preia ambele laturi ale secțiunii pentru fiecare piesă și fiecare rând de material, împarte lucrarea pe secțiuni, potrivește fiecărei secțiuni materialul ei și returnează secțiunile separat — fiecare cu barele și totalurile proprii, alături de cifrele pentru întreaga lucrare.
Două detalii de știut înainte de integrare:
-
Cele două laturi ale secțiunii pot fi trimise în orice ordine. 50×100 și 100×50 sunt aceeași grindă întoarsă și formează o singură secțiune. Astfel, o diferență în felul în care au fost introduse datele tale nu poate face materialul să dispară.
-
„Niciun material de această secțiune” și „nu a încăput” se raportează separat. Primul înseamnă material lipsă, al doilea o problemă de capacitate, iar rezolvarea diferă — amestecate într-o singură listă, l-ar trimite pe utilizatorul tău să caute în locul greșit.
Ai putea aproxima asta cu mai multe apeluri 1d proprii, grupând piesele singur. Te-ar costa o cerere din cotă pentru fiecare secțiune în loc de una pentru lucrare, ar muta potrivirea materialului în codul tău și ar produce un total pe care ar trebui să-l compui singur — și care nu ar coincide neapărat cu ce arată aplicația CutOptim pentru aceeași lucrare.
Piese dintr-un fișier CAD
Endpointul de nesting nu acceptă doar coordonate. O piesă poate purta în schimb un source — un document SVG sau DXF — iar serverul îi extrage conturul, și găurile din el, din fișier. Este același cititor pe care aplicația îl folosește când tragi un desen peste modul ei Nesting, deci o bibliotecă de piese care există deja ca fișiere CAD nu trebuie rescrisă mai întâi în liste de coordonate.
Fișierul înlocuiește doar geometria. Cantitatea, materialul, rotațiile permise și propriile tale metadate rămân câmpuri obișnuite ale rândului piesei, exact ca atunci când trimiți coordonate. Un fișier descrie o piesă; când un singur desen conține mai multe componente separate, POST /v1/import/nest îl împarte întâi în rânduri gata de folosit — iar acel apel necesită o cheie, dar nu consumă o cerere din cota ta lunară.
Nimic nu se stochează. Fișierul există doar ca cererea însăși: este citit în memorie și dispare în momentul în care răspunsul este scris. Nu rămâne nicio copie pe disc sau într-o bază de date, nimic nu ajunge într-un jurnal și nu este nimic de șters după aceea. Cu unitățile procedăm la fel — un DXF poate declara milimetri sau inci și noi raportăm ce a spus, dar coordonatele nu sunt niciodată convertite, fiindcă nicio valoare din acest API nu poartă o unitate.
Același răspuns de fiecare dată
Motorul este determinist: aceeași intrare produce întotdeauna același rezultat. Nu există aleatoriu și nu există ceas în algoritm.
Sună academic, dar este exact motivul practic pentru care merită să construiești pe el. Înseamnă că rezultatele pot fi puse în cache — dacă ai întrebat deja despre exact aceeași lucrare, poți refolosi liniștit răspunsul în loc să întrebi din nou. Înseamnă și că integrarea poate fi testată: un plan poate fi comparat cu un rezultat cunoscut ca bun, iar o diferență este o diferență reală, nu zgomot. Un software care dă luni un preț unui client va da vineri același preț.
Există o singură excepție opțională, și o spune ea însăși: motorul max pentru nesting (mai jos) cheltuiește un buget de timp fix căutând, așa că până unde ajunge depinde de câtă muncă încape în acel timp. Răspunsurile sale poartă deterministic: false. Orice alt motor — inclusiv cel implicit pentru nesting, lbf — este determinist.
Reîncercări sigure. Dacă se întrerupe conexiunea, nu știți dacă cererea a ajuns. Trimiteți antetul Idempotency-Key — o valoare aleasă de dumneavoastră pentru fiecare lucrare — și reîncercați cu aceeași cheie: timp de 24 de ore, aceeași cerere returnează răspunsul salvat, marcat Idempotency-Replayed: true, și nu se taxează a doua oară. Nici o lucrare max nu intră de două ori în coadă. Cheia demo publică ignoră acest antet. (Din 2026-10-15.)
Webhookuri pentru lucrările asincrone. În loc să interogați GET /v1/jobs/{id}, înregistrați un endpoint (un URL https://) în panou și primiți un POST semnat — job.succeeded sau job.failed — când o lucrare max asincronă se termină. Verificați antetul CutOptim-Signature cu secretul primit, răspundeți în 10 secunde și citiți planul cu GET /v1/jobs/{id}. O livrare eșuată se reîncearcă: 8 încercări în 24 de ore. (Din 2026-10-19.)
SDK-uri oficiale. Clienți open source pentru TypeScript, Python și PHP — npm install @cutoptim/engine, pip install cutoptim, composer require cutoptim/engine — cu cereri tipizate, reîncercări care nu se taxează niciodată de două ori (fiecare apel poartă un Idempotency-Key), un ajutor pentru așteptarea lucrărilor asincrone și verificarea webhookurilor. Codul pe GitHub; detalii în ghidul SDK (în engleză).
Server MCP pentru asistenți AI. Claude Code, Cursor, VS Code și Claude Desktop pot apela motorul ca instrumente prin serverul Model Context Protocol găzduit la https://api.cutoptim.com/mcp, cu aceeași cheie API (Authorization: Bearer …) și din aceeași cotă: un apel de instrument este un apel API, iar instrumentele validate_* sunt gratuite. Rulează și local, cu pachetul npx -y @cutoptim/mcp (cheia în CUTOPTIM_API_KEY), iar MCP Registry oficial îl listează ca io.github.cutoptim/engine. Configurațiile clienților sunt în ghidul MCP (în engleză).
Trei motoare
API-ul oferă mai multe variante de motor. Primele două rulează sincron; al treilea este asincron. Diferența nu este de calitate — este un compromis între viteză, faptul că rezultatul poate fi tăiat sau nu pe un ferăstrău pentru panouri și cât de aproape ajunge de minimul teoretic.
heuristiceste cel implicit și este același pe care îl folosește aplicația. Produce aranjamente ghilotină: cel mai bun randament, fiecare aranjament tăiabil pe ferăstrău și întotdeauna un plan de tăiere complet. Sincron.balancedse activează explicit. Folosește în schimb nesting liber, care este dramatic mai rapid la lucrările foarte mari — măsurat aproximativ 25× mai rapid la o lucrare de 2.000 de piese — cu prețul unui randament puțin mai mic. Reținerea importantă: aranjamentele sale adesea nu pot fi tăiate de la o margine la alta, așa că pentru acelea nu returnează niciun plan de tăiere. Sincron.maxse activează explicit, pentru panouri 2D (și, separat, pentru nesting true-shape — vezi mai jos). La 2D este o căutare în arbore pe server care atinge optimul demonstrat pe mult mai multe lucrări decât cel implicit, iar aranjamentele sale rămân tăiabile ghilotină. Costul este timpul: o rezolvaremaxdurează de la câteva secunde până la un minut, deci nu răspunde în cadrul răspunsului. În schimb,POST /v1/optimize/2dcuengine: "max"returnează un id de lucrare, iar tu interogheziGET /v1/jobs/{id}până când este gata. Rămâne determinist. Apelează la el atunci când o lucrare mare și valoroasă merită așteptarea pentru ultimele câteva plăci. Modelează un singur format de stoc la dimensiunea completă a plăcii, cu disponibilitate nelimitată, așa că o cerere care mai poartă un al doilea format de stoc,trimpe laturi, stoc limitat (respectStock), materiale, grupuri de fibră sau unmatchedSetsnevid este refuzată din start cu un400care numește exact ce nu poate face — înainte ca un apel să fie taxat. Trimite acele lucrări cătreheuristic, care le modelează pe toate.
Nesting: lbf și max
Nesting-ul true-shape are propriile sale două motoare. lbf este cel implicit: instantaneu, sincron și determinist. max se activează explicit și este asincron, exact ca max la 2D — POST /v1/optimize/nest cu engine: "max" returnează un id de lucrare, iar tu interoghezi GET /v1/jobs/{id}.
max pentru nesting rulează întâi trecerea lbf, așa că are mereu un răspuns valid la îndemână. Apoi cheltuiește un buget de timp (options.timeBudgetMs, 60 de secunde implicit, între 10 și 180) căutând un aranjament cu mai puține plăci, umplând câte o placă odată. Nu returnează niciodată mai multe plăci decât lbf: când căutarea nu găsește nicio îmbunătățire, primești aranjamentul lbf și un avertisment care spune asta. Pentru că această căutare este limitată în timp, răspunsurile ei poartă deterministic: false. Acceptă mai multe dimensiuni de placă per material și respectStock, și își ordonează rezultatul cu aceeași regulă ca lbf (mai jos): înlocuiește planul lbf doar atunci când este mai bun — niciodată doar pentru că are mai puține plăci. O placă poligonală sau zonele de excludere, pe care căutarea sa în bandă nu le poate modela, sunt deservite de trecerea lbf din interiorul lucrării, cu un avertisment — niciodată refuzate. Vechiul nume sparrow este acceptat ca alias pentru max.
Piesele dreptunghiulare primesc o grilă exactă (din 2026-09-28). lbf găsește pozițiile prin eșantionare, iar aceasta aproape niciodată nu nimerește o grilă fără nicio rezervă: trei piese de 500 mm pe lățimea unei plăci de 1500 mm la spațiere zero încap exact, iar o căutare prin eșantionare așază doar două. De aceea ambele motoare încearcă și două alternative și o păstrează pe cea care se clasează cel mai bine după aceeași regulă: piesele restrânse la unghiurile drepte pe care le permit, și dreptunghiurile de încadrare ale pieselor așezate de un algoritm exact de așezare a dreptunghiurilor (dreptunghiurile care nu se suprapun nu pot conține piese care se suprapun, așa că metoda este validă pentru orice contur). La egalitate — aceleași plăci, aceeași arie de placă — câștigă planul care își umple plăcile în ordine, de la prima la ultima, apoi cel cu mai puține piese rotite în afara unghiurilor drepte. Nu este nimic de activat, iar prin această ordonare un rezultat poate doar să se îmbunătățească; un plan pe care dreptunghiurile îl aduc la cel mai mic număr de plăci permis de aria pieselor face și ca max să răspundă imediat, în loc să mai caute.
O lucrare cu câteva zeci de piese are de obicei nevoie de un buget de aproximativ 15 secunde (timeBudgetMs: 15000); lucrarea se termină la aproximativ una-două secunde după buget, plus timpul petrecut în coadă. Interoghează GET /v1/jobs/{id} la fiecare două-trei secunde — interogarea nu consumă cotă. Niciun buget nu poate promite un anumit număr de plăci.
Nesting: distanța de la marginea plăcii, dimensiunile plăcii și costul fiecărei plăci
- Distanța de la margine.
options.minSeparationeste spațierea dintre piese și, de una singură, se aplică și la marginea plăcii.options.edgeClearancesetează marginea separat — de exemplu 5 între piese și 0 sau 10 la margine. Omite-l și marginea păstreazăminSeparation, exact ca înainte. Funcționează pe ambele motoare, are nevoie de plăci dreptunghiulare (wșih), iar zonele de excludere păstreazăminSeparation, la fel ca piesele. O placă poligonală, sau o valoare care nu lasă loc pe placă, este refuzată cu un400înainte ca un apel să fie taxat. - Alegerea unei dimensiuni de placă. Când un material are două sau mai multe rânduri de material de bază,
lbfle încearcă în ordinea ta, fiecare dimensiune separat și într-o ordine de la cel mai ieftin în sus, și o păstrează pe cea mai bună — așa că rezultatul nu mai depinde de ordinea în care listezi rândurile. Ordonarea este: cele mai multe piese de tăiat obligatoriu plasate (vezi mai jos), apoi cele mai multe piese plasate, apoi cea mai mică arie totală de placă (material), apoi cele mai puține plăci. Cuoptions.minimizeCostordonează în schimb după prețul total (price, saucostpentru un rând fără preț) — dar numai atunci când fiecare rând al acelui material poartă unul; altfel revine la arie și spune asta înwarnings. - Amestecarea dimensiunilor. După aceea, fiecare placă — cea mai puțin umplută mai întâi — este renestuită pe cont propriu pe rândurile mai ieftine sau mai mici și înlocuită atunci când întregul plan clasează mai bine. Așa că dimensiunile pot fi amestecate în cadrul unui material: de obicei două plăci mari și una mai mică la final, acolo unde ultima placă pe jumătate goală era înainte una mare. Cu
options.respectStock, niciun rând nu este folosit mai des decâtqtyal lui. Motorulmaxaplică aceeași ordonare. - Piese de tăiat obligatoriu.
parts[].priority: truemarchează o piesă care trebuie tăiată. Contează cuoptions.respectStock— o ofertă plafonată, unde nu toate piesele pot încăpea: piesele de tăiat obligatoriu sunt atunci plasate primele, așa că o piesă obișnuită nu ocupă niciodată spațiul de care are nevoie o piesă de tăiat obligatoriu, iar fiecare ordonare de mai sus pune înainte planul care păstrează mai multe dintre ele, chiar dacă plasează mai puține piese în total. Ambele motoare respectă asta (maxpăstrează aranjamentullbfori de câte ori rămâne ceva neplasat). FărărespectStock, orice piesă care încape este plasată oricum, așa că marcajul nu schimbă nimic. O piesă de tăiat obligatoriu care nu încape pe nicio placă rămâne totuși listată înunplaced. (Din 2026-09-22 — înainte, motorul de nesting accepta câmpul, dar îl ignora.) - Stoc limitat pe care nu încape tot. Cu
options.respectStock, dacă planul lasă încă piese neplasate, motorul umple în plus plăcile una câte una cu dreptunghiurile de încadrare ale pieselor — fiecare cât de plină se poate, iar o piesă care încape doar pe o singură dimensiune de placă merge acolo prima (o latură înaltă pe singura placă mare, nu pe o fâșie de rest). Planul este preluat doar dacă plasează mai multe piese (cele obligatorii întâi) sau folosește mai puțin material; o lucrare la care încape tot revine exact ca înainte. Respectă rotațiile permise ale fiecărei piese,minSeparationșiedgeClearance. (Din 2026-10-14.) - Ce a costat fiecare placă. Fiecare placă poartă
stock— indexul rândului de material de bază din cerere din care a fost tăiată — iar răspunsul adaugăstockUsage: câte o intrare pentru fiecare rând de material de bază folosit, cu numărul de plăci, prețul total și densitatea. Unitatea este rândul de material de bază, nu dimensiunea: două rânduri cu aceleași dimensiuni, dar cu preț saumetadiferit, sunt două intrări. - Lungimea de tăiere și străpungerile. Fiecare placă poartă
cutLength— perimetrul însumat al conturilor și al găurilor pieselor sale plasate, în unitatea ta — șipierces, unul per contur închis;metricstotalizează ambele. Este lungimea geometrică a conturului: fără tăiere pe linie comună, intrări de tăiere sau micro-îmbinări — CAM-ul tău le adaugă pe acelea. - Aria utilizată, pentru facturarea unei părți de placă. Fiecare placă poartă
usedWidthșiusedHeight— cel mai îndepărtat punct la care ajunge orice piesă plasată din colțul de origine al plăcii, în unitatea ta, pe placa reală (cuedgeClearanceeste inclus și golul de la margine) — șiusedArea, produsul lor;stockUsage[].usedAreaîl totalizează pe rând de material de bază. Asta îi trebuie unui ERP ca să factureze o tăiere orizontală (usedHeight× lățimea plăcii), o tăiere verticală (usedWidth× înălțimea plăcii) sau bounding box-ul (usedArea) în loc de placa întreagă — regula de facturare rămâne a ta. Ca să facă aceste cifre mici, ambele motoare compactează implicit placa cea mai puțin umplută a fiecărui material: piesele ei sunt renestuite pe aceeași placă cu subseturi de rotații din cele permise fiecărei piese — 0/180, 0/90/180/270 și o singură orientare pentru fiecare copie, intersectate cu unallowedRotationsdiscret, niciodată un unghi nou — iar aranjamentul cu cea mai mică arie utilizată este păstrat. Cuengine: "max", placa respectivă este apoi rearanjată și de căutarea propriu-zisă — de-a lungul înălțimii plăcii și, dacă planul are o singură placă, și de-a lungul lățimii — și se păstrează, după aceeași regulă, aranjamentul mai strâns. Numărul de plăci, dimensiunile, prețul și piesele plasate nu se schimbă niciodată;options.compact: falsereturnează aranjamentul necompactat. Dacă facturezi o fâșie în loc de bounding box, seteazăoptions.compactForpentru a alege:"horizontal"păstrează aranjamentul cu cea mai micăusedHeight(o fâșie pe toată lățimea plăcii),"vertical"pe cel cu cea mai micăusedWidth(o fâșie pe toată înălțimea plăcii); implicit"box"păstrează cea mai micăusedArea. Modurile de fâșie mai încearcă și fiecare copie rotită cu un sfert (90° sau 270°) acolo undeallowedRotationspermite. Cât de mică ajunge aria utilizată depinde de piese. (Din 2026-09-22.)
balanced nu înseamnă „rezultate mai bune”. Este mai rapid și dă un randament puțin mai mic, iar când aranjamentul său nu este tăiabil ghilotină nu există niciun plan de tăiere de dat unui operator de ferăstrău. Alege-l doar când viteza la o lucrare foarte mare contează mai mult decât un plan gata de ferăstrău. Dacă nu ești sigur, rămâi pe varianta implicită.
Limite
Fiecare cerere este mărginită, așa că o lucrare scăpată de sub control eșuează clar, în loc să rămână blocată:
| Limită | Valoare |
|---|---|
| Piese per cerere | 2.000 |
| Rânduri de material per cerere | 50 |
| Dimensiunea corpului cererii | 1 MB |
| Dimensiunea corpului cererii — rutele nest care pot purta un desen | 10 MB |
| Chei active per cont | 10 |
Apeluri validate fără cheie per adresă |
120 / minut |
| Chei API necunoscute per adresă | 30 / minut — apoi 429 pentru restul minutului |
| Așteptare pentru un loc de calcul liber (trasee sincrone) | circa 8 s — apoi 429, nu se taxează nimic |
Lucrări max în queued/running per cont |
5 |
Bugetul de căutare al max pentru nesting, per lucrare |
10–180 s (implicit 60 s) |
Păstrarea Idempotency-Key |
24 de ore |
| Endpointuri webhook pe cont | 5 |
| Încercări de livrare webhook | 8 în 24 de ore |
Obținerea accesului
Pornește de la pagina Engine API. Engine API se facturează separat de planurile aplicației și nicio schimbare de plan nu îl activează.
- Încearcă, apoi abonează-te — sau scrie-ne. Poți apela API-ul înainte să plătești: butoanele Rulează acest exemplu din documentația API folosesc o cheie demo publică, iar orice cont autentificat poate crea în panou chei de test gratuite (propria alocare lunară mică, nu se facturează niciodată, fără abonament). Când ești gata, abonarea din pagina Engine API este calea cea mai rapidă — planul de intrare, Studio, începe cu o perioadă de probă gratuită, iar accesul ajunge singur în cont. Dacă preferi să descrii mai întâi integrarea sau ai nevoie de un volum peste planul standard, scrie-ne și spune ce vrei să conectezi și aproximativ câte planuri de tăiere pe lună va fi nevoie.
- Accesul este adăugat pe contul tău. Nimic altceva la contul tău nu se schimbă.
- Creează o cheie. Cardul Chei API este în panoul de control pentru orice cont autentificat: fără abonament creează chei de test, cu acces API și chei live. Îți creezi, denumești și ștergi singur cheile de acolo.
- Copiază imediat cheia. Cheia completă este afișată exact o singură dată, în momentul în care o creezi.
O cheie este afișată o singură dată. CutOptim stochează doar un hash sha256 al ei, niciodată cheia în sine — deci nu poate fi citită înapoi mai târziu, nici de tine, nici de noi. Copiază-o direct în configurația software-ului tău atunci când o creezi. Dacă pierzi o cheie, șterge-o și creează una nouă; dacă o cheie ajunge vreodată să fie expusă, șterge-o și apelurile încetează să funcționeze imediat.
Tratează o cheie ca pe o parolă: locul ei este în configurația software-ului tău, nu într-un email, într-un tabel sau într-o captură de ecran.
Ce face cardul Chei API din panoul tău
Patru comenzi — și merită spus exact ce schimbă fiecare, mai ales ultima, despre care mulți cred că ține de facturare. Nu ține.
- Plan, schimbarea planului și Facturare. Arată pe ce plan se află contul (Studio sau Scale). Treci la Scale (sau Treci la Studio) schimbă planul după o confirmare, iar cota lunară a contului se modifică imediat. Facturare deschide setările tale de facturare, unde actualizezi cardul, vezi facturile sau anulezi.
- Creează cheie. Generează o cheie nouă și o afișează o singură dată, chiar acolo. Numele (
Integrare ERP,staging) există doar ca să le deosebești mai târziu. Până la 10 chei active per cont. Cheile de test se creează la fel și se numără separat: au propria alocare lunară mică și nu se facturează niciodată. - Bara de consum. Două cifre: totalul contului pe luna calendaristică față de cotă și, pentru fiecare cheie, cât a consumat ea. Cifra pe cheie răspunde la care integrare consumă alocarea — nu este un buget separat.
- Revocă. Scoate din uz acea singură cheie, începând cu următorul apel. Rândul rămâne vizibil, ca istoricul să nu se piardă.
Revocarea unei chei nu are legătură cu abonamentul. Nu anulează nimic, nu returnează bani și nu eliberează cotă — planul merge mai departe și alocarea rămâne, doar că nu mai deții acea cheie. Revocă atunci când o cheie a fost expusă sau o integrare este retrasă. Ca să nu mai fii facturat, anulează abonamentul: accesul continuă până la finalul perioadei deja plătite, iar după aceea încetează să funcționeze și cheile existente.
O singură cotă pentru cont, nu una pentru fiecare cheie
Fiecare cheie activă a contului consumă din aceeași alocare lunară. A doua cheie nu creează o a doua cotă — cheile există ca să separi staging-ul de producție, să dai fiecărei integrări propria credențială și să revoci una fără să le deranjezi pe celelalte.
GET /v1/usage raportează situația contului (used, limit, remaining), deci răspunde la întrebarea pe care o ai de fapt — cât a mai rămas până când apelurile încep să eșueze — indiferent de cheia cu care ai întrebat. Când alocarea se termină, fiecare cheie returnează 402, nu doar cea care a consumat-o.
Planuri, preț și cotă
Engine API este facturat separat de planurile aplicației, lunar, în EUR, cu două planuri:
| Plan | Ce diferă |
|---|---|
| Studio | Planul de intrare, cu perioadă de probă gratuită |
| Scale | O cotă lunară de cereri mai mare, fără perioadă de probă — treci la el de la Studio |
Restul este la fel în ambele: aceleași motoare, toate cele patru moduri, fiecare opțiune, aceleași răspunsuri. Fiecare cerere contează la fel — o lucrare de nesting costă o cerere, exact ca una 2D sau 1D.
- Plafon strict, fără depășiri. Când cota lunară s-a epuizat, apelurile returnează
402până când aceasta se resetează în prima zi a lunii următoare. Nu există factură-surpriză. - Două e-mailuri, ca plafonul să nu te ia prin surprindere. Trimitem un e-mail contului la 90% din cotă și încă unul când aceasta este epuizată.
- Schimbarea planului se face dintr-un singur buton de pe cardul Chei API din panoul tău (Treci la Scale / Treci la Studio); noua cotă se aplică imediat. O trecere la un plan superior se taxează pe loc pentru restul perioadei; o trecere la un plan inferior nu se rambursează, iar prețul mai mic se aplică de la următoarea reînnoire. Schimbarea este disponibilă după perioada de probă.
- Volumele mai mari decât planul Scale se tarifează individual — scrie-ne.
Prețurile și cotele actuale sunt listate pe pagina Engine API — acea pagină le citește din configurația noastră de prețuri, deci cifra de acolo este întotdeauna cea corectă.
Pentru detaliile tehnice — structura exactă a cererii și a răspunsului, fiecare opțiune, toate codurile de eroare și modul în care funcționează versionarea — vezi documentația API.
Componente open-source
Motoarele CutOptim se bazează pe biblioteci open-source, folosite nemodificate pe serverele noastre:
- jagua-rs — motorul geometric de coliziune din spatele nesting-ului true-shape (MPL-2.0).
- sparrow — căutarea din spatele motorului
maxpentru nesting (MIT, KU Leuven). - PackingSolver — căutarea în arbore din spatele motorului
maxpentru 2D (MIT).
Tot ce este în jurul lor — API-ul, corespondența dintre contract și aceste motoare, packerele dreptunghiulare și aplicația însăși — este cod propriu CutOptim.
Ce nu se schimbă
Merită spus limpede, pentru că Engine API este ușor de citit greșit ca o schimbare a produsului:
- Optimizatorul din aplicație este neschimbat. Rulează în continuare în browserul tău, exact ca înainte.
- Gratuit, Pro și Atelier nu sunt afectate. Includ în continuare optimizatorul din aplicație, cu aceleași limite ca înainte. Nimic nu a fost mutat în spatele API-ului.
- Nimic din ce faci în aplicație nu consumă cereri API. Cota lunară de API este atinsă doar de apelurile făcute de propriul tău software.
Engine API este o adăugire pentru cei care integrează CutOptim în alt software. Dacă nu este cazul tău, nimic nu s-a schimbat.