Engine API
Si solo cortas paneles, no necesitas esta página. El optimizador dentro de CutOptim ya hace todo lo que se describe aquí. La Engine API es el mismo motor sin ninguna pantalla acoplada, para cuando otro software necesita planes de corte sin que una persona abra la aplicación.
Todo lo que CutOptim hace en tu navegador parte de un mismo cálculo: dadas estas piezas y este material, ¿cuál es la mejor forma de cortarlas? La Engine API expone exactamente ese cálculo a través de internet, para que un programa distinto pueda plantear la pregunta y recibir la respuesta — sin navegador, sin clics, sin nadie con la sesión iniciada.
Esa es toda la idea. No es un optimizador nuevo, ni un optimizador mejor, ni un plan más grande. Es el mismo motor, accesible para el software en lugar de para una persona.
¿Esto es para mí?
Para la inmensa mayoría de los usuarios de CutOptim, la respuesta honesta es no. Si tu jornada de trabajo consiste en abrir CutOptim, introducir piezas y material, e imprimir o exportar el plan, la aplicación es el producto y esta página es irrelevante para ti.
La Engine API es para una situación: los planes de corte necesitan aparecer dentro de un software que ya usas, sin que nadie visite CutOptim. En la práctica eso significa una de dos personas:
- Ya usas un software dentro del cual pertenece el plan de corte. Un ERP que guarda tus pedidos, una herramienta de presupuestos que fija precios a los trabajos, o el propio software de una máquina. En lugar de que un operario vuelva a teclear la misma lista de piezas en CutOptim, ese programa consulta el motor directamente y muestra el plan allí donde ya ocurre el trabajo.
- Estás encargando que te construyan un software. Un desarrollador interno, una empresa de software local o el proveedor de tu máquina. La Engine API es aquello a lo que ellos se conectan.
Usar la Engine API implica que alguien escribe software contra ella. No hay interfaz, ni hoja de cálculo que rellenar ni nada que instalar — es un servicio para programas, y el trabajo lo hace quien escribe ese programa. Si nadie de tu parte va a programar, la aplicación es lo que quieres.
Si no tienes claro en qué lado de esa línea estás, una buena prueba: ¿podría aparecer el plan sin que nadie lo pida? Si es así, la API es relevante. Si siempre hay una persona que decide crear un plan de corte, la aplicación ya es la herramienta adecuada.
Qué hace
Tu software envía las mismas dos cosas que teclearías en la aplicación — una lista de piezas y una lista de material — en formato JSON. El motor devuelve una respuesta completa:
- El plano completo. Cada pieza, colocada en un tablero o barra concretos, incluido si se giró.
- Un plan de corte. No solo un dibujo de rectángulos: la secuencia real de cortes de guillotina, en orden, para que el plan pueda ejecutarse en una seccionadora.
- Los números. Cuántos tableros o barras requiere el trabajo, el porcentaje de aprovechamiento, cuántos cortes hacen falta y el precio total del material utilizado. Para paneles también obtienes los dos recuentos honestos de cortes — líneas de corte, que fusiona los cortes que comparten un mismo ajuste de tope, y pasadas de sierra, que cuenta cada pasada — además de la longitud total serrada.
- Opcionalmente, el dibujo. Pide
include: ["svg","csv","dxf"]y la respuesta también lleva la distribución como un archivo listo para usar — un dibujo SVG 2D autónomo, un DXF R12/AC1009 o una lista de corte CSV — en línea en el JSON, sin almacenamiento y sin una segunda llamada. (SVG es solo 2D.) En las solicitudes 2D también puedes pedirlabels(datos de etiqueta por pieza),planHash(una huella del plan),pdf(el PDF del plan de corte) ylabelsPdf(el PDF de etiquetas): los PDF en base64, dibujados con el mismo código que la app. - Tus propios identificadores, devueltos. Adjunta un objeto
meta— un número de artículo, una línea de pedido, una referencia de cliente — a cualquier pieza o fila de material, y vuelve sin cambios en cada pieza colocada y cada tablero o barra, para que el plan cuadre con tu propio sistema. Este es el campo que debes usar cuando quieras enviar todos tus tableros, etiquetar cada uno con tu propio código y leer de vuelta qué tablero eligió el optimizador: pon el código enstock[].metay vuelve reflejado ensheets[].meta. Nunca afecta a la colocación. No uses el campomaterialpara identificar:materiales una partición estricta (una pieza solo se corta a partir de material del mismo tipo), así que etiquetar cada fila de material con un material y dejar las piezas sin etiquetar hace que todas las piezas vuelvan comounmatchedy el resultado quede vacío.
Hay cuatro modos de optimización, todos correspondientes a la aplicación — uno para paneles 2D, uno para material lineal 1D como barras, perfiles y tubo, uno para madera, donde el material tiene una sección, y el anidado por forma real (POST /v1/optimize/nest), que encaja polígonos arbitrarios para corte por láser, plasma y chorro de agua (el modo Nesting de la aplicación). Cada endpoint de optimización tiene además un endpoint de validación gratuito que comprueba una solicitud sin resolverla (ver más abajo).
Endpoints
La URL base es https://api.cutoptim.com. Los endpoints de optimización y de uso llevan una clave en una cabecera Authorization: Bearer <key>; los endpoints de validación y de disponibilidad no necesitan clave.
| Endpoint | Qué hace |
|---|---|
POST /v1/optimize/2d |
Optimización de paneles 2D |
POST /v1/optimize/1d |
Optimización 1D / lineal — barras, perfiles, tubo |
POST /v1/optimize/wood |
Optimización de madera — 1D con coincidencia de sección |
POST /v1/optimize/nest |
Anidado de forma real — polígonos irregulares para láser, plasma y chorro de agua |
POST /v1/validate/2d · /1d · /wood · /nest |
Validar una solicitud sin resolver — gratis, sin clave, sin cuota |
GET /v1/jobs/{id} |
Sondear un trabajo asíncrono del motor max — solo tus propios trabajos, sin cuota |
POST /v1/import/nest |
Lee los contornos de las piezas de un archivo SVG o DXF — requiere clave, no consume cuota |
GET /v1/usage |
El uso y la cuota de la CUENTA para el mes en curso (todas las claves comparten una) |
GET /v1/health |
Comprobación de disponibilidad — no necesita clave |
La mayoría de las llamadas se responden directamente con el resultado terminado. La única excepción es el motor asíncrono max (ver Tres motores más abajo): un envío max devuelve un id de trabajo, y sondeas GET /v1/jobs/{id} hasta que el plan esté listo.
Los endpoints de validación toman el mismo cuerpo que el endpoint de optimización correspondiente y lo comprueban sin ejecutar el cálculo: una solicitud mal formada vuelve como un 400 que nombra el campo exacto que falla, y una bien formada devuelve valid: true más avisos de viabilidad (por ejemplo, una pieza que no cabe en ningún material). No cuestan nada y no necesitan clave, así que puedes validar tus cargas útiles mientras construyes la integración — antes incluso de tener una clave — y confirmar que una solicitud no será rechazada sin gastar una de tus llamadas mensuales.
Dirección de la veta en paneles
El contrachapado y los tableros chapados tienen veta, y una pieza vista debe cortarse con la veta en el sentido correcto. En POST /v1/optimize/2d, envía grain en una fila de material ("w" o "h", el lado del tablero a lo largo del cual corre la veta) y grain en una pieza (el lado de la pieza a lo largo del cual debe correr). Cada una de esas piezas se coloca con su veta a lo largo de la de su tablero: girada 90° cuando es lo que hace falta (rotated: true en la colocación, como en cualquier giro), y rotatable se ignora para ella. Una pieza sin grain sigue girando libremente, también en una fila de material sin grain (MDF, melamina); una pieza CON grain mantiene también en esa fila la orientación que le dan las filas con veta — material separa los tableros con veta de los lisos. Una pieza que solo cabría girada 90° contra la veta aparece en unplaced con el tamaño enviado, una línea de warnings la nombra y POST /v1/validate/2d lo avisa antes de gastar una llamada.
En una misma solicitud pueden convivir filas de material cuya veta corre en direcciones distintas (un 2440 × 1220 con "w" y un 1220 × 2440 con "h"), y cada tablero vuelve en la orientación de su propia fila, con grain devuelto en sheets[]. Con material, una pieza solo queda sujeta a una veta cuando su propio material tiene un tablero con veta. Si la solicitud no incluye ningún material con veta, el grain de una pieza no tiene efecto, y una línea en warnings lo indica. options.trim y un options.firstCut forzado se aplican a cada tablero en la orientación de su propia fila, también en una fila cuya veta corre en el otro sentido. El modo Dirección de la veta de la app de CutOptim ejecuta el mismo código. (Desde el 2 de octubre de 2026.)
Coincidencia de veta en paneles (conjuntos)
La dirección de veta mantiene la veta de cada pieza en el sentido correcto. Algunos frentes necesitan más: un frente de cajón sobre dos puertas cuyo dibujo continúe de uno a otro, como si las tres piezas siguieran siendo un mismo tablero. En POST /v1/optimize/2d, da un id a esas filas de piezas y nómbralas en 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"]] } }
]
}
- Qué es un conjunto.
layout.linesenumera los miembros porparts[].id. Condir: "rows"cada línea es una fila de miembros uno junto a otro y las filas se apilan de arriba abajo, así que[["DF"], ["DOOR", "DOOR"]]es un frente de cajón sobre dos puertas; con"cols"cada línea es una columna y las columnas van una junto a otra. Una pieza puede aparecer más de una vez en un mismo conjunto (Door, Door), pero solo puede pertenecer a un conjunto.qty(por defecto 1) es cuántas instancias necesitas —tres muebles iguales sonqty: 3— y elqtypropio de las piezas debe cubrir todas las instancias. Un conjunto tiene al menos 2 y como máximo 24 miembros, y una solicitud admite como máximo 50 conjuntos. - Cómo se corta. El conjunto pasa por el optimizador como un solo rectángulo —el bloque— y vuelve como sus miembros, separados exactamente por un kerf, de una misma pieza de tablero. El
graindel conjunto ("w"o"h", a lo largo del ancho o del alto del bloque) decide la dirección de todos los miembros; elgrainpropio de un miembro no se usa dentro del conjunto, y un warning nombra a cualquier miembro al que sustituye. Singrainen el conjunto, el bloque puede girar cuando todos los miembros sonrotatable.installGapes la holgura entre los miembros en el mueble (por defecto: el kerf); en el tablero siguen separados por un kerf. - Qué devuelve. Cada miembro colocado lleva
matchedSet: eliddel conjunto, quéinstancey supositionen orden de lectura en el frente del mueble —de arriba abajo y de izquierda a derecha, desde 1—, más unhintcomo"left"o"right"cuando no hay ambigüedad. La respuesta añade un resumenmatchedSets, una entrada por conjunto: suletter(A, B … en el orden de la solicitud), cuántas instancias se cortaron como un bloque (asBlock), divididas o sin colocar, el tamaño del bloque y loswarningsdel conjunto. Cuando un bloque no cabe en ningún tablero,onMiss: "split"(el valor por defecto) coloca los miembros uno a uno con un warning, yonMiss: "unplaced"los enumera enunplaced. - Avisos, no errores. Una medida que no cuadra es un aviso del conjunto, no un rechazo. Cada línea empieza con su código —
align:(las líneas no quedan enrasadas),gap:(el kerf es más ancho queinstallGap),grain:,split:,unplaced:,unmatched:(no hay stock del material del conjunto),priority:ygrainGroup:—, yalignygapse juzgan a 1/64 de tu unidad o un cuarto de kerf, lo que sea menor. Un conjunto que no puede disponerse en absoluto —un id de miembro que ninguna pieza lleva, un id referenciado en dos piezas, menos de dos miembros, demasiadas pocas piezas paraqty— es un400que nombra el campo exacto, antes de que se cobre una llamada. parts[].ides seguro de enviar. Solo se comprueba un id al que se refiere un conjunto (una cadena imprimible no vacía de como máximo 64 caracteres, o un entero, en exactamente una pieza). Cualquier otro id se ignora, sea cual sea su contenido, así que tus números de artículo del ERP pueden quedarse en las filas. Y no cambia nada para una solicitud sin conjuntos: solo un arraymatchedSetsno vacío activa la función —ausente,null,[]o cualquier valor que no sea un array se responde exactamente como antes—.- Exportaciones. Con conjuntos,
csvgana las columnasSetyPositional final,svgimprime el código de posición (A1, A2 …) en las etiquetas de las piezas y dibuja el marco de cada conjunto en un grupomatched-setsaparte —options.setOutlines: falseomite ese grupo—, ydxflleva el código de posición en la capa LABELS.pdfylabelsPdfno marcan los conjuntos: dibujan los miembros como piezas normales, ywarningslo dice; las marcas del conjunto están ensheets[].parts[].matchedSet,csvysvg. - Motores y endpoints. Los motores
heuristicybalanceddisponen conjuntos (balancedno ordena porpriority, así que conrespectStockun conjunto puede perder su sitio allí, con un warningpriority:). El motormaxrechaza unmatchedSetsno vacío con un400cuyodetails.unsupportedlo nombra, antes de que se cobre una llamada; uno vacío es un trabajomaxordinario.matchedSetsyparts[].idson solo 2D: los endpoints 1D, wood y nest los ignoran. grainGroupestá obsoleto. Se sigue aceptando y funciona exactamente como antes: las piezas que comparten un grupo se mantienen en un mismo tablero. Nunca las colocó una junto a otra, así que no da una veta continua entre ellas; para eso, usamatchedSets.
La función Coincidencia de veta de la app de CutOptim dispone los conjuntos con el mismo núcleo.
Por qué la madera tiene su propio endpoint
El material lineal conoce una sola dimensión, su longitud, así que cualquier barra puede servir para cualquier pieza. La madera no funciona así: una pieza de 50×150 no puede salir de una barra de 50×100, por mucha longitud que le quede. Por eso el endpoint de madera toma los dos lados de la sección en cada pieza y cada fila de material, divide el trabajo por sección, empareja cada sección con su propio material y devuelve las secciones por separado — cada una con sus propias barras y sus propios totales, junto a las cifras del trabajo completo.
Dos detalles que conviene conocer antes de integrarlo:
- Los dos lados de la sección pueden enviarse en cualquier orden. 50×100 y 100×50 son la misma barra girada, así que se emparejan como una sola sección. Eso significa que una diferencia en cómo se hayan introducido tus datos no puede hacer que desaparezca material.
- “No hay material de esta sección” y “no cupo” se informan por separado. Lo primero es un aviso de material faltante, lo segundo es un problema de capacidad, y tienen soluciones distintas — así que mezclarlos en una sola lista haría que tu usuario buscara en el sitio equivocado.
Podrías aproximar esto con varias llamadas 1d propias, agrupando tú mismo las piezas. Costaría una petición de tu cuota por sección en lugar de una por trabajo, dejaría la coincidencia de material en tu código y produciría un total del trabajo que tendrías que ensamblar tú mismo — uno que no coincidiría necesariamente con lo que la aplicación de CutOptim muestra para el mismo trabajo.
Piezas desde un archivo CAD
El endpoint de nesting no acepta solo coordenadas. Una pieza puede llevar en su lugar un source — un documento SVG o DXF — y el servidor extrae de él su contorno y los agujeros que contenga. Es el mismo lector que usa la app cuando sueltas un dibujo sobre su modo Nesting, así que una biblioteca de piezas que ya existe como archivos CAD no hay que reescribirla antes en listas de coordenadas.
El archivo sustituye solo la geometría. Cantidad, material, rotaciones permitidas y tus propios metadatos siguen siendo campos normales de la fila de la pieza, igual que cuando envías coordenadas. Un archivo describe una pieza; cuando un mismo dibujo contiene varios componentes separados, POST /v1/import/nest lo divide antes en filas listas para usar — y esa llamada requiere una clave pero no consume una solicitud de tu cuota mensual.
No se almacena nada. El archivo existe únicamente como la propia solicitud: se lee en memoria y desaparece en el momento en que se escribe la respuesta. No queda copia en disco ni en una base de datos, nada acaba en un registro y después no hay nada que borrar. Con las unidades hacemos lo mismo — un DXF puede declarar milímetros o pulgadas y nosotros informamos de lo que dijo, pero las coordenadas nunca se convierten, porque ningún valor de esta API lleva unidad.
La misma respuesta cada vez
El motor es determinista: la misma entrada siempre produce la misma salida. No hay aleatoriedad ni reloj dentro del algoritmo.
Esto suena académico pero es la razón práctica para construir sobre él. Significa que los resultados pueden cachearse — si ya preguntaste por este mismo trabajo exacto, puedes reutilizar la respuesta con seguridad en lugar de preguntar de nuevo. También significa que la integración puede probarse: un plan puede compararse con un resultado conocido como bueno, y una diferencia es una diferencia real, no ruido. Un software que le da un precio a un cliente el lunes le dará el mismo precio el viernes.
Hay una excepción opcional, y lo indica: el motor max de anidado (más abajo) dedica un presupuesto de tiempo fijo a buscar, así que hasta dónde llega depende de cuánto trabajo entre en ese tiempo. Sus respuestas llevan deterministic: false. Todos los demás motores — incluido el predeterminado de anidado, lbf — son deterministas.
Reintentar con seguridad. Si se corta la conexión, no sabe si la solicitud llegó. Envíe una cabecera Idempotency-Key —un valor que usted elige para cada trabajo— y reintente con la misma clave: durante 24 horas, la misma solicitud devuelve la respuesta guardada, marcada con Idempotency-Replayed: true, y no se cobra otra vez. Un trabajo max tampoco se encola dos veces. La clave demo pública ignora esta cabecera. (Desde 2026-10-15.)
Webhooks para trabajos asíncronos. En lugar de consultar GET /v1/jobs/{id}, registre un endpoint (una URL https://) en su panel y reciba un POST firmado — job.succeeded o job.failed — cuando termine un trabajo max asíncrono. Compruebe la cabecera CutOptim-Signature con el secreto recibido, responda en 10 segundos y lea el plan con GET /v1/jobs/{id}. Una entrega fallida se reintenta: 8 intentos en 24 horas. (Desde 2026-10-19.)
SDK oficiales. Clientes de código abierto para TypeScript, Python y PHP — npm install @cutoptim/engine, pip install cutoptim, composer require cutoptim/engine — con peticiones tipadas, reintentos que nunca se cobran dos veces (cada llamada lleva un Idempotency-Key), una ayuda para esperar los trabajos asíncronos y verificación de webhooks. Código en GitHub; detalles en la guía de SDK (en inglés).
Servidor MCP para asistentes de IA. Claude Code, Cursor, VS Code y Claude Desktop pueden llamar al motor como herramientas a través del servidor Model Context Protocol alojado en https://api.cutoptim.com/mcp, con la misma clave de API (Authorization: Bearer …) y la misma cuota: una llamada a una herramienta es una llamada a la API, y las herramientas validate_* son gratuitas. También se ejecuta en local con el paquete npx -y @cutoptim/mcp (clave en CUTOPTIM_API_KEY), y el MCP Registry oficial lo lista como io.github.cutoptim/engine. Las configuraciones de cada cliente están en la guía MCP (en inglés).
Tres motores
La API ofrece a elegir entre motores. Los dos primeros se ejecutan de forma síncrona; el tercero es asíncrono. La diferencia no es de calidad — es un compromiso entre velocidad, si el resultado puede cortarse en una seccionadora y cuánto se acerca al mínimo teórico.
heuristices el predeterminado y el mismo que usa la aplicación. Produce planos de guillotina: mayor aprovechamiento, todos los planos cortables en una seccionadora, y siempre un plan de corte completo. Síncrono.balancedes opcional. Usa anidado libre en su lugar, que es drásticamente más rápido en trabajos muy grandes — medido en aproximadamente 25× más rápido en un trabajo de 2.000 piezas — a costa de un aprovechamiento algo menor. La pega importante: sus planos a menudo no pueden cortarse de borde a borde, así que para esos no devuelve ningún plan de corte. Síncrono.maxes opcional, para paneles 2D (y, por separado, para el anidado de forma real — ver más abajo). En 2D es una búsqueda en árbol del lado del servidor que alcanza el óptimo probado en muchos más trabajos que el predeterminado, y sus planos siguen siendo cortables con guillotina. El coste es tiempo: un cálculomaxtarda de segundos a un minuto, así que no responde en la propia respuesta. En su lugar,POST /v1/optimize/2dconengine: "max"devuelve un id de trabajo, y sondeasGET /v1/jobs/{id}hasta que esté listo. Sigue siendo determinista. Recurre a él cuando un trabajo grande y valioso merezca la espera por los últimos tableros. Modela un solo formato de stock a tamaño completo de tablero, con disponibilidad ilimitada, así que una solicitud que además lleve un segundo formato de stock,trimpor lado, stock limitado (respectStock), materiales, grupos de veta o unmatchedSetsno vacío se rechaza de antemano con un400que nombra exactamente lo que no puede hacer — antes de que se cobre una llamada. Envía esos trabajos aheuristic, que los modela todos.
Anidado: lbf y max
El anidado de forma real tiene sus propios dos motores. lbf es el predeterminado: instantáneo, síncrono y determinista. max es opcional y asíncrono, exactamente igual que el max de 2D — POST /v1/optimize/nest con engine: "max" devuelve un id de trabajo, y sondeas GET /v1/jobs/{id}.
El max de anidado ejecuta primero la pasada de lbf, así que siempre tiene una respuesta válida en la mano. Luego dedica un presupuesto de tiempo (options.timeBudgetMs, 60 segundos por defecto, entre 10 y 180) a buscar una distribución con menos tableros, llenando un tablero cada vez. Nunca devuelve más tableros que lbf: cuando la búsqueda no encuentra ninguna mejora, obtienes la distribución de lbf y un aviso que lo dice. Como la búsqueda tiene un tiempo limitado, sus respuestas llevan deterministic: false. Acepta varios tamaños de tablero por material y respectStock, y clasifica su resultado con la misma regla que lbf (más abajo): sustituye el plan de lbf solo cuando es mejor — nunca solo porque tenga menos tableros. Un tablero poligonal o las zonas de exclusión, que su búsqueda por bandas no puede modelar, los sirve la pasada de lbf dentro del trabajo, con un aviso — nunca se rechazan. El nombre antiguo sparrow se acepta como alias de max.
Las piezas rectangulares obtienen una cuadrícula exacta (desde el 2026-09-28). lbf encuentra las posiciones por muestreo, y eso casi nunca da con una cuadrícula sin holgura: tres piezas de 500 mm a lo ancho de un tablero de 1500 mm con espaciado cero encajan exactamente, y una búsqueda por muestreo coloca dos. Por eso los dos motores prueban también dos alternativas y se quedan con la que mejor clasifica según la misma regla: las piezas restringidas a los ángulos rectos que permiten, y los rectángulos envolventes de las piezas colocados por un empaquetador exacto de rectángulos (rectángulos que no se solapan no pueden contener piezas que se solapen, así que es válido para cualquier contorno). En caso de empate — mismos tableros, misma área de tablero — gana el plan que llena sus tableros en orden, del primero al último, y después el que tiene menos piezas giradas fuera de los ángulos rectos. No hay nada que activar, y por esa clasificación un resultado solo puede mejorar; un plan que los rectángulos llevan al menor número de tableros que permite el área de las piezas hace además que max responda al instante en lugar de seguir buscando.
Un trabajo de unas pocas docenas de piezas suele necesitar unos 15 segundos de presupuesto (timeBudgetMs: 15000); el trabajo termina aproximadamente entre uno y dos segundos después del presupuesto, más el tiempo que pase en la cola. Sondea GET /v1/jobs/{id} cada dos o tres segundos — sondear no cuesta cuota. Ningún presupuesto puede prometer un número de tableros concreto.
Anidado: margen en el borde, tamaños de tablero y lo que costó cada tablero
- Margen en el borde.
options.minSeparationes el espaciado entre piezas, y por sí solo también se aplica en el borde del tablero.options.edgeClearancefija el borde por separado — por ejemplo 5 entre piezas y 0 o 10 en el borde. Si lo omites, el borde conservaminSeparation, exactamente como antes. Funciona en los dos motores, necesita tableros rectangulares (wyh), y las zonas de exclusión conservanminSeparationigual que las piezas. Un tablero poligonal, o un valor que no deje espacio en el tablero, se rechaza con un400antes de que se cobre una llamada. - Elegir un tamaño de tablero. Cuando un material tiene dos o más filas de material,
lbflas prueba en tu orden, cada tamaño por su cuenta y en un orden de más barato primero, y se queda con la mejor — así el resultado deja de depender del orden en que listes las filas. La clasificación es: el mayor número de piezas de corte obligatorio colocadas (ver más abajo), luego más piezas colocadas, luego la menor área total de tablero (material), luego el menor número de tableros. Conoptions.minimizeCostclasifica por precio total en su lugar (price, ocostpara una fila sin precio) — pero solo cuando todas las filas de ese material llevan uno; si no, recae en el área y lo indica enwarnings. - Mezclar tamaños. Después, cada tablero — empezando por el menos lleno — se vuelve a anidar por su cuenta sobre las filas más baratas o más pequeñas, y se sustituye cuando el plan completo clasifica mejor. Así los tamaños pueden mezclarse dentro de un mismo material: normalmente dos tableros grandes y uno más pequeño al final, donde el último tablero, ahora medio vacío, antes era uno grande. Con
options.respectStock, ninguna fila se usa más veces que suqty. El motormaxaplica la misma clasificación. - Piezas de corte obligatorio.
parts[].priority: truemarca una pieza que debe cortarse sí o sí. Importa conoptions.respectStock— un suministro limitado, donde no todas las piezas pueden caber: las piezas de corte obligatorio se colocan entonces primero, así que una pieza normal nunca ocupa el espacio de tablero que necesita una pieza de corte obligatorio, y cada clasificación anterior prioriza el plan que conserva más de ellas, incluso si coloca menos piezas en total. Los dos motores lo respetan (maxconserva la distribución delbfsiempre que algo quede sin colocar). SinrespectStock, todas las piezas que caben se colocan de todos modos, así que la marca no cambia nada. Una pieza de corte obligatorio que no cabe en ningún tablero sigue apareciendo enunplaced. (Desde el 22 de septiembre de 2026 — antes, el motor de anidado aceptaba el campo pero lo ignoraba.) - Un stock limitado en el que no cabe todo. Con
options.respectStock, cuando el plan aún deja piezas sin colocar, el motor además llena las hojas una a una con los rectángulos envolventes de las piezas — cada una lo más llena posible, y una pieza que solo cabe en un tamaño de hoja va allí primero (un lateral alto en la única hoja grande, no en una tira de retal). Ese plan solo se adopta si coloca más piezas (primero las obligatorias) o usa menos material; un trabajo en el que cabe todo vuelve exactamente como antes. Respeta las rotaciones permitidas de cada pieza,minSeparationyedgeClearance. (Desde el 2026-10-14.) - Lo que costó cada tablero. Cada tablero lleva
stock— el índice de la fila de material de la solicitud desde la que se cortó — y la respuesta añadestockUsage: una entrada por cada fila de material usada, con su número de tableros, precio total y densidad. La unidad es la fila de material, no el tamaño: dos filas con las mismas dimensiones pero un precio ometadistinto son dos entradas. - Longitud de corte y perforaciones. Cada tablero lleva
cutLength— el perímetro sumado de los contornos de sus piezas colocadas y sus agujeros, en tu unidad — ypierces, uno por cada contorno cerrado;metricstotaliza ambos. Es la longitud geométrica del contorno: sin corte por línea común, entradas de corte ni microuniones — tu CAM las añade. - Área usada, para facturar por tablero parcial. Cada tablero lleva
usedWidthyusedHeight— el punto más lejano al que llega cualquier pieza colocada desde la esquina de origen del tablero, en tu unidad, sobre el tablero real (conedgeClearancese incluye el margen al borde) — yusedArea, su producto;stockUsage[].usedArealo totaliza por fila de material. Eso es lo que necesita un ERP para cobrar un corte horizontal (usedHeight× ancho del tablero), uno vertical (usedWidth× alto del tablero) o la caja envolvente (usedArea) en lugar del tablero completo — la regla de facturación sigue siendo tuya. Para que esos números sean pequeños, los dos motores compactan por defecto el tablero menos lleno de cada material: sus piezas se vuelven a anidar sobre el mismo tablero con subconjuntos de rotación de lo que cada pieza permite — 0/180, 0/90/180/270 y una sola orientación para todas las copias, intersectado con unallowedRotationsdiscreto, nunca un ángulo nuevo — y se conserva la disposición con la menor área usada. Conengine: "max", ese tablero lo vuelve a colocar después también la propia búsqueda — a lo largo de la altura del tablero y, si el plan tiene un solo tablero, también a lo largo de su anchura — y se conserva, con la misma regla, la disposición más ajustada. El número de tableros, los tamaños, el precio y las piezas colocadas nunca cambian;options.compact: falsedevuelve la disposición sin compactar. Si facturas una franja en vez de la caja envolvente, fijaoptions.compactForsegún corresponda:"horizontal"conserva la disposición con la menorusedHeight(una franja que cruza todo el ancho del tablero),"vertical"la de menorusedWidth(una franja que cruza todo el alto del tablero); el valor por defecto"box"conserva la menorusedArea. Los modos de franja también prueban cada copia girada un cuarto de vuelta (90° o 270°) dondeallowedRotationslo permita. Lo pequeña que llegue a ser el área usada depende de las piezas. (Desde el 22 de septiembre de 2026.)
balanced no significa “mejores resultados”. Es más rápido y aprovecha algo menos, y cuando su plano no es cortable con guillotina no hay ningún plan de corte que entregar a un operario de sierra. Elígelo solo cuando la velocidad en un trabajo muy grande importe más que un plan listo para la sierra. Si tienes dudas, quédate con el predeterminado.
Límites
Cada petición está acotada, para que un trabajo desbocado falle con claridad en lugar de quedarse colgado:
| Límite | Valor |
|---|---|
| Piezas por petición | 2.000 |
| Filas de material por petición | 50 |
| Tamaño del cuerpo de la petición | 1 MB |
| Tamaño del cuerpo de la solicitud — rutas nest que pueden llevar un dibujo | 10 MB |
| Claves activas por cuenta | 10 |
Llamadas validate sin clave por dirección |
120 / minuto |
| Claves API desconocidas por dirección | 30 / minuto — después 429 durante el resto del minuto |
| Espera por un hueco de cálculo libre (rutas síncronas) | unos 8 s — después 429, sin cargo |
Trabajos max en queued/running por cuenta |
5 |
Presupuesto de búsqueda del motor max de anidado por trabajo |
10–180 s (60 s por defecto) |
Conservación de Idempotency-Key |
24 horas |
| Endpoints de webhook por cuenta | 5 |
| Intentos de entrega de webhook | 8 en 24 horas |
Obtener acceso
Empieza en la página de la Engine API. La Engine API se factura por separado de los planes de la aplicación, y ninguna mejora de plan la activa.
- Pruébala, luego suscríbete — o pregunta. Puedes llamar a la API antes de pagar: los botones Ejecutar este ejemplo de la referencia de la API usan una clave de demostración pública, y cualquier cuenta con la sesión iniciada puede crear claves de prueba gratuitas en el panel (su propio cupo mensual reducido, nunca se facturan, sin suscripción). Cuando estés listo, suscribirte en la página de la Engine API es la vía más rápida — el plan de entrada, Studio, empieza con una prueba gratuita, y el acceso llega a tu cuenta por sí solo. Si prefieres describir primero tu integración, o necesitas un volumen por encima del plan estándar, ponte en contacto en su lugar y di qué quieres conectar y aproximadamente cuántos planes de corte al mes necesitará.
- El acceso aparece en tu cuenta. Nada más de tu cuenta cambia.
- Crea una clave. La tarjeta de claves de API está en tu panel para toda cuenta con la sesión iniciada: sin suscripción crea claves de prueba, con acceso a la API también claves live. Tú mismo creas, nombras y eliminas claves ahí.
- Copia la clave de inmediato. La clave completa se muestra exactamente una vez, en el momento en que la creas.
Una clave se muestra solo una vez. CutOptim almacena únicamente un hash sha256 de ella, nunca la clave en sí — así que no puede volver a leerse después, ni por ti ni por nosotros. Cópiala directamente en la configuración de tu software cuando la crees. Si pierdes una clave, elimínala y crea una nueva; si una clave llega a quedar expuesta, elimínala y las llamadas dejan de funcionar de inmediato.
Trata una clave como una contraseña: pertenece a la configuración de tu software, no a un correo, una hoja de cálculo o una captura de pantalla.
Qué hace la tarjeta de claves de API de tu panel
Cuatro controles, y vale la pena ser preciso sobre qué cambia cada uno — especialmente el último, que la gente espera que toque la facturación y no lo hace.
- Plan, Cambiar y Facturación. Muestra en qué plan está la cuenta (Studio o Scale). Cambiar a Scale (o Cambiar a Studio) cambia el plan tras una confirmación, y la cuota mensual de la cuenta cambia de inmediato. Facturación abre tu configuración de facturación, donde actualizas la tarjeta, ves las facturas o cancelas.
- Crear clave. Genera una clave nueva y la muestra una vez, ahí mismo. Le pones un nombre (
ERP integration,staging) únicamente para poder distinguir tus claves más adelante. Hasta 10 claves activas por cuenta. Las claves de prueba se crean igual y se cuentan aparte: tienen su propio cupo mensual reducido y nunca se facturan. - La barra de uso. Dos números: el total de tu cuenta para el mes natural frente a la cuota mensual, y por clave, cuánto ha gastado esa clave. La cifra por clave está para responder qué integración se está comiendo el cupo — no es un presupuesto aparte.
- Revocar. Deja esa clave concreta sin funcionar, a partir de la siguiente llamada. La fila permanece visible para que no se pierda su historial.
Revocar una clave no tiene nada que ver con tu suscripción. No cancela nada, no reembolsa nada y no libera cuota — el plan sigue en marcha y el cupo sigue vigente, simplemente dejas de tener esa clave en particular. Revoca cuando una clave haya quedado expuesta o cuando se retire una integración. Para dejar de pagar, cancela la suscripción en su lugar; el acceso continúa entonces hasta el final del periodo que ya pagaste, y después de eso incluso las claves existentes dejan de funcionar.
Una cuota para la cuenta, no una por clave
Cada clave activa de tu cuenta consume del mismo cupo mensual. Crear una segunda clave no crea una segunda cuota — las claves existen para que puedas separar staging de producción, dar a cada integración su propia credencial y revocar una sin molestar a las demás.
GET /v1/usage informa de la posición de la cuenta (used, limit, remaining), de modo que responde a la pregunta que realmente tienes — cuánto queda antes de que las llamadas empiecen a fallar — con independencia de con qué clave preguntaste. Cuando se agota el cupo, todas las claves devuelven 402, no solo la que lo gastó.
Planes, precio y cuota
La Engine API se factura por separado de los planes de la aplicación, de forma mensual, en EUR, con dos planes:
| Plan | En qué se diferencian |
|---|---|
| Studio | El plan de entrada, con una prueba gratuita |
| Scale | Una cuota mensual de peticiones mayor, sin prueba — se llega a él cambiando desde Studio |
Todo lo demás es igual en los dos: los mismos motores, los cuatro modos, todas las opciones, las mismas respuestas. Cada petición cuenta igual — un trabajo de anidado cuesta una petición, exactamente igual que uno de 2D o de 1D.
- Tope estricto, sin excesos. Cuando se agota la cuota mensual, las llamadas devuelven
402hasta que se restablece el primer día del mes siguiente. No hay factura sorpresa. - Dos correos, para que el tope no te sorprenda. Enviamos un correo a la cuenta al llegar al 90 % de la cuota y otro cuando se agota.
- El cambio de plan es un solo botón en la tarjeta de claves de API de tu panel (Cambiar a Scale / Cambiar a Studio); la nueva cuota se aplica de inmediato. Una mejora se cobra al instante por el resto del periodo; una bajada no se reembolsa y el precio más bajo se aplica desde la próxima renovación. El cambio está disponible al terminar la prueba.
- Los volúmenes mayores que el plan Scale se presupuestan de forma individual — ponte en contacto.
Los precios y cuotas actuales están indicados en la página de la Engine API — esa página los lee de nuestra configuración de precios, así que siempre es la cifra exacta.
Para el detalle técnico — la forma exacta de la petición y la respuesta, todas las opciones, todos los códigos de error y cómo funciona el versionado — consulta la referencia de la API.
Componentes de código abierto
Los motores de CutOptim se apoyan en bibliotecas de código abierto, usadas sin modificar en nuestros servidores:
- jagua-rs — el motor geométrico de colisiones detrás del anidado de forma real (MPL-2.0).
- sparrow — la búsqueda detrás del motor max de anidado (MIT, KU Leuven).
- PackingSolver — la búsqueda en árbol detrás del motor max de 2D (MIT).
Todo lo demás que hay a su alrededor — la API, la correspondencia entre el contrato y estos motores, los empaquetadores rectangulares y la propia aplicación — es código propio de CutOptim.
Qué no cambia esto
Vale la pena decirlo con claridad, porque es fácil malinterpretar la Engine API como un cambio en el producto:
- El optimizador de la aplicación no cambia. Sigue ejecutándose en tu navegador, exactamente igual que antes.
- Gratis, Pro y Taller no se ven afectados. Siguen incluyendo el optimizador integrado, con los mismos límites que antes. Nada se movió detrás de la API.
- Nada de lo que hagas en la aplicación consume peticiones de la API. La cuota mensual de la API solo se toca con las llamadas que hace tu propio software.
La Engine API es una adición para quienes integran CutOptim en otro software. Si ese no eres tú, nada ha cambiado.