Aller au contenu principal
Sur cette page▾

Engine API

Si vous découpez simplement des panneaux, vous n’avez pas besoin de cette page. L’optimiseur intégré à CutOptim fait déjà tout ce qui est décrit ici. L’Engine API est le même moteur, sans écran, pour le cas où un autre logiciel a besoin de plans de découpe sans qu’une personne ouvre l’application.

Tout ce que CutOptim fait dans votre navigateur part d’un seul calcul : avec ces pièces et ce stock, quelle est la meilleure façon de les découper ? L’Engine API expose exactement ce calcul sur Internet, pour qu’un autre programme puisse poser la question et récupérer la réponse — sans navigateur, sans clic, sans personne connectée.

C’est toute l’idée. Ce n’est pas un nouvel optimiseur, ni un meilleur optimiseur, ni un forfait supérieur. C’est le même moteur, joignable par un logiciel au lieu d’une personne.


Est-ce fait pour moi ?

Pour l’immense majorité des utilisateurs de CutOptim, la réponse honnête est non. Si votre journée de travail consiste à ouvrir CutOptim, saisir des pièces et du stock, puis imprimer ou exporter le plan, l’application est le produit et cette page ne vous concerne pas.

L’Engine API répond à une seule situation : des plans de découpe doivent apparaître dans un logiciel que vous utilisez déjà, sans que personne ne se rende sur CutOptim. En pratique, cela concerne l’une de ces deux personnes :

  • Vous utilisez déjà un logiciel dans lequel le plan de découpe a sa place. Un ERP qui porte vos commandes, un outil de devis qui chiffre les chantiers, ou le logiciel propre à une machine. Au lieu qu’un opérateur ressaisisse la même liste de pièces dans CutOptim, ce programme interroge directement le moteur et affiche le plan là où le travail se fait déjà.
  • Vous faites développer un logiciel pour vous. Par un développeur interne, une société informatique locale ou le fournisseur de votre machine. L’Engine API est ce à quoi il se connecte.

Utiliser l’Engine API suppose que quelqu’un écrive un logiciel qui s’y connecte. Il n’y a pas d’interface, pas de tableur à remplir et rien à installer — c’est un service destiné aux programmes, et le travail est réalisé par la personne qui écrit ce programme. Si personne, de votre côté, n’écrit de code, c’est l’application qu’il vous faut.

Si vous ne savez pas de quel côté de la frontière vous vous situez, voici un bon test : le plan pourrait-il apparaître sans que personne ne le demande ? Si oui, l’API est pertinente. Si c’est toujours une personne qui décide de créer un plan de découpe, l’application est déjà le bon outil.


Ce qu’elle fait

Votre logiciel envoie les deux mêmes choses que vous saisiriez dans l’application — une liste de pièces et une liste de stock — au format JSON. Le moteur renvoie une réponse complète :

  • La disposition complète. Chaque pièce, positionnée sur un panneau ou une barre précis, en indiquant si elle a été tournée.
  • Un plan de découpe. Pas seulement une image de rectangles : la véritable séquence de coupes guillotine, dans l’ordre, pour que le plan puisse être exécuté sur une scie à panneaux.
  • Les chiffres. Combien de panneaux ou de barres le chantier demande, le pourcentage de rendement, le nombre de coupes nécessaires et le prix total de la matière utilisée. Pour les panneaux, vous obtenez en plus les deux décomptes honnêtes des coupes — les lignes de coupe, qui regroupent les coupes partageant un même réglage de butée, et les passes de scie, qui comptent chaque passe — ainsi que la longueur sciée totale.
  • En option, le dessin. Demandez include: ["svg","csv","dxf"] et la réponse porte aussi la disposition sous forme de fichier prêt à l’emploi — un dessin SVG 2D autonome, un DXF R12/AC1009 ou une liste de coupe CSV — en ligne dans le JSON, sans stockage ni second appel. (SVG en 2D uniquement.) Une requête 2D peut aussi demander labels (les données d’étiquette par pièce), planHash (une empreinte du plan), pdf (le PDF du plan de découpe) et labelsPdf (le PDF des étiquettes) — les PDF encodés en base64, dessinés par le même code que l’application.
  • Vos propres identifiants, renvoyés. Attachez un objet meta — un numéro d’article, une ligne de commande, une référence client — à toute pièce ou ligne de stock, et il revient inchangé sur chaque pièce placée et chaque panneau ou barre, pour que le plan corresponde à votre propre système. C’est le champ à utiliser lorsque vous voulez envoyer tous vos panneaux, marquer chacun d’eux de votre propre code et relire quel panneau l’optimiseur a retenu — placez le code dans stock[].meta et il vous revient sur sheets[].meta. Il n’influence jamais le placement. N’utilisez pas le champ material pour identifier vos lignes : material est une partition stricte (une pièce n’est jamais découpée que dans du stock du même matériau), si bien qu’étiqueter chaque ligne de stock avec un matériau en laissant les pièces sans étiquette fait revenir toutes les pièces en unmatched, avec un résultat vide.

Il y a quatre modes d’optimisation, tous correspondant à l’application — un pour les panneaux 2D, un pour le matériau 1D linéaire (barres, profilés, tubes), un pour le bois, dont la matière possède une section, et l’imbrication par forme réelle (POST /v1/optimize/nest), qui imbrique des polygones arbitraires pour la découpe laser, plasma et jet d’eau (le mode Nesting de l’application). Chaque endpoint d’optimisation dispose aussi d’un endpoint de validation gratuit qui vérifie une requête sans la résoudre (voir ci-dessous).

Endpoints

L’URL de base est https://api.cutoptim.com. Les endpoints d’optimisation et d’usage portent une clé dans un en-tête Authorization: Bearer <key> ; les endpoints de validation et de disponibilité ne nécessitent aucune clé.

Endpoint Ce qu’il fait
POST /v1/optimize/2d Optimisation de panneaux 2D
POST /v1/optimize/1d Optimisation 1D / linéaire — barres, profilés, tubes
POST /v1/optimize/wood Optimisation du bois — 1D avec correspondance de section
POST /v1/optimize/nest Imbrication à forme réelle — polygones irréguliers pour le laser, le plasma et le jet d’eau
POST /v1/validate/2d · /1d · /wood · /nest Valider une requête sans la résoudre — gratuit, sans clé, sans quota
GET /v1/jobs/{id} Interroger un travail asynchrone du moteur max — vos propres travaux uniquement, sans quota
POST /v1/import/nest Lit les contours de pièces dans un fichier SVG ou DXF — nécessite une clé, ne consomme aucun quota
GET /v1/usage Consommation et quota du COMPTE sur le mois en cours (toutes les clés en partagent un)
GET /v1/health État de disponibilité — ne nécessite aucune clé

La plupart des appels reçoivent directement le résultat terminé. La seule exception est le moteur max asynchrone (voir Trois moteurs ci-dessous) : une soumission max renvoie un identifiant de travail, et vous interrogez GET /v1/jobs/{id} jusqu’à ce que le plan soit prêt.

Les endpoints de validation prennent le même corps que l’endpoint d’optimisation correspondant et le vérifient sans lancer la résolution : une requête mal formée revient sous forme de 400 nommant le champ fautif exact, et une requête bien formée renvoie valid: true accompagné d’avertissements de faisabilité (par exemple, une pièce qui ne tient dans aucun stock). Ils ne coûtent rien et ne nécessitent aucune clé : vous pouvez donc valider vos charges utiles pendant que vous construisez l’intégration — avant même de détenir une clé — et confirmer qu’une requête ne sera pas rejetée sans dépenser l’un de vos appels mensuels.

Sens du fil sur les panneaux

Le contreplaqué et les panneaux plaqués ont un fil, et une pièce apparente doit être découpée avec le fil dans le bon sens. Sur POST /v1/optimize/2d, envoyez grain sur une ligne de stock — "w" ou "h", le côté du panneau le long duquel court le fil — et grain sur une pièce, le côté de la pièce le long duquel il doit courir. Chaque pièce de ce type est placée avec son fil le long de celui de son panneau : tournée de 90° lorsque c’est nécessaire (rotated: true sur le placement, comme pour toute rotation), et rotatable est ignoré pour elle. Une pièce sans grain pivote toujours librement, y compris sur une ligne de stock sans grain (MDF, mélaminé) ; une pièce AVEC un grain garde sur une telle ligne aussi l’orientation que lui donnent les lignes à fil — material sépare les panneaux à fil des panneaux unis. Une pièce qui ne tiendrait que tournée de 90° contre le fil figure dans unplaced à la taille envoyée, une ligne de warnings la nomme, et POST /v1/validate/2d le signale avant qu’un appel soit consommé.

Des lignes de stock dont le fil court dans des sens différents peuvent figurer dans une même requête — un 2440 × 1220 avec "w" et un 1220 × 2440 avec "h" — et chaque panneau revient dans l’orientation propre à sa ligne, avec grain repris dans sheets[]. Avec material, une pièce n’est soumise à un fil que si son propre matériau a un panneau avec un fil. Le grain d’une pièce, sans stock avec fil dans la requête, n’a aucun effet, et une ligne de warnings le signale. options.trim et un options.firstCut forcé s’appliquent à chaque panneau dans l’orientation de sa propre ligne, y compris sur une ligne dont le fil court dans l’autre sens. Le mode Sens du fil de l’application CutOptim exécute le même code. (Depuis le 2026-10-02.)

Correspondance du grain sur les panneaux (matched sets)

Le sens du fil garde le fil de chaque pièce dans le bon sens. Certaines façades demandent davantage : une façade de tiroir au-dessus de deux portes dont le motif se prolonge de l’une à l’autre, comme si les trois étaient encore une seule planche. Sur POST /v1/optimize/2d, donnez un id à ces lignes de pièces et nommez-les dans 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 qu’est un ensemble. layout.lines liste les membres par parts[].id. Avec dir: "rows", chaque ligne est une rangée de membres côte à côte et les rangées s’empilent de haut en bas : [["DF"], ["DOOR", "DOOR"]] est donc une façade de tiroir au-dessus de deux portes ; avec "cols", chaque ligne est une colonne et les colonnes se dressent côte à côte. Une pièce peut apparaître plusieurs fois dans un même ensemble (Door, Door), mais n’appartenir qu’à un seul ensemble. qty (1 par défaut) est le nombre d’exemplaires voulus — trois meubles identiques valent qty: 3 — et le qty propre des pièces doit couvrir chaque exemplaire. Un ensemble compte au moins 2 et au plus 24 membres, et une requête accepte au plus 50 ensembles.
  • Comment il est découpé. L’ensemble passe dans l’optimiseur comme un seul rectangle — le bloc — et ressort sous forme de ses membres, séparés d’exactement un trait de scie, dans une même planche. Le grain de l’ensemble ("w" ou "h", dans le sens de la largeur ou de la hauteur du bloc) décide du sens de chaque membre ; le grain propre à un membre n’est pas utilisé dans l’ensemble, et un avertissement nomme tout membre qu’il supplante. Sans grain d’ensemble, le bloc peut pivoter lorsque tous les membres sont rotatable. installGap est l’écart entre les membres sur le meuble (par défaut : le trait de scie) ; sur le panneau, ils restent séparés d’un trait de scie.
  • Ce qui revient. Chaque membre placé porte matchedSet : l’id de l’ensemble, quel instance, et sa position dans l’ordre de lecture de la façade du meuble — de haut en bas, de gauche à droite, à partir de 1 — plus un hint tel que "left" ou "right" quand c’est sans ambiguïté. La réponse ajoute un récapitulatif matchedSets, une entrée par ensemble : sa letter (A, B … dans l’ordre de la requête), combien d’exemplaires ont été découpés en un seul bloc (asBlock), scindés ou laissés non placés, la dimension du bloc et les warnings de l’ensemble. Quand un bloc ne tient sur aucun panneau du stock, onMiss: "split" (par défaut) place les membres un par un avec un avertissement, et onMiss: "unplaced" les liste dans unplaced.
  • Des avertissements, pas des erreurs. Une dimension qui ne s’aligne pas est un avertissement sur l’ensemble, pas un refus. Chaque ligne commence par son code — align: (les lignes ne sont pas alignées), gap: (le trait de scie est plus large que installGap), grain:, split:, unplaced:, unmatched: (aucun stock du matériau de l’ensemble), priority: et grainGroup: — et align et gap sont jugés à 1/64 de votre unité ou au quart du trait de scie, selon la plus petite des deux valeurs. Un ensemble qui ne peut pas du tout être disposé — un id de membre qu’aucune pièce ne porte, un id référencé sur deux pièces, moins de deux membres, trop peu de pièces pour qty — est un 400 qui nomme le champ exact, avant qu’un appel ne soit facturé.
  • parts[].id peut être envoyé sans risque. Seul un id auquel un ensemble renvoie est vérifié (une chaîne imprimable non vide de 64 caractères au plus, ou un entier, sur exactement une pièce). Tout autre id est ignoré, quel que soit son contenu : les numéros d’article de votre ERP peuvent donc rester sur les lignes. Et rien ne change pour une requête sans ensembles : seul un tableau matchedSets non vide active la fonction — absent, null, [] ou toute valeur qui n’est pas un tableau reçoit exactement la même réponse qu’avant.
  • Exports. Avec des ensembles, csv gagne des colonnes Set et Position à la fin, svg imprime le code de position (A1, A2 …) dans les étiquettes des pièces et dessine le cadre de chaque ensemble dans un groupe matched-sets distinct — options.setOutlines: false omet ce groupe — et dxf porte le code de position sur le calque LABELS. pdf et labelsPdf ne marquent pas les ensembles : ils dessinent les membres comme des pièces ordinaires, et warnings le dit ; les marques d’ensemble se trouvent dans sheets[].parts[].matchedSet, csv et svg.
  • Moteurs et endpoints. Les moteurs heuristic et balanced disposent les ensembles (balanced ne classe pas priority : sous respectStock, un ensemble peut y perdre sa place, avec un avertissement priority:). Le moteur max refuse un matchedSets non vide par un 400 dont details.unsupported le nomme, avant qu’un appel ne soit facturé ; un matchedSets vide est un travail max ordinaire. matchedSets et parts[].id ne concernent que la 2D : les endpoints 1D, bois et nest les ignorent.
  • grainGroup est obsolète. Il est toujours accepté et fonctionne exactement comme avant : les pièces d’un même groupe sont gardées sur un seul panneau. Il ne les a jamais placées l’une à côté de l’autre, il ne donne donc aucun fil continu entre elles — pour cela, utilisez matchedSets.

La fonction Correspondance du grain de l’application CutOptim dispose les ensembles avec le même noyau.

Pourquoi le bois a son propre endpoint

Le matériau linéaire ne connaît qu’une dimension, sa longueur : n’importe quelle barre peut donc fournir n’importe quelle pièce. Le bois ne fonctionne pas ainsi : une pièce 50×150 ne peut pas sortir d’une barre 50×100, quelle que soit la longueur restante. L’endpoint bois prend donc les deux côtés de la section sur chaque pièce et chaque ligne de stock, découpe le travail par section, associe à chaque section son propre stock et renvoie les sections séparément — chacune avec ses barres et ses totaux, à côté des chiffres du travail complet.

Deux détails à connaître avant de l’intégrer :

  • Les deux côtés de la section peuvent être envoyés dans n’importe quel ordre. 50×100 et 100×50 sont la même poutre retournée et forment une seule section. Une différence dans la façon dont vos données ont été saisies ne peut donc pas faire disparaître de la matière.

  • « Aucun stock de cette section » et « n’a pas tenu » sont signalés séparément. Le premier est un manque de matière, le second un problème de capacité, et ils ne se corrigent pas de la même façon — les mélanger dans une seule liste enverrait votre utilisateur chercher au mauvais endroit.

Vous pourriez approcher ce résultat avec plusieurs appels 1d de votre côté, en groupant les pièces vous-même. Cela coûterait une requête de votre quota par section au lieu d’une pour le travail, déplacerait la correspondance du stock dans votre code et produirait un total que vous devriez assembler — et qui ne correspondrait pas nécessairement à ce que l’application CutOptim affiche pour le même travail.


Des pièces depuis un fichier CAO

L’endpoint de nesting n’accepte pas que des coordonnées. Une pièce peut porter à la place un source — un document SVG ou DXF — et le serveur en extrait le contour, ainsi que les trous qu’il contient. C’est le même lecteur que celui de l’application lorsque vous déposez un dessin sur son mode Nesting : une bibliothèque de pièces qui existe déjà en fichiers CAO n’a donc pas à être réécrite en listes de coordonnées.

Le fichier ne remplace que la géométrie. Quantité, matériau, rotations autorisées et vos propres métadonnées restent des champs ordinaires de la ligne de pièce, exactement comme lorsque vous envoyez des coordonnées. Un fichier décrit une pièce ; lorsqu’un même dessin contient plusieurs composants distincts, POST /v1/import/nest le découpe d’abord en lignes de pièces prêtes à l’emploi — et cet appel exige une clé mais ne consomme aucune requête de votre quota mensuel.

Rien n’est conservé. Le fichier n’existe que comme la requête elle-même : il est lu en mémoire et disparaît au moment où la réponse est écrite. Aucune copie ne reste sur un disque ou dans une base de données, rien n’atterrit dans un journal, et il n’y a rien à supprimer ensuite. Nous traitons les unités de la même façon — un DXF peut déclarer des millimètres ou des pouces et nous rapportons ce qu’il a déclaré, mais les coordonnées ne sont jamais converties, car aucune valeur de cette API ne porte d’unité.

La même réponse à chaque fois

Le moteur est déterministe : une même entrée produit toujours le même résultat. Il n’y a aucun aléatoire et aucune horloge dans l’algorithme.

Cela peut sembler théorique, mais c’est justement la raison pratique de construire dessus. Les résultats peuvent être mis en cache — si vous avez déjà posé la question pour exactement ce chantier, vous pouvez réutiliser la réponse en toute sécurité au lieu de la redemander. Cela signifie aussi que l’intégration peut être testée : un plan peut être comparé à un résultat connu comme bon, et un écart est un véritable écart, pas du bruit. Un logiciel qui annonce un prix à un client le lundi annoncera le même prix le vendredi.

Il existe une exception facultative, et elle se déclare comme telle : le moteur max de l’imbrication (ci-dessous) consacre un budget de temps fixe à sa recherche, si bien que ce qu’il atteint dépend du travail qui tient dans ce temps. Ses réponses portent deterministic: false. Tous les autres moteurs — y compris celui par défaut de l’imbrication, lbf — sont déterministes.

Réessayer sans risque. Si la connexion tombe, impossible de savoir si la requête est arrivée. Envoyez un en-tête Idempotency-Key — une valeur que vous choisissez pour chaque travail — et réessayez avec la même clé : pendant 24 heures, la même requête renvoie la réponse enregistrée, marquée Idempotency-Replayed: true, sans être facturée une seconde fois. Un travail max n’est pas non plus mis deux fois en file. La clé de démo publique ignore cet en-tête. (Depuis le 2026-10-15.)

Webhooks pour les jobs asynchrones. Au lieu d’interroger GET /v1/jobs/{id}, enregistrez un endpoint (une URL https://) dans votre tableau de bord et recevez un POST signé — job.succeeded ou job.failed — quand un job max asynchrone se termine. Vérifiez l’en-tête CutOptim-Signature avec le secret reçu, répondez en 10 secondes et lisez le plan avec GET /v1/jobs/{id}. Un envoi qui échoue est retenté : 8 tentatives sur 24 heures. (Depuis le 2026-10-19.)

SDK officiels. Des clients open source pour TypeScript, Python et PHP — npm install @cutoptim/engine, pip install cutoptim, composer require cutoptim/engine — avec des requêtes typées, des nouvelles tentatives jamais facturées deux fois (chaque appel porte un Idempotency-Key), une aide pour attendre les jobs asynchrones et la vérification des webhooks. Code sur GitHub ; détails dans le guide des SDK (en anglais).

Serveur MCP pour assistants IA. Claude Code, Cursor, VS Code et Claude Desktop peuvent appeler le moteur comme outils via le serveur Model Context Protocol hébergé à https://api.cutoptim.com/mcp, avec la même clé d’API (Authorization: Bearer …) et le même quota : un appel d’outil est un appel d’API, et les outils validate_* sont gratuits. Il tourne aussi en local avec le paquet npx -y @cutoptim/mcp (clé dans CUTOPTIM_API_KEY), et le MCP Registry officiel le référence sous io.github.cutoptim/engine. Les configurations des clients sont dans le guide MCP (en anglais).


Trois moteurs

L’API propose plusieurs moteurs au choix. Les deux premiers s’exécutent de façon synchrone ; le troisième est asynchrone. La différence n’est pas une question de qualité : c’est un compromis entre la vitesse, le fait que le résultat soit réalisable ou non sur une scie à panneaux, et sa proximité avec le minimum théorique.

  • heuristic est le moteur par défaut, celui-là même qu’utilise l’application. Il produit des dispositions guillotine : le meilleur rendement, toute disposition sciable sur une scie à panneaux, et toujours un plan de découpe complet. Synchrone.
  • balanced s’active explicitement. Il utilise à la place une imbrication libre, beaucoup plus rapide sur les très gros chantiers — mesurée à environ 25× plus rapide sur un chantier de 2 000 pièces — au prix d’un rendement légèrement plus faible. La réserve importante : ses dispositions ne peuvent souvent pas être coupées de rive à rive, et dans ce cas il ne renvoie aucun plan de découpe. Synchrone.
  • max s’active explicitement, pour les panneaux 2D (et, séparément, pour l’imbrication à forme réelle — voir ci-dessous). En 2D, c’est une recherche arborescente côté serveur qui atteint l’optimum prouvé sur bien plus de travaux que le moteur par défaut, et ses dispositions restent coupables en guillotine. Le prix est le temps : un calcul max prend de quelques secondes à une minute, il ne répond donc pas dans la réponse. À la place, POST /v1/optimize/2d avec engine: "max" renvoie un identifiant de travail, et vous interrogez GET /v1/jobs/{id} jusqu’à ce qu’il soit prêt. Il reste déterministe. Réservez-le aux gros chantiers de valeur pour lesquels attendre en vaut la peine, afin de gagner les derniers panneaux. Il modélise un seul format de stock en pleine dimension et en quantité illimitée : une requête qui porte en plus un deuxième format de stock, un trim par côté, un stock limité (respectStock), des matériaux, des groupes de fil ou un matchedSets non vide est refusée d’emblée par un 400 qui nomme précisément ce qu’il ne sait pas faire — avant qu’un appel ne soit facturé. Envoyez ces travaux à heuristic, qui les modélise tous.

Imbrication : lbf et max

L’imbrication à forme réelle a ses deux propres moteurs. lbf est celui par défaut : instantané, synchrone et déterministe. max s’active explicitement et fonctionne de façon asynchrone, exactement comme le max 2D — POST /v1/optimize/nest avec engine: "max" renvoie un identifiant de travail, et vous interrogez GET /v1/jobs/{id}.

Le max d’imbrication exécute d’abord la passe lbf, il a donc toujours une réponse valide en main. Il consacre ensuite un budget de temps (options.timeBudgetMs, 60 secondes par défaut, entre 10 et 180) à chercher une disposition avec moins de feuilles, en remplissant une feuille à la fois. Il ne renvoie jamais plus de feuilles que lbf : quand la recherche ne trouve aucune amélioration, vous récupérez la disposition lbf accompagnée d’un avertissement qui le précise. Comme la recherche est limitée dans le temps, ses réponses portent deterministic: false. Il accepte plusieurs tailles de feuille par matériau et respectStock, et classe son résultat avec la même règle que lbf (ci-dessous) : il ne remplace le plan lbf que lorsqu’il est meilleur — jamais simplement parce qu’il a moins de feuilles. Une feuille polygonale ou des zones d’exclusion, que sa recherche en bandes ne peut pas modéliser, sont servies par la passe lbf à l’intérieur du travail, avec un avertissement — jamais refusées. L’ancien nom sparrow est accepté comme alias de max.

Les pièces rectangulaires obtiennent une grille exacte (depuis le 2026-09-28). lbf trouve les positions par échantillonnage, ce qui ne tombe presque jamais sur une grille sans aucun jeu : trois pièces de 500 mm sur la largeur d’une feuille de 1500 mm avec un espacement nul s’ajustent exactement, et une recherche par échantillonnage en place deux. Les deux moteurs essaient donc aussi deux variantes et gardent celle qui se classe le mieux selon la même règle : les pièces limitées aux angles droits qu’elles autorisent, et les boîtes englobantes des pièces rangées par un algorithme exact de rangement de rectangles (des boîtes qui ne se chevauchent pas ne peuvent pas contenir de pièces qui se chevauchent, c’est donc valable pour n’importe quel contour). À égalité — mêmes feuilles, même surface de feuille — l’emporte le plan qui remplit ses feuilles de l’avant vers l’arrière, puis celui qui a le moins de pièces sorties des angles droits. Rien à activer, et un résultat ne peut que s’améliorer selon ce classement ; un plan que les rectangles ramènent au plus petit nombre de feuilles que permet la surface des pièces fait aussi répondre max immédiatement, sans lancer de recherche.

Un travail de quelques dizaines de pièces a généralement besoin d’un budget d’environ 15 secondes (timeBudgetMs: 15000) ; le travail se termine environ une à deux secondes après le budget, plus le temps éventuel passé en file d’attente. Interrogez GET /v1/jobs/{id} toutes les deux à trois secondes — l’interrogation ne consomme aucun quota. Aucun budget ne peut promettre un nombre de feuilles précis.

Imbrication : espace en bord de feuille, tailles de feuille et coût de chaque feuille

  • Espace en bord de feuille. options.minSeparation est l’espacement entre les pièces, et à lui seul il s’applique aussi au bord de la feuille. options.edgeClearance règle le bord séparément — par exemple 5 entre les pièces et 0 ou 10 au bord. Omettez-le et le bord garde minSeparation, exactement comme avant. Cela fonctionne sur les deux moteurs, il faut des feuilles rectangulaires (w et h), et les zones d’exclusion gardent minSeparation comme les pièces. Une feuille polygonale, ou une valeur qui ne laisse aucune place sur une feuille, est refusée par un 400 avant qu’un appel ne soit facturé.
  • Choix d’une taille de feuille. Quand un matériau a deux lignes de stock ou plus, lbf les essaie dans votre ordre, chaque taille séparément puis dans un ordre du moins cher au plus cher, et garde la meilleure — le résultat ne dépend donc plus de l’ordre dans lequel vous listez les lignes. Le classement est : le plus de pièces à découper impérativement placées (voir plus bas), puis le plus de pièces placées, puis la plus petite surface totale de feuille (matière), puis le moins de feuilles. Avec options.minimizeCost, il classe plutôt par prix total (price, ou cost pour une ligne sans prix) — mais seulement quand toutes les lignes de ce matériau en portent un ; sinon il retombe sur la surface et le signale dans warnings.
  • Mélange des tailles. Ensuite, chaque feuille — la moins remplie en premier — est réimbriquée seule sur les lignes moins chères ou plus petites, et remplacée lorsque le plan entier se classe mieux. Les tailles peuvent donc être mélangées au sein d’un même matériau : typiquement deux grandes feuilles et une plus petite en dernier, là où la dernière feuille à moitié vide était auparavant une grande. Avec options.respectStock, aucune ligne n’est utilisée plus souvent que son qty. Le moteur max applique le même classement.
  • Pièces à découper impérativement. parts[].priority: true marque une pièce à découper impérativement. Cela compte avec options.respectStock — un approvisionnement plafonné, où toutes les pièces ne tiennent pas forcément : les pièces à découper impérativement sont alors placées en premier, si bien qu’une pièce ordinaire ne prend jamais l’espace de feuille dont une pièce à découper impérativement a besoin, et chaque classement ci-dessus place devant le plan qui en garde le plus, même s’il place moins de pièces au total. Les deux moteurs le respectent (max garde la disposition lbf dès qu’une pièce reste non placée). Sans respectStock, toute pièce qui tient est placée de toute façon, donc le champ ne change rien. Une pièce à découper impérativement qui ne tient sur aucune feuille reste tout de même listée dans unplaced. (Depuis le 2026-09-22 — avant cela, le moteur d’imbrication acceptait ce champ mais l’ignorait.)
  • Un stock limité où tout ne tient pas. Avec options.respectStock, lorsque le plan laisse encore des pièces non placées, le moteur remplit en plus les panneaux un par un avec les rectangles englobants des pièces — chacun aussi plein que possible, et une pièce qui ne tient que sur une seule taille de panneau y va en premier (un côté haut sur l’unique grand panneau, pas sur une bande de chute). Ce plan n’est retenu que s’il place plus de pièces (les obligatoires d’abord) ou utilise moins de matière ; un travail où tout tient revient exactement comme avant. Il respecte les rotations autorisées de chaque pièce, minSeparation et edgeClearance. (Depuis le 2026-10-14.)
  • Coût de chaque feuille. Chaque feuille porte stock — l’index de la ligne de stock de la requête dont elle provient — et la réponse ajoute stockUsage : une entrée par ligne de stock utilisée, avec son nombre de feuilles, son prix total et sa densité. L’unité est la ligne de stock, pas la taille : deux lignes de mêmes dimensions mais avec un prix ou un meta différent forment deux entrées.
  • Longueur de coupe et perçages. Chaque feuille porte cutLength — le périmètre cumulé des contours et des trous de ses pièces placées, dans votre unité — et pierces, un par contour fermé ; metrics totalise les deux. C’est la longueur de contour géométrique : pas de coupe à ligne commune, d’entrées de coupe ni de micro-joints — votre FAO les ajoute.
  • Surface utilisée, pour une facturation partielle de feuille. Chaque feuille porte usedWidth et usedHeight — le point le plus éloigné que n’importe quelle pièce placée atteint depuis le coin d’origine de la feuille, dans votre unité, sur la feuille réelle (avec edgeClearance, l’espace au bord est inclus) — et usedArea, leur produit ; stockUsage[].usedArea le totalise par ligne de stock. C’est ce dont un ERP a besoin pour facturer une coupe horizontale (usedHeight × largeur de la feuille), une coupe verticale (usedWidth × hauteur de la feuille) ou la boîte englobante (usedArea) plutôt que la feuille entière — la règle de facturation reste la vôtre. Pour rendre ces chiffres petits, les deux moteurs compactent par défaut la feuille la moins remplie de chaque matériau : ses pièces sont réimbriquées sur la même feuille avec des sous-ensembles de rotation parmi ceux que chaque pièce autorise — 0/180, 0/90/180/270 et une seule orientation pour chaque copie, croisés avec un allowedRotations discret, jamais un nouvel angle —, et la disposition avec la plus petite surface utilisée est conservée. Avec engine: "max", cette feuille est ensuite aussi réagencée par la recherche elle-même — dans la hauteur de la feuille et, si le plan tient sur une seule feuille, aussi dans sa largeur — et la disposition la plus serrée est conservée selon la même règle. Le nombre de feuilles, leurs tailles, le prix et les pièces placées ne changent jamais ; options.compact: false renvoie la disposition non compactée. Si vous facturez une bande plutôt que la boîte englobante, réglez options.compactFor en conséquence : "horizontal" conserve la disposition avec la plus petite usedHeight (une bande sur toute la largeur de la feuille), "vertical" celle avec la plus petite usedWidth (une bande sur toute la hauteur de la feuille) ; la valeur par défaut "box" conserve la plus petite usedArea. Les modes bande essaient aussi chaque copie tournée d’un quart de tour (90° ou 270°) là où allowedRotations le permet. À quel point la surface utilisée rétrécit dépend des pièces. (Depuis le 2026-09-22.)

balanced ne veut pas dire « de meilleurs résultats ». Il est plus rapide, son rendement est légèrement plus faible, et lorsque sa disposition n’est pas coupable en guillotine il n’y a aucun plan de découpe à remettre à l’opérateur de la scie. Ne le choisissez que lorsque la vitesse sur un très gros chantier compte plus qu’un plan prêt pour la scie. En cas de doute, restez sur le moteur par défaut.


Limites

Chaque requête est bornée, pour qu’un chantier qui déraille échoue clairement au lieu de rester bloqué :

Limite Valeur
Pièces par requête 2 000
Lignes de stock par requête 50
Taille du corps de requête 1 Mo
Taille du corps de requête — routes nest susceptibles de porter un dessin 10 Mo
Clés actives par compte 10
Appels validate sans clé par adresse 120 / minute
Clés API inconnues par adresse 30 / minute — puis 429 pour le reste de la minute
Attente d’un créneau de calcul libre (chemins synchrones) environ 8 s — puis 429, rien n’est facturé
Travaux max en queued/running par compte 5
Budget de recherche du max d’imbrication par travail 10–180 s (60 s par défaut)
Conservation de l’Idempotency-Key 24 heures
Endpoints de webhook par compte 5
Tentatives d’envoi d’un webhook 8 sur 24 heures

Obtenir un accès

Commencez par la page Engine API. L’Engine API est facturée séparément des offres de l’application, et aucun changement d’offre ne l’active.

  1. Essayez, puis abonnez-vous — ou écrivez-nous. Vous pouvez appeler l’API avant de payer : les boutons Exécuter cet exemple de la documentation de l’API utilisent une clé de démo publique, et tout compte connecté peut créer des clés de test gratuites sur le tableau de bord (leur propre petit quota mensuel, jamais facturées, aucun abonnement nécessaire). Quand vous êtes prêt, s’abonner depuis la page Engine API est la voie la plus rapide : l’offre d’entrée, Studio, commence par un essai gratuit, et l’accès arrive tout seul sur votre compte. Si vous préférez décrire d’abord votre intégration, ou s’il vous faut un volume au-delà de l’offre standard, écrivez-nous en indiquant ce que vous voulez connecter et combien de plans de découpe par mois cela représente environ.
  2. L’accès est ajouté à votre compte. Rien d’autre ne change sur votre compte.
  3. Créez une clé. La carte Clés API figure sur votre tableau de bord pour tout compte connecté : sans abonnement, elle crée des clés de test ; avec l’accès API, aussi des clés live. Vous y créez, nommez et supprimez vos clés vous-même.
  4. Copiez la clé immédiatement. La clé complète n’est affichée qu’une seule fois, au moment où vous la créez.

Une clé n’est affichée qu’une seule fois. CutOptim n’en conserve qu’une empreinte sha256, jamais la clé elle-même — elle ne peut donc pas être relue par la suite, ni par vous ni par nous. Copiez-la directement dans la configuration de votre logiciel au moment où vous la créez. Si vous perdez une clé, supprimez-la et créez-en une nouvelle ; si une clé se retrouve exposée, supprimez-la et les appels cessent aussitôt de fonctionner.

Traitez une clé comme un mot de passe : sa place est dans la configuration de votre logiciel, pas dans un e-mail, un tableur ou une capture d’écran.

Ce que fait la carte Clés API de votre tableau de bord

Quatre commandes, et il vaut la peine de préciser ce que chacune change — surtout la dernière, dont beaucoup pensent qu’elle touche la facturation. Ce n’est pas le cas.

  • Offre, changement et facturation. Indique l’offre du compte (Studio ou Scale). Passer à Scale (ou Passer à Studio) change d’offre après une confirmation, et le quota mensuel du compte change tout de suite. Facturation ouvre vos paramètres de facturation, où vous mettez à jour la carte, consultez les factures ou résiliez.
  • Créer une clé. Génère une nouvelle clé et l’affiche une seule fois, sur place. Le nom (Intégration ERP, staging) sert uniquement à les distinguer par la suite. Jusqu’à 10 clés actives par compte. Les clés de test se créent de la même façon et sont comptées à part : elles ont leur propre petit quota mensuel et ne sont jamais facturées.
  • La barre d’utilisation. Deux chiffres : le total de votre compte pour le mois calendaire face au quota, et par clé, ce qu’elle a consommé. Le chiffre par clé répond à quelle intégration consomme l’enveloppe — ce n’est pas un budget distinct.
  • Révoquer. Met cette clé hors service dès l’appel suivant. La ligne reste visible pour ne pas perdre son historique.

Révoquer une clé n’a rien à voir avec votre abonnement. Cela n’annule rien, ne rembourse rien et ne libère pas de quota — l’offre continue et l’enveloppe reste, vous ne détenez simplement plus cette clé. Révoquez lorsqu’une clé a été exposée ou qu’une intégration est retirée. Pour cesser d’être facturé, résiliez l’abonnement : l’accès se poursuit alors jusqu’à la fin de la période déjà payée, après quoi même les clés existantes cessent de fonctionner.

Un quota pour le compte, pas un par clé

Chaque clé active de votre compte puise dans la même enveloppe mensuelle. Créer une deuxième clé ne crée pas un deuxième quota — les clés servent à séparer la préproduction de la production, à donner à chaque intégration son propre identifiant, et à en révoquer une sans perturber les autres.

GET /v1/usage renvoie la position du compte (used, limit, remaining) et répond donc à la question que vous vous posez vraiment — combien reste-t-il avant que les appels échouent — quelle que soit la clé utilisée pour demander. Une fois l’enveloppe épuisée, toutes les clés renvoient 402, pas seulement celle qui l’a consommée.


Offres, tarif et quota

L’Engine API est facturée séparément des forfaits de l’application, au mois, en EUR, avec deux offres :

Offre Ce qui diffère
Studio L’offre d’entrée, avec un essai gratuit
Scale Un quota mensuel de requêtes plus élevé, pas d’essai — on y passe depuis Studio

Tout le reste est identique des deux côtés : les mêmes moteurs, les quatre modes, toutes les options, les mêmes réponses. Chaque requête compte de la même façon — un travail d’imbrication coûte une requête, exactement comme un travail 2D ou 1D.

  • Plafond strict, aucun dépassement. Quand le quota mensuel est épuisé, les appels renvoient 402 jusqu’à sa remise à zéro, le premier jour du mois suivant. Aucune facture surprise.
  • Deux e-mails pour que le plafond ne vous surprenne pas. Nous écrivons au compte à 90 % du quota, puis de nouveau lorsqu’il est épuisé.
  • Changer d’offre se fait en un bouton sur la carte Clés API de votre tableau de bord (Passer à Scale / Passer à Studio) ; le nouveau quota s’applique tout de suite. Un passage à l’offre supérieure est facturé immédiatement pour le reste de la période ; un passage à l’offre inférieure n’est pas remboursé, et le prix inférieur s’applique à partir du prochain renouvellement. Le changement est possible une fois l’essai terminé.
  • Les volumes supérieurs à l’offre Scale sont tarifés au cas par cas — écrivez-nous.

Les tarifs et quotas actuels sont indiqués sur la page Engine API — cette page les lit dans notre configuration tarifaire, la valeur qui y figure est donc toujours exacte.

Pour le détail technique — la structure exacte de la requête et de la réponse, toutes les options, tous les codes d’erreur et le fonctionnement du versionnage — voir la documentation de l’API.


Composants open source

Les moteurs de CutOptim s’appuient sur des bibliothèques open source, utilisées sans modification sur nos serveurs :

  • jagua-rs — le moteur de collision géométrique derrière l’imbrication à forme réelle (MPL-2.0).
  • sparrow — la recherche derrière le moteur max d’imbrication (MIT, KU Leuven).
  • PackingSolver — la recherche arborescente derrière le moteur max 2D (MIT).

Tout ce qui les entoure — l’API, la correspondance entre le contrat et ces moteurs, les placeurs rectangulaires et l’application elle-même — est le code propre de CutOptim.


Ce que cela ne change pas

Cela vaut la peine d’être dit clairement, car l’Engine API se prête facilement au malentendu d’un changement dans le produit :

  • L’optimiseur de l’application est inchangé. Il s’exécute toujours dans votre navigateur, exactement comme avant.
  • Gratuit, Pro et Atelier ne sont pas touchés. Ces forfaits incluent toujours l’optimiseur intégré à l’application, avec les mêmes limites qu’avant. Rien n’a été déplacé derrière l’API.
  • Rien de ce que vous faites dans l’application ne consomme de requêtes API. Le quota mensuel de l’API n’est entamé que par les appels que votre propre logiciel effectue.

L’Engine API est un ajout destiné aux personnes qui intègrent CutOptim dans d’autres logiciels. Si ce n’est pas votre cas, rien n’a changé.

FAQ

Quelle est la différence entre les offres Studio et Scale ?
Uniquement le nombre de requêtes par mois et l'essai. Les deux offres font tourner les mêmes moteurs, les quatre modes et toutes les options, et chaque requête compte de la même façon — un travail d'imbrication coûte une requête, exactement comme un travail 2D. Studio est l'offre d'entrée et comprend un essai gratuit ; Scale a un quota mensuel plus élevé et pas d'essai, puisqu'on y arrive en passant de Studio. Les tarifs et quotas actuels figurent sur la page Engine API.
Puis-je passer de Studio à Scale, et inversement ?
Oui, une fois l'essai terminé et le premier paiement abouti, avec le bouton Passer à Scale (ou Passer à Studio) de la carte Clés API de votre tableau de bord. Le nouveau quota mensuel s'applique tout de suite à votre compte. Un passage à l'offre supérieure est facturé immédiatement pour le reste de la période de facturation ; un passage à l'offre inférieure n'est pas remboursé, et le prix inférieur s'applique à partir du prochain renouvellement.
Puis-je essayer l'API avant de payer ?
Oui, de deux façons. La documentation de l'API propose des boutons Exécuter cet exemple qui utilisent une clé de démo publique, sans aucun compte — petits travaux uniquement. Et tout compte CutOptim connecté peut créer des clés de test sur le tableau de bord : elles ont leur propre petit quota mensuel, ne sont jamais facturées et ne demandent aucun abonnement, vous pouvez donc construire toute l'intégration avant d'acheter. Studio commence ensuite par un essai gratuit.
Serai-je prévenu avant que mon quota mensuel ne soit épuisé ?
Oui. Nous écrivons au compte à 90 % du quota mensuel, puis de nouveau lorsqu'il est épuisé. Ensuite, les appels renvoient 402 jusqu'à la remise à zéro du quota, le premier jour du mois suivant — ou tout de suite si vous passez à l'offre supérieure.
Ai-je besoin de l'Engine API ?
Presque certainement pas. Si vous découpez des panneaux ou des barres en ouvrant CutOptim dans votre navigateur, l'application fait déjà tout ce que fait l'API — l'API est le même moteur, sans écran. Elle n'existe que pour une seule situation : un autre logiciel a besoin de plans de découpe sans qu'une personne ouvre l'application. Si personne, de votre côté, n'écrit de code qui s'adresse à CutOptim, vous pouvez l'ignorer.
À qui l'Engine API s'adresse-t-elle réellement ?
À deux types de clients : celui qui utilise déjà un logiciel dans lequel le plan de découpe devrait se trouver — un ERP qui porte les commandes, un outil de devis ou de saisie de commandes, le logiciel propre à une machine — et celui qui fait développer un tel logiciel pour lui, par un développeur interne ou une agence. Dans les deux cas, le travail est réalisé par la personne qui écrit ce logiciel, et non par vous dans l'interface de CutOptim.
Comment obtenir un accès à l'Engine API ?
Vous pouvez vous abonner depuis la page Engine API : elle propose une période d'essai, et l'accès arrive tout seul sur votre compte. C'est la voie la plus rapide. Si vous préférez décrire d'abord votre intégration, ou s'il vous faut un volume au-delà de l'offre standard, écrivez-nous. Dans les deux cas, vous créez ensuite vous-même les clés live sur la carte Clés API de votre tableau de bord. L'Engine API est facturée séparément des offres de l'application et aucun changement d'offre ne l'active.
L'Engine API traite-t-elle le bois, ou seulement les panneaux et les barres ?
Les quatre modes de l'application : panneaux, barres, bois et nesting true-shape. L'endpoint bois connaît la section : les pièces et le stock portent les deux côtés de la section, si bien qu'une pièce 50×150 n'est jamais découpée que dans du stock 50×150. Le travail est découpé par section et chaque section revient avec ses propres barres et totaux ; les besoins dont la section n'a aucun stock sont signalés séparément des pièces qui avaient du stock et n'ont pas tenu.
L'Engine API change-t-elle quelque chose à mon forfait Gratuit, Pro ou Atelier ?
Non. L'Engine API est une option distincte et ne change rien aux forfaits habituels. L'optimiseur intégré à l'application est inchangé, il s'exécute toujours dans votre navigateur et reste inclus dans Gratuit, Pro et Atelier exactement comme avant. Rien de ce que vous faites dans l'application ne se met à consommer des requêtes API.
Existe-t-il un SDK ou une bibliothèque cliente pour l'Engine API ?
Oui. Des SDK officiels et open source existent pour TypeScript (npm @cutoptim/engine), Python (PyPI cutoptim) et PHP (Composer cutoptim/engine) — code sur github.com/cutoptim, guide sur /engine/reference/guides/sdks. Ils sont facultatifs : l'API reste du HTTPS simple avec du JSON, que tout langage sait appeler sans paquet CutOptim. Les jobs asynchrones ont des webhooks : enregistrez un endpoint dans votre tableau de bord et recevez un POST signé quand un job max se termine, au lieu d'interroger. La plupart des appels reçoivent directement le résultat terminé ; la seule exception est le moteur max asynchrone — pour les panneaux 2D et pour l'imbrication à forme réelle —, où POST /v1/optimize/2d ou /v1/optimize/nest avec engine "max" renvoie un identifiant de travail que vous interrogez avec GET /v1/jobs/{id} jusqu'à ce que le résultat soit prêt.
Le moteur balanced est-il meilleur que celui par défaut ?
Non — c'est un compromis, pas une amélioration. Le moteur heuristic, celui par défaut, donne le meilleur rendement et chaque disposition qu'il produit est réalisable sur une scie à panneaux : il renvoie donc toujours un plan de découpe. Le moteur balanced est beaucoup plus rapide sur les très gros chantiers, mais son rendement est légèrement plus faible et ses dispositions ne peuvent souvent pas être coupées de rive à rive — dans ce cas, il ne renvoie aucun plan de découpe. Ne le choisissez que lorsque la vitesse sur un gros chantier compte plus qu'un plan prêt pour la scie.
Pourquoi ma clé API n'est-elle affichée qu'une seule fois ?
Parce que CutOptim ne conserve jamais la clé elle-même — uniquement une empreinte sha256. Personne, nous compris, ne peut donc relire votre clé dans la base de données : elle ne peut être affichée qu'au moment de sa création. Copiez-la immédiatement dans la configuration de votre logiciel ; si vous la perdez, supprimez la clé et créez-en une nouvelle.
Que se passe-t-il si je révoque une clé API — suis-je remboursé ?
Non, et cela n'annule rien non plus. La révocation met cette seule clé hors service dès l'appel suivant ; votre abonnement continue et le quota mensuel demeure. Révoquez une clé lorsqu'elle a été exposée ou qu'une intégration est retirée, puis créez-en une de remplacement. Pour cesser d'être facturé, résiliez plutôt l'abonnement : l'accès se poursuit jusqu'à la fin de la période déjà payée, après quoi même les clés existantes cessent de fonctionner.
Créer davantage de clés API me donne-t-il plus de requêtes ?
Non. Le quota mensuel appartient au compte et chaque clé active puise dans la même enveloppe : une deuxième clé n'ajoute pas un deuxième quota. Les clés servent à séparer la préproduction de la production, à donner à chaque intégration son propre identifiant et à en révoquer une sans perturber les autres. Une fois l'enveloppe épuisée, toutes les clés renvoient 402, pas seulement celle qui l'a consommée. GET /v1/usage renvoie la position du compte, quelle que soit la clé utilisée.
L'Engine API peut-elle renvoyer un dessin, et pas seulement des coordonnées ?
Oui. Ajoutez include: ["svg","csv","dxf"] à une requête d'optimisation et la réponse porte la disposition sous forme de fichier prêt à l'emploi, en ligne dans le JSON : un dessin SVG 2D autonome, un DXF R12/AC1009 sur les calques STOCK/PARTS/LABELS, ou une liste de coupe CSV. Aucun stockage, aucun second appel. SVG en 2D uniquement ; une requête 1D ou bois renvoie plutôt un avertissement. Vous pouvez aussi attacher un objet meta (votre numéro d'article ERP, un identifiant de ligne de commande ou une référence client) à toute pièce ou ligne de stock, et il revient à l'identique en sortie pour que le plan se réconcilie avec votre système. C'est aussi le champ qui vous dit quel panneau a été retenu : placez votre code dans stock[].meta et il vous revient sur sheets[].meta, sans jamais influencer le placement. N'utilisez pas material pour identifier vos lignes — material est une partition stricte, et étiqueter tout le stock avec un matériau en laissant les pièces sans étiquette fait revenir toutes les pièces en unmatched, avec un résultat vide.
Puis-je vérifier une requête sans dépenser l'un de mes appels mensuels ?
Oui. POST /v1/validate/2d, /v1/validate/1d, /v1/validate/wood ou /v1/validate/nest prend le même corps que l'endpoint d'optimisation correspondant et le vérifie sans le résoudre — gratuitement, sans clé API et sans quota dépensé. Une requête mal formée revient sous forme de 400 nommant le champ fautif exact, et une requête bien formée renvoie valid: true accompagné d'avertissements de faisabilité (comme une pièce qui ne tient dans aucun stock). Utilisez-la pour valider vos charges utiles pendant que vous construisez l'intégration, avant même de détenir une clé.
Que devient un fichier SVG ou DXF que j'envoie à l'API ?
Il n'en reste rien. Le fichier voyage comme corps de la requête, est lu en mémoire pour en tirer le contour de la pièce, et disparaît dès que la réponse est écrite — aucune copie sur disque, aucune copie en base, aucune ligne de journal le contenant, donc rien à supprimer ensuite et aucune durée de conservation à demander. C'est la même absence d'état que tient le reste de l'API : nous ne gardons pas davantage vos plans de découpe que la requête qui les a produits.
L'imbrication à forme réelle a-t-elle aussi un moteur max ?
Oui. POST /v1/optimize/nest avec engine "max" est asynchrone, comme le max 2D : l'appel répond 202 avec un identifiant de travail, et vous interrogez GET /v1/jobs/{id}. Il exécute d'abord la passe instantanée lbf, puis consacre un budget de temps — 60 secondes par défaut, de 10 à 180 via options.timeBudgetMs — à chercher une disposition avec moins de feuilles, en remplissant une feuille à la fois. Il ne renvoie jamais plus de feuilles que lbf ; quand il n'en trouve aucune, vous récupérez la disposition lbf accompagnée d'un avertissement qui le précise. Comme la recherche est limitée dans le temps, ses réponses portent deterministic: false. Il accepte plusieurs tailles de feuille par matériau ainsi que respectStock, et ne garde son propre résultat que lorsqu'il classe mieux que le plan lbf (par prix avec options.minimizeCost, sinon par surface de feuille). Une feuille polygonale ou des zones d'exclusion, que sa recherche ne peut pas modéliser, sont servies par la passe lbf à l'intérieur du travail avec un avertissement — jamais refusées.
Pourquoi des pièces rectangulaires imbriquées revenaient-elles inclinées ou sur une feuille de trop ?
Avant le 2026-09-28, cela pouvait arriver : le moteur d'imbrication lbf trouve les positions par échantillonnage, si bien qu'avec la rotation libre il pouvait tourner une pièce presque rectangulaire d'une fraction de degré, et il trouvait rarement une grille sans aucun jeu, comme trois pièces de 500 mm sur la largeur d'une feuille de 1500 mm avec un espacement nul. Les deux moteurs d'imbrication essaient désormais aussi les pièces aux angles droits qu'elles autorisent, et rangent les boîtes englobantes des pièces avec un algorithme exact de rangement de rectangles, puis gardent le plan qui se classe le mieux ; à égalité, l'emporte le plan qui remplit ses feuilles de l'avant vers l'arrière, puis celui qui a le moins de pièces inclinées. Vous n'avez rien à changer à votre requête. Si vos pièces ne doivent jamais sortir des angles droits, envoyez allowedRotations: [0, 90, 180, 270] comme avant.
Puis-je régler l'espace au bord de la feuille séparément de l'espacement entre les pièces ?
Oui. options.minSeparation est l'espacement entre les pièces, et à lui seul il s'applique aussi au bord de la feuille. Ajoutez options.edgeClearance pour régler le bord séparément — par exemple 5 entre les pièces et 0 ou 10 au bord. Cela fonctionne sur les deux moteurs d'imbrication, et si vous l'omettez, le bord garde minSeparation exactement comme avant. Il faut des feuilles rectangulaires (w et h) : avec une feuille polygonale, ou avec une valeur qui ne laisse aucune place sur une feuille, la requête est refusée par un 400 avant qu'un appel ne soit facturé. Les zones d'exclusion gardent minSeparation, comme les pièces.
Comment l'imbrication choisit-elle entre plusieurs tailles de feuille ?
Quand un matériau a deux lignes de stock ou plus, le moteur lbf les essaie dans votre ordre, chaque taille séparément puis dans un ordre du moins cher au plus cher, et garde la meilleure — la réponse ne dépend donc plus de la ligne que vous listez en premier. Il classe d'abord par le plus grand nombre de pièces à découper impérativement placées (les pièces marquées priority, ce qui compte avec options.respectStock), puis par le plus grand nombre de pièces placées, puis par la plus petite surface totale de feuille utilisée ; avec options.minimizeCost, il classe plutôt par prix total (price, ou cost quand une ligne n'a pas de prix), à condition que toutes les lignes de ce matériau en aient un. Ensuite, chaque feuille — la moins remplie en premier — est réimbriquée seule sur les lignes moins chères ou plus petites, et remplacée lorsque le plan entier se classe mieux — les tailles peuvent donc être mélangées au sein d'un même matériau : typiquement deux grandes feuilles et une plus petite en dernier. Avec options.respectStock, aucune ligne n'est utilisée plus souvent que son qty. La réponse indique de quelle ligne provient chaque feuille (sheets[].stock) et totalise les feuilles, le prix et la densité par ligne (stockUsage). Le moteur max applique le même classement.
Puis-je marquer des pièces d'imbrication comme à découper impérativement ?
Oui : parts[].priority: true. Cela compte quand l'approvisionnement en feuilles est plafonné (options.respectStock), car alors toutes les pièces ne tiennent pas forcément : les pièces à découper impérativement sont placées en premier, si bien qu'une pièce ordinaire ne prend jamais l'espace de feuille dont une pièce à découper impérativement a besoin, et chaque comparaison de plan classe devant celui qui en garde le plus. Les deux moteurs d'imbrication le respectent. Sans respectStock, toute pièce qui tient est placée de toute façon, donc le champ ne change rien. Une pièce à découper impérativement qui ne tient sur aucune feuille revient quand même dans unplaced. (Avant le 2026-09-22, le moteur d'imbrication acceptait ce champ mais n'agissait pas dessus.)
La réponse d'imbrication inclut-elle la longueur de coupe ?
Oui. Chaque feuille porte cutLength — le périmètre cumulé des contours extérieurs et des trous des pièces placées, dans votre unité — et pierces, un par contour fermé (le contour de chaque pièce plus un par trou) ; metrics totalise les deux pour l'ensemble du travail. C'est la longueur de contour géométrique : la coupe à ligne commune, les entrées et sorties de coupe et les micro-joints ne sont pas inclus, car la FAO de votre machine les ajoute — c'est donc une base solide pour le temps machine et les consommables, pas le trajet d'outil final.
Puis-je ne facturer que la partie d'une feuille qu'une imbrication utilise ?
L'API vous donne les chiffres ; la règle de facturation reste la vôtre. Chaque feuille porte usedWidth et usedHeight — le point le plus éloigné que n'importe quelle pièce placée atteint, mesuré depuis le coin d'origine de la feuille, dans votre unité — et usedArea, leur produit ; stockUsage[].usedArea le totalise par ligne de stock. Une coupe horizontale correspond à usedHeight × la largeur de la feuille, une coupe verticale à usedWidth × la hauteur de la feuille, une boîte englobante à usedArea. Les deux moteurs d'imbrication compactent aussi par défaut la feuille la moins remplie de chaque matériau : ses pièces sont réimbriquées sur la même feuille avec des sous-ensembles de rotation parmi ceux que chaque pièce autorise (0/180, 0/90/180/270, une seule orientation pour chaque copie — jamais un nouvel angle), et la disposition avec la plus petite surface utilisée est conservée. Le nombre de feuilles, leurs tailles, le prix et les pièces placées ne changent jamais. options.compact: false renvoie la disposition non compactée. Si vous facturez une bande plutôt que la boîte englobante, réglez options.compactFor sur "horizontal" (la plus petite hauteur utilisée, pour une bande sur toute la largeur de la feuille) ou "vertical" (la plus petite largeur utilisée, pour une bande sur toute la hauteur de la feuille) ; la valeur par défaut "box" minimise la surface utilisée. À quel point la surface utilisée rétrécit dépend des pièces, donc aucune fraction de feuille ne peut être promise à l'avance.
Quel budget de temps donner au moteur max d'imbrication ?
Le travail se termine environ une à deux secondes après son budget, plus le temps éventuel passé en file d'attente. Pour un travail de quelques dizaines de pièces, 15 secondes (options.timeBudgetMs: 15000) suffisent généralement ; la valeur par défaut est 60 secondes, et la plage va de 10 à 180. Un budget plus large donne à la recherche plus de chances d'économiser une feuille, mais aucun budget ne peut promettre un nombre de feuilles précis — cela dépend des pièces et de l'espacement. Interrogez GET /v1/jobs/{id} toutes les deux à trois secondes ; l'interrogation ne consomme aucun quota.
L'API peut-elle respecter le sens du fil d'une pièce ?
Oui. Sur POST /v1/optimize/2d, donnez à une ligne de stock grain: "w" ou "h" — le côté du panneau le long duquel court le fil — et à une pièce grain: "w" ou "h" — le côté de la pièce le long duquel il doit courir. Chaque pièce de ce type est placée avec son fil le long de celui de son panneau, tournée de 90° quand il le faut (rotated: true), et rotatable est alors ignoré pour elle. Des lignes de stock dont le fil court dans des sens différents peuvent être mélangées. Avec material, seuls comptent les panneaux du matériau propre à la pièce. Chaque panneau renvoie le grain de sa ligne. Si aucune ligne de stock n'a de fil, le grain d'une pièce n'a aucun effet et warnings le signale. Les trois moteurs 2D le prennent en charge (max avec sa ligne de stock unique habituelle).
L'API peut-elle découper des façades assorties pour que le fil se prolonge d'une pièce à l'autre ?
Oui, sur POST /v1/optimize/2d. Donnez un id aux lignes de pièces et nommez-les dans matchedSets — pour une façade de tiroir au-dessus de deux portes, une disposition avec dir rows et les lignes [DF] et [DOOR, DOOR]. L'ensemble est découpé côte à côte dans une même planche, séparé d'exactement un trait de scie, et le fil de l'ensemble décide du sens de chaque membre. Chaque membre placé revient avec matchedSet (l'id de l'ensemble, l'exemplaire et sa position), et la réponse ajoute un récapitulatif matchedSets dont les warnings signalent, par exemple, que les dimensions ne s'alignent pas. Les moteurs heuristic et balanced disposent les ensembles ; le moteur max refuse un matchedSets non vide par un 400 avant qu'un appel ne soit facturé. Les exports pdf et labelsPdf dessinent les membres comme des pièces ordinaires, et la réponse l'indique ; csv, svg et dxf marquent les ensembles. Sans tableau matchedSets non vide, rien ne change, et parts[].id n'est vérifié que sur les lignes qu'un ensemble nomme.
grainGroup est-il toujours pris en charge ?
Oui. grainGroup est obsolète mais toujours accepté, et il fonctionne exactement comme avant : les pièces d'un même groupe sont gardées sur un seul panneau. Il ne les a jamais placées l'une à côté de l'autre, il ne donne donc aucun fil continu entre elles — pour des façades dont le motif doit se prolonger, utilisez plutôt matchedSets. Le moteur max refuse grainGroup, comme il l'a toujours fait.

Mis à jour: 13 octobre 2026