Документація API

Інтегруйте керування замовленнями, оптимізацію 2D розкрою та перевірку DXF CNC від Handifyit у свій робочий процес. Оптимізація підтримує результати JSON та експорт PDF, SVG, DXF, CSV і PTX. Автентифіковані запити API використовують заголовок Authorization: Bearer <token>.

Також можна працювати в браузері: створювати замовлення, імпортувати деталі, порівнювати збережені результати, обирати потрібний варіант і змінювати статуси. Нижче наведено документацію API; щоб почати без коду, перегляньте опис роботи із замовленнями. Як це працює

Перейти до: CNC попередній валідатор · POST /api/validate-cnc · Набори обмежень · Оптимізація · Імпорт CSV · Імпорт DXF · Swagger UI

Автентифікація — довготривалі токени API

Handifyit використовує Довготривалі токени API для автоматизованих або серверних запитів. Вони діють, доки ви їх не відкличете. Щоб отримати токен, виконайте три кроки нижче.

1

Увійдіть, щоб отримати токен доступу

Надішліть облікові дані та перейдіть на сторінку Профіль.

POST /login
Content-Type: application/json

{
  "email": "[email protected]",
  "password": "yourpassword"
}

→ 200 OK
{
  "access_token":  "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
2

Створіть довготривалий токен API

Дайте токену API зрозумілу назву. Скопіюйте отриманий токен — його значення показується лише один раз.

POST /api/tokens
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "name": "My Production App"
}

→ 201 Created
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",  ← збережіть це!
  "name": "My Production App"
}

Токени API також можна відкликати через Профіль.

3

Використовуйте токен API в кожному запиті

Передавайте токен API як Bearer у всіх запитах до /api/*.

POST /api/optimize
Authorization: Bearer <your-api-token>
Content-Type: application/json

{ ... тіло запиту ... }

Спільне тіло запиту

Усі шість кінцевих точок оптимізації приймають однакове тіло JSON. Обов’язкові лише materials, stock_plates, parts та optimize_type; решта має значення за замовчуванням.

ПолеСтатусЗа замовчуваннямОпис
materialsобов’язкове—Масив матеріалів. Кожен об’єкт потребує id (ціле число), name (рядок), identifier (короткий код) і може містити thickness у мм (типово 18). Деталі та плити групуються за material_id.
stock_platesобов’язкове—Доступні плити для розкрою. Кожен об’єкт: width, height, quantity (типово 1), material_id.
partsобов’язкове—Деталі для розкрою. Кожен об’єкт: width, height, quantity (типово 1), material_id та can_rotate (типово true). Поворот визначається для кожної деталі.
optimize_typeобов’язкове—"saw" — гільйотинні прямолінійні різи для форматно-розкрійних верстатів. "cnc" — вкладений розкрій для фрезерних верстатів ЧПК, гнучкіший, але повільніший.
blade_widthнеобов’язкове5Ширина пропилу пилки або фрези, 1–10, у тих самих одиницях, що й розміри деталей і плит. Віднімається між різами. Імпорт файлів допускає 0–10.
trim_stock_plateнеобов’язкове10Обрізка кожного краю плити перед оптимізацією, 0–50, для вилучення непридатного крайового матеріалу.
allow_mixed_stock_sizesнеобов’язковеtrueДозволяє змішувати формати плит одного матеріалу. Значення false вимагає однакового розміру всіх плит матеріалу.
pattern_directionнеобов’язкове"none""paralleltowidth"
performance_modeнеобов’язкове"normal""fast" — найшвидша відповідь. "normal" — збалансований режим (рекомендовано). "high" — інтенсивне ущільнення для зменшення відходів ціною довшого обчислення.
random_seedнеобов’язкове0Цілочисельне початкове значення генератора випадкових чисел. Однакове значення дає змогу відтворювати однакові схеми між запитами.
can_rotateнеобов’язкове—Застаріле. Параметр рівня запиту збережено для сумісності: він задає однаковий дозвіл повороту всім деталям. Пропустіть його, щоб застосовувалися окремі прапорці can_rotate.

Повний приклад запиту

{
  "materials": [
    { "id": 1, "name": "Plywood 18mm", "identifier": "PLY18", "thickness": 18 }
  ],
  "stock_plates": [
    { "width": 2440, "height": 1220, "quantity": 5, "material_id": 1 }
  ],
  "parts": [
    { "width": 800, "height": 600, "quantity": 4, "material_id": 1, "can_rotate": true  },
    { "width": 400, "height": 300, "quantity": 8, "material_id": 1, "can_rotate": false }
  ],
  "optimize_type":           "saw",
  "blade_width":              5,
  "trim_stock_plate":         10,
  "allow_mixed_stock_sizes":  true,
  "pattern_direction":       "none",
  "performance_mode":        "normal",
  "random_seed":              0
}

Обмеження безкоштовного тарифу

Для безкоштовних облікових записів наведені обмеження діють на всіх кінцевих точках оптимізації (/api/optimize, /api/optimize/pdf, /api/optimize/dxf, /api/optimize/svg, /api/optimize/csv, /api/optimize/ptx та всіх варіантах from-dxf і from-csv):

  • 25 деталей на запит — сума всіх значень part.quantity у масиві parts не має перевищувати 25. Перевищення повертає 400.
  • 25 запитів оптимізації на день — облік ведеться для кожного облікового запису й скидається опівночі UTC. Перевищення повертає 429.
POST/api/optimize

Запускає оптимізатор і повертає повну схему у JSON. Файли не створюються. Використовуйте цю кінцеву точку для обробки або відображення результатів у власному застосунку.

Структура відповіді

{
  "results": [
    {
      "material": { "id": 1, "name": "Plywood 18mm", "identifier": "PLY18",
                    "thickness": 18 },
      "layouts": [
        {
          "stock_width":  2420,
          "stock_height": 1200,
          "stock_index":  0,
          "cuts": [
            { "x": 0,   "y": 0,   "width": 800, "height": 600, "part_id": 0 },
            { "x": 805, "y": 0,   "width": 400, "height": 300, "part_id": 1 },
            { "x": 805, "y": 305, "width": 400, "height": 300, "part_id": 1 }
          ],
          "cut_length_mm":     10420,
          "cut_length_method": "guillotine",
          "offcuts": [
            { "x": 1220, "y": 0, "width": 1220, "height": 1220 },
            …
          ],
          "saw_plan": {
            "kind": "split", "x": 0, "y": 0, "width": 2440, "height": 1220,
            "axis": "x", "cuts": [5, 810, 1215],
            "children": [
              { "kind": "offcut", "x": 0, "y": 0, "width": 5, "height": 1220 },
              { "kind": "split", "x": 10, "y": 0, "width": 800, "height": 1220,
                "axis": "y", "cuts": [5, 610],
                "children": [
                  { "kind": "offcut", "x": 10, "y": 0, "width": 800, "height": 5 },
                  { "kind": "part", "x": 10, "y": 10, "width": 800, "height": 600,
                    "cut_index": 0 },
                  …
                ] },
              …
            ]
          }
        }
      ],
      "summary": {
        "total_stock_used":    1,
        "total_parts":         12,
        "material_efficiency": 91.8,
        "total_cut_length_mm": 10420
      }
    }
  ]
}

Відповідь містить один запис results для кожного матеріалу. Запис включає:

  • layouts — об’єкт для кожної використаної плити; cuts містить положення (x, y) і розміри кожної деталі на плиті
  • summary — total_stock_used, total_parts, material_efficiency (0–100 %) та total_cut_length_mm

stock_width і stock_height описують корисну площу плити після віднімання trim_stock_plate з кожного краю. Координати cut відраховуються від верхнього лівого кута цієї площі. part_id — індекс деталі у власній групі матеріалу, а не глобальний ідентифікатор.

cut_length_mm вимірюється двома способами, а cut_length_method вказує спосіб: "guillotine" — шлях пилки, "contour" — периметр, який фреза проходить навколо деталі. Це різні фізичні величини; не додавайте й не порівнюйте їх між собою.

stock_index — позиція вихідної плити в масиві stock_plates запиту. offcuts — цілі залишки без деталей після запланованих різів, включно з дрібними відходами. На відміну від cuts, їх координати задано на необрізаній плиті. Розміри фізичні: пропил уже враховано, необрізані краї включено.

saw_plan — той самий план у вигляді дерева на необрізаній плиті. Частину "split" ділять паралельними різами: cuts задає початки смуг пропилу вздовж axis ("x" — пилка рухається вздовж плити, "y" — поперек). Ширина смуги — blade_width. children містить запис для кожного проміжку; null означає відсутність залишку. Листки дерева — деталі "part", де cut_index посилається на cuts, та залишки "offcut". Значення null означає, що послідовність прямих різів неможлива, як іноді буває для схем "cnc".

POST/api/optimize/pdf

Оптимізує та формує один багатосторінковий PDF, по сторінці на плиту. Файл завантажується у хмарне сховище; повертається підписане посилання для завантаження.

Запит

Таке саме тіло JSON, як у /api/optimize (див. вище).

Відповідь

{
  "files": [
    {
      "name": "layout-1708433600000.pdf",
      "url":  "https://storage.example.com/pdf/1708433600000/layout-1708433600000.pdf"
    }
  ]
}

Відповідь містить один файл PDF з усіма плитами.

POST/api/optimize/dxf

Оптимізує та створює файл DXF для кожної плити. Формат сумісний із більшістю систем CAD/CAM і контролерів ЧПК (AutoCAD, Fusion 360, Mach3 тощо). Повертає окремі посилання на завантажені файли.

Запит

Таке саме тіло JSON, як у /api/optimize (див. вище).

Відповідь

{
  "files": [
    {
      "name": "plate-1-25318.dxf",
      "url":  "https://storage.example.com/dxf/1708433600000/plate-1-25318.dxf"
    },
    {
      "name": "plate-2-25318.dxf",
      "url":  "https://storage.example.com/dxf/1708433600000/plate-2-25318.dxf"
    }
  ]
}

Один файл на плиту. Назва містить індекс плити й ідентифікатор запуску: plate-1-25318.dxf — плита 1 запуску 25318.

POST/api/optimize/csv

Оптимізує та створює один CSV з усіма деталями всіх матеріалів і плит. Рядки містять положення, розміри деталі та плити, назву й код матеріалу для таблиць, ERP або власних постпроцесорів. Файл зберігається у хмарі; повертається посилання.

Запит

Таке саме тіло JSON, як у /api/optimize (див. вище).

Стовпці CSV

Part ID, x, y, width, height, stock_width, stock_height, material(as name), material(as identifier)

Відповідь

{
  "files": [
    {
      "name": "layout-1708433600000.csv",
      "url":  "https://storage.example.com/csv/1708433600000/layout-1708433600000.csv"
    }
  ]
}

Один CSV з усіма різами всіх матеріалів і плит.

POST/api/optimize/svg

Оптимізує та створює SVG для кожної плити. Масштабована векторна графіка підходить для перегляду у браузері та імпорту в Inkscape, Illustrator або Figma. Повертає окремі посилання на завантажені файли.

Запит

Таке саме тіло JSON, як у /api/optimize (див. вище).

Відповідь

{
  "files": [
    {
      "name": "plate-1-25318.svg",
      "url":  "https://storage.example.com/svg/1708433600000/plate-1-25318.svg"
    },
    {
      "name": "plate-2-25318.svg",
      "url":  "https://storage.example.com/svg/1708433600000/plate-2-25318.svg"
    }
  ]
}
POST/api/optimize/ptx
Бета

Експорт PTX перебуває на етапі бета-тестування й ще не перевірений на реальних верстатах. Перевірте експортовані файли на своєму верстаті перед використанням у виробництві.

Оптимізує та створює файл PTX (Pattern Exchange) для кожної групи матеріалу. Це формат обміну для пилок HOLZMA / HOMAG, сумісний із HolzLink, CADmatic 4/5 та HOMAG intelliDivide. Файл містить завдання матеріалу, схеми й послідовності різів. Повертає посилання на файли у хмарі.

Запит

Таке саме тіло JSON, як у /api/optimize (див. вище). Значення optimize_type: "saw" дає гільйотинні схеми для виконання на форматно-розкрійному верстаті.

Відповідь

{
  "files": [
    {
      "name": "J1708433600000.PTX",
      "url":  "https://storage.example.com/ptx/1708433600000/J1708433600000.PTX"
    }
  ]
}

Один PTX на групу матеріалу. Кожен файл містить:

  • HEADER, один рядок JOBS і один MATERIALS — метадані програми, товщину плити, ширину пропилу та обрізку.
  • BOARDS + PATTERNS — пара для кожної унікальної схеми, з розмірами необрізаної плити й кількістю її повторень. Однакові схеми об’єднуються.
  • PARTS_REQ + PARTS_INF + PARTS_UDI — відповідні рядки кожної унікальної геометрії деталі у схемі, з наскрізною нумерацією завдання. Кількості враховують усі повторні плити. Необов’язкові описи та мітки крайок порожні; код матеріалу — DSP.
  • CUTS — вказівки початкових, поздовжніх, поперечних, повторних різів і обрізки; окрема послідовність для кожної схеми з посиланнями на потрібні деталі.

Типова товщина — 18 мм, поширена для меблевих плит. Виміри у міліметрах. Назви програм і файлів мають вигляд J<timestamp>.PTX, з унікальним числовим ідентифікатором для кожного матеріалу.

Вкладена схема "cnc" не завжди придатна для пилки. У такому разі кінцева точка повертає 422 замість файлу.

Імпорт списку деталей CSV

Кінцеві точки from-csv приймають multipart/form-data замість JSON. Завантажте список деталей із таблиці: сервер створить масив parts з рядків. Інші параметри — матеріали, плити, пропил тощо — передайте рядком JSON у полі params.

Формат CSV

↓ Завантажити шаблон / приклад CSVУсі підтримувані поля та 10 прикладів деталей із різною кількістю. Замініть коди матеріалів своїми.

Material Code,Width,Height,Quantity,Can Rotate
PLY18,800,600,4,1
PLY18,400,300,8,0
MDF16,1200,400,2,1

Як рядки перетворюються на деталі

  • Рядок заголовків обов’язковий. Регістр, крайові пробіли, дефіси й підкреслення ігноруються в назвах: Material Code, Width, Height, Quantity, Can Rotate.
  • Material Code зіставляється з identifier елемента масиву materials. Невідомий код призводить до помилки запиту із зазначенням рядка.
  • Can Rotate необов’язкове: 1 дозволяє поворот на 90°, 0 забороняє. Порожня клітинка або відсутній стовпець означають без повороту, щоб зберегти напрям волокон.
  • Material Code, Width, Height та Quantity обов’язкові в кожному рядку.
  • Підтримуються кома, крапка з комою, табуляція, UTF-8 BOM і текст у лапках. Розміри API — додатні цілі міліметри; кількості — додатні цілі числа.

Крайкування кожного боку

Для Top, Right, Bottom та Left задайте Edge Band (код), Edge Thickness (мм), Pre Milling (зняті мм) і Edge Method. Приклади: Top Edge Band, Top Edge Thickness. Назви боків стосуються деталі до повороту.

Необроблені боки залишайте порожніми. Методи: none, band, pre_mill_band. Пропущений метод визначається з коду, товщини й фрезерування. Для крайкування потрібна додатна товщина; API не шукає коди у каталозі. Імпортер робочого місця може взяти відсутню товщину з каталогу.

Dimension Mode приймає blank (типово) або finished. Оптимізатор компенсує товщину та попереднє фрезерування. Необов’язкові обмеження верстата: Banding Min Length, Banding Min Cross Size, Pre Milling Min Length, Pre Milling Min Cross Size, у мм; нуль вимикає обмеження. Processing Order містить кожен бік один раз, наприклад top right bottom left. Помилки вказують номер рядка.

Робоче місце також імпортує Part Code, Part Name, Grain (none, paralleltowidth, paralleltolength), Priority і Notes. API оптимізації CSV без збереження стану ігнорує ці метадані замовлення.

Поля запиту (multipart)

ПолеСтатусТипОпис
fileобов’язкове—Список деталей CSV із заголовками, наведеними вище.
paramsобов’язкове—Параметри оптимізації у JSON (див. таблицю нижче). Усі поля OptimizeRequest, крім parts.

Поля JSON «params»

ПолеСтатусЗа замовчуваннямОпис
materialsобов’язкове—Потрібен хоча б один матеріал. identifier зіставляється з Material Code кожного рядка.
stock_platesобов’язкове—Як у /api/optimize; потрібна хоча б одна плита.
optimize_typeобов’язкове—"saw" або "cnc" (як у /api/optimize).
blade_widthнеобов’язкове5Пропил у мм. Імпорт файлів, на відміну від кінцевої точки JSON, допускає 0.
trim_stock_plateнеобов’язкове10Як у /api/optimize.
allow_mixed_stock_sizesнеобов’язковеtrueЯк у /api/optimize.
pattern_directionнеобов’язкове"none"Як у /api/optimize.
performance_modeнеобов’язкове"normal"Як у /api/optimize.
random_seedнеобов’язкове0Як у /api/optimize.

Приклад JSON «params»

{
  "materials": [
    { "id": 1, "name": "Plywood 18mm", "identifier": "PLY18", "thickness": 18 },
    { "id": 2, "name": "MDF 16mm",     "identifier": "MDF16", "thickness": 16 }
  ],
  "stock_plates": [
    { "width": 2440, "height": 1220, "quantity": 5, "material_id": 1 },
    { "width": 2800, "height": 2070, "quantity": 3, "material_id": 2 }
  ],
  "optimize_type":           "saw",
  "blade_width":              5,
  "trim_stock_plate":         10,
  "allow_mixed_stock_sizes":  true,
  "pattern_direction":       "none",
  "performance_mode":        "normal",
  "random_seed":              0
}

Приклад запиту (curl)

# результат JSON
curl -X POST https://handifyit.com/api/optimize/from-csv \
  -H "Authorization: Bearer <your-api-token>" \
  -F "[email protected]" \
  -F 'params={
    "materials":    [{"id":1,"name":"Plywood 18mm","identifier":"PLY18","thickness":18}],
    "stock_plates": [{"width":2440,"height":1220,"quantity":5,"material_id":1}],
    "optimize_type":   "saw",
    "blade_width":      5,
    "trim_stock_plate": 10
  }'

# PDF — формат експорту ставиться перед суфіксом «from-csv»:
curl -X POST https://handifyit.com/api/optimize/pdf/from-csv \
  -H "Authorization: Bearer <your-api-token>" \
  -F "[email protected]" \
  -F 'params={"materials":[...],"stock_plates":[...],"optimize_type":"saw"}'

# Та сама схема для /svg/from-csv /dxf/from-csv /csv/from-csv /ptx/from-csv

Кінцеві точки

POST/api/optimize/from-csv

Читає CSV, оптимізує та повертає повну схему JSON зі структурою /api/optimize.

{
  "results": [
    {
      "material": { "id": 1, "name": "Plywood 18mm", "identifier": "PLY18",
                    "thickness": 18 },
      "layouts": [
        {
          "stock_width":  2420,
          "stock_height": 1200,
          "stock_index":  0,
          "cuts": [
            { "x": 0,   "y": 0,   "width": 800, "height": 600, "part_id": 0 },
            { "x": 805, "y": 0,   "width": 400, "height": 300, "part_id": 1 },
            { "x": 805, "y": 305, "width": 400, "height": 300, "part_id": 1 }
          ],
          "cut_length_mm":     10420,
          "cut_length_method": "guillotine",
          "offcuts": [
            { "x": 1220, "y": 0, "width": 1220, "height": 1220 },
            …
          ],
          "saw_plan": {
            "kind": "split", "x": 0, "y": 0, "width": 2440, "height": 1220,
            "axis": "x", "cuts": [5, 810, 1215],
            "children": [
              { "kind": "offcut", "x": 0, "y": 0, "width": 5, "height": 1220 },
              { "kind": "split", "x": 10, "y": 0, "width": 800, "height": 1220,
                "axis": "y", "cuts": [5, 610],
                "children": [
                  { "kind": "offcut", "x": 10, "y": 0, "width": 800, "height": 5 },
                  { "kind": "part", "x": 10, "y": 10, "width": 800, "height": 600,
                    "cut_index": 0 },
                  …
                ] },
              …
            ]
          }
        }
      ],
      "summary": {
        "total_stock_used":    1,
        "total_parts":         12,
        "material_efficiency": 91.8,
        "total_cut_length_mm": 10420
      }
    }
  ]
}
POST/api/optimize/{format}/from-csv

Той самий імпорт з експортом. {format} — pdf, svg, dxf, csv або ptx. Відповідь — оболонка { "files": [...] } з підписаними посиланнями для завантаження.

Бета

Експорт PTX перебуває на етапі бета-тестування й ще не перевірений на реальних верстатах. Перевірте експортовані файли на своєму верстаті перед використанням у виробництві.

Оптимізація з імпортом DXF

Кінцеві точки from-dxf приймають multipart/form-data замість JSON. Сервер читає зовнішні контури DXF, тому масив parts вручну не потрібен. Замкнена межа стає деталлю, чиї width та height визначає обмежувальний прямокутник, паралельний осям. Усі налаштування оптимізації передайте рядком JSON у полі params.

Як виділяються деталі з DXF

  • Замкнені об’єкти LWPOLYLINE, POLYLINE, ELLIPSE та SPLINE верхнього рівня, без зовнішньої межі, стають деталями.
  • width і height — розміри обмежувального прямокутника деталі, паралельного осям, округлені до цілого в одиницях unit (типово мм). Деталі менші за 1 одиницю в будь-якому вимірі пропускаються.
  • Усі деталі отримують матеріал material_id; типово це id першого елемента масиву materials.
  • Внутрішні контури — свердління, вирізи, пази — ігноруються. Для оптимізації розкрою потрібна лише зовнішня межа деталі.

Поля запиту (multipart)

ПолеСтатусТипОпис
fileобов’язкове—Байти файлу DXF (R12–2018). Розширення назви має бути .dxf.
paramsобов’язкове—Параметри оптимізації у JSON (таблиця нижче): усі поля OptimizeRequest, крім parts, плюс unit та material_id.

Поля JSON «params»

ПолеСтатусЗа замовчуваннямОпис
materialsобов’язкове—Як у /api/optimize; потрібен хоча б один матеріал.
stock_platesобов’язкове—Як у /api/optimize; потрібна хоча б одна плита.
optimize_typeобов’язкове—"saw" або "cnc" (як у /api/optimize).
unitнеобов’язкове"mm""cm"
material_idнеобов’язковеid першого матеріалуІдентифікатор матеріалу для всіх деталей DXF. Типово — id першого елемента масиву materials.
blade_widthнеобов’язкове5Пропил у мм. Імпорт файлів, на відміну від кінцевої точки JSON, допускає 0.
can_rotateнеобов’язковеtrueЗастосовується до всіх деталей DXF, бо креслення не має окремого прапорця повороту для кожної деталі.
trim_stock_plateнеобов’язкове10Як у /api/optimize.
allow_mixed_stock_sizesнеобов’язковеtrueЯк у /api/optimize.
pattern_directionнеобов’язкове"none"Як у /api/optimize.
performance_modeнеобов’язкове"normal"Як у /api/optimize.
random_seedнеобов’язкове0Як у /api/optimize.

Приклад JSON «params»

{
  "materials": [
    { "id": 1, "name": "Plywood 18mm", "identifier": "PLY18", "thickness": 18.0 }
  ],
  "stock_plates": [
    { "width": 2440, "height": 1220, "quantity": 5, "material_id": 1 }
  ],
  "optimize_type":           "saw",
  "blade_width":              5,
  "can_rotate":               true,
  "trim_stock_plate":         10,
  "allow_mixed_stock_sizes":  true,
  "pattern_direction":       "none",
  "performance_mode":        "normal",
  "random_seed":              0,
  "unit":                    "mm",
  "material_id":              1
}

Приклад запиту (curl)

# результат JSON
curl -X POST https://handifyit.com/api/optimize/from-dxf \
  -H "Authorization: Bearer <your-api-token>" \
  -F "[email protected]" \
  -F 'params={
    "materials":       [{"id":1,"name":"Plywood 18mm","identifier":"PLY18","thickness":18}],
    "stock_plates":    [{"width":2440,"height":1220,"quantity":5,"material_id":1}],
    "optimize_type":   "saw",
    "blade_width":      5,
    "can_rotate":       true,
    "trim_stock_plate": 10,
    "unit":            "mm"
  }'

# PDF — використовуйте кінцеву точку експорту PDF:
curl -X POST https://handifyit.com/api/optimize/pdf/from-dxf \
  -H "Authorization: Bearer <your-api-token>" \
  -F "[email protected]" \
  -F 'params={"materials":[...],"stock_plates":[...],"optimize_type":"saw"}'

# Та сама схема для /svg/from-dxf /dxf/from-dxf /csv/from-dxf /ptx/from-dxf

Кінцеві точки

POST/api/optimize/from-dxf

Читає DXF, оптимізує та повертає повну схему JSON зі структурою /api/optimize.

{
  "results": [
    {
      "material": { "id": 1, "name": "Plywood 18mm", "identifier": "PLY18",
                    "thickness": 18 },
      "layouts": [
        {
          "stock_width":  2420,
          "stock_height": 1200,
          "stock_index":  0,
          "cuts": [
            { "x": 0,   "y": 0,   "width": 800, "height": 600, "part_id": 0 },
            { "x": 805, "y": 0,   "width": 400, "height": 300, "part_id": 1 },
            { "x": 805, "y": 305, "width": 400, "height": 300, "part_id": 1 }
          ],
          "cut_length_mm":     10420,
          "cut_length_method": "guillotine",
          "offcuts": [
            { "x": 1220, "y": 0, "width": 1220, "height": 1220 },
            …
          ],
          "saw_plan": {
            "kind": "split", "x": 0, "y": 0, "width": 2440, "height": 1220,
            "axis": "x", "cuts": [5, 810, 1215],
            "children": [
              { "kind": "offcut", "x": 0, "y": 0, "width": 5, "height": 1220 },
              { "kind": "split", "x": 10, "y": 0, "width": 800, "height": 1220,
                "axis": "y", "cuts": [5, 610],
                "children": [
                  { "kind": "offcut", "x": 10, "y": 0, "width": 800, "height": 5 },
                  { "kind": "part", "x": 10, "y": 10, "width": 800, "height": 600,
                    "cut_index": 0 },
                  …
                ] },
              …
            ]
          }
        }
      ],
      "summary": {
        "total_stock_used":    1,
        "total_parts":         12,
        "material_efficiency": 91.8,
        "total_cut_length_mm": 10420
      }
    }
  ]
}
POST/api/optimize/pdf/from-dxf

Читає DXF, оптимізує та повертає PDF-план, по сторінці на плиту, за підписаним посиланням.

{
  "files": [
    {
      "name": "layout-1708433600000.pdf",
      "url":  "https://storage.example.com/pdf/1708433600000/layout-1708433600000.pdf"
    }
  ]
}
POST/api/optimize/svg/from-dxf

Читає DXF, оптимізує та повертає по файлу SVG на плиту за підписаними посиланнями.

{
  "files": [
    {
      "name": "plate-1-25318.svg",
      "url":  "https://storage.example.com/svg/1708433600000/plate-1-25318.svg"
    },
    {
      "name": "plate-2-25318.svg",
      "url":  "https://storage.example.com/svg/1708433600000/plate-2-25318.svg"
    }
  ]
}
POST/api/optimize/dxf/from-dxf

Читає DXF, оптимізує та повертає по файлу схеми DXF на плиту за підписаними посиланнями.

{
  "files": [
    {
      "name": "plate-1-25318.dxf",
      "url":  "https://storage.example.com/dxf/1708433600000/plate-1-25318.dxf"
    },
    {
      "name": "plate-2-25318.dxf",
      "url":  "https://storage.example.com/dxf/1708433600000/plate-2-25318.dxf"
    }
  ]
}
POST/api/optimize/csv/from-dxf

Читає DXF, оптимізує та повертає один список розкрою CSV за підписаним посиланням.

{
  "files": [
    {
      "name": "layout-1708433600000.csv",
      "url":  "https://storage.example.com/csv/1708433600000/layout-1708433600000.csv"
    }
  ]
}
POST/api/optimize/ptx/from-dxf
Бета

Експорт PTX перебуває на етапі бета-тестування й ще не перевірений на реальних верстатах. Перевірте експортовані файли на своєму верстаті перед використанням у виробництві.

Читає DXF, оптимізує та повертає файли PTX для пилок HOLZMA / HOMAG за підписаними посиланнями.

{
  "files": [
    {
      "name": "J1708433600000.PTX",
      "url":  "https://storage.example.com/ptx/1708433600000/J1708433600000.PTX"
    }
  ]
}

Попередня перевірка ЧПК

Перед виробництвом засіб перевірки ЧПК аналізує файл DXF за обмеженнями верстата. Він читає межі деталей та внутрішні операції — свердління, вирізи, пази — і шукає порушення геометричних правил.

КодСерйозністьОпис
PART_TOO_SMALLпомилкаОбмежувальний прямокутник деталі менший за part_min_width × part_min_height.
PART_TOO_LARGEпомилкаОбмежувальний прямокутник деталі перевищує part_max_width × part_max_height.
OPERATION_OUTSIDE_PARTпомилкаОдна або кілька вершин контуру операції лежать поза межею деталі.
OPERATION_INTERSECTS_EDGEпомилкаРебра операції перетинають межу деталі, навіть якщо вершини всередині.
OPERATION_TOO_CLOSE_TO_EDGEпомилка / попередженняВідстань операції до краю менша за min_edge_offset. Помилка при < ½ межі, попередження при < межі.
DRILL_DIAMETER_TOO_SMALLпомилкаДіаметр свердління менший за drill_min_diameter.
DRILL_DIAMETER_TOO_LARGEпомилкаДіаметр свердління перевищує drill_max_diameter.
OPERATIONS_INTERSECTпомилкаДві операції на одному боці перекриваються.
OPERATIONS_TOO_CLOSEпомилка / попередженняВідстань між поверхнями двох операцій менша за min_op_spacing. Помилка при < ½ межі, попередження при < межі.
POST/api/validate-cnc

Завантажте DXF як multipart/form-data. Відповідь — повний ValidationReport, з одним PartResult на виявлену деталь, її операціями й порушеннями.

Поля запиту (multipart)

ПолеСтатусТипОпис
fileобов’язкове—Байти DXF. Підтримується більшість двійкових версій R12–2018.
configнеобов’язковетипові значенняОб’єкт ValidationConfig у JSON (таблиця нижче). Усі поля необов’язкові; пропущені отримують типові значення.

Поля ValidationConfig

ПолеСтатусЗа замовчуваннямОпис
part_min_widthнеобов’язкове50Мінімальна допустима ширина деталі у мм.
part_min_heightнеобов’язкове50Мінімальна допустима висота деталі у мм.
part_max_widthнеобов’язкове2800Максимальна допустима ширина деталі у мм.
part_max_heightнеобов’язкове2070Максимальна допустима висота деталі у мм.
drill_min_diameterнеобов’язкове2Мінімальний діаметр свердла у мм.
drill_max_diameterнеобов’язкове35Максимальний діаметр свердла у мм.
min_edge_offsetнеобов’язкове8Мінімальна відстань (мм) від краю операції до межі деталі.
min_op_spacingнеобов’язкове8Мінімальна відстань між поверхнями двох операцій у мм.
groove_aspect_ratioнеобов’язкове3.0Замкнений внутрішній контур класифікується як паз, а не звичайний виріз, якщо довга сторона ≥ цьому коефіцієнту × короткій стороні.
unitнеобов’язкове"mm""cm"

Приклад запиту (curl)

curl -X POST https://handifyit.com/api/validate-cnc \
  -H "Authorization: Bearer <your-api-token>" \
  -F "[email protected]" \
  -F 'config={"part_min_width":50,"part_min_height":50,\
              "part_max_width":2800,"part_max_height":2070,\
              "drill_min_diameter":2,"drill_max_diameter":35,\
              "min_edge_offset":8,"min_op_spacing":8,\
              "groove_aspect_ratio":3,"unit":"mm"}'

Приклад відповіді

{
  "valid": false,
  "summary": {
    "total_parts":      3,
    "total_operations": 12,
    "total_issues":     2,
    "errors":           1,
    "warnings":         1
  },
  "parts": [
    {
      "id":    "part_1",
      "layer": "PART",
      "bbox":  { "min_x": 0, "min_y": 0, "max_x": 400, "max_y": 300,
                 "width": 400, "height": 300 },
      "operations": [
        {
          "id":     "op_1",
          "kind":   "drilling",
          "side":   "through",
          "layer":  "DRILL",
          "bbox":   { "min_x": 46, "min_y": 46, "max_x": 54, "max_y": 54,
                      "width": 8, "height": 8 },
          "center": { "x": 50, "y": 50 },
          "diameter": 8
        }
      ],
      "issues": [
        {
          "code":         "OPERATION_TOO_CLOSE_TO_EDGE",
          "message":      "Operation op_1 is 3.50 mm from the part edge (minimum: 8.0 mm)",
          "severity":     "error",
          "operation_id": "op_1"
        }
      ],
      "valid": false
    }
  ]
}

Основні поля відповіді:

  • valid — true, лише якщо жодна деталь не має проблем рівня помилка.
  • summary — загальні кількості: total_parts, total_operations, errors, warnings.
  • parts[] — об’єкт кожної виявленої деталі з обмежувальним прямокутником, операціями та проблемами.
  • issues[].severity — "error" (блокувальна) або "warning" (лише рекомендаційна).

Збережені конфігурації ЧПК

Зберігайте іменовані конфігурації ValidationConfig для повторних перевірок. Вони доступні лише вашому обліковому запису.

GET/api/cnc-configs

Повертає всі збережені конфігурації автентифікованого користувача.

GET /api/cnc-configs
Authorization: Bearer <your-api-token>

→ 200 OK
{
  "configs": [
    {
      "id":         "d4f2a1b3-...",
      "name":       "Standard Router",
      "config":     { ... },
      "created_at": "2026-04-05T10:00:00Z",
      "updated_at": "2026-04-05T10:00:00Z"
    }
  ]
}
POST/api/cnc-configs

Створює іменовану конфігурацію. Повертає 201 Created зі збереженим записом.

POST /api/cnc-configs
Authorization: Bearer <your-api-token>
Content-Type: application/json

{
  "name": "Standard Router",
  "config": {
    "part_min_width":     50,
    "part_min_height":    50,
    "part_max_width":     2800,
    "part_max_height":    2070,
    "drill_min_diameter": 2,
    "drill_max_diameter": 35,
    "min_edge_offset":    8,
    "min_op_spacing":     8,
    "groove_aspect_ratio": 3,
    "unit": "mm"
  }
}

→ 201 Created
{
  "id":         "d4f2a1b3-...",
  "name":       "Standard Router",
  "config":     { ... },
  "created_at": "2026-04-05T10:00:00Z",
  "updated_at": "2026-04-05T10:00:00Z"
}
PUT/api/cnc-configs/{id}

Замінює назву та/або налаштування конфігурації. Структура тіла така сама, як у POST. Повертає 200 OK з оновленим записом або 404, якщо ID відсутній чи належить іншому користувачу.

DELETE/api/cnc-configs/{id}

Назавжди видаляє конфігурацію. Повертає 204 No Content після успіху або 404, якщо її не знайдено.

Відповіді з помилками

Усі кінцеві точки повертають помилки в однаковій оболонці JSON:

{ "message": "A part (800×600) does not fit any stock plate" }
  • 400 — перевищено кількість деталей: сума quantity більша за обмеження тарифу на запит. Також повідомляє про некоректний CSV або відсутнє поле multipart.
  • 401 — токен Bearer відсутній, прострочений або відкликаний.
  • 422 — деталь не вміщується в жодну плиту або плит недостатньо. Оптимізація виконується повністю або завершується помилкою; часткової схеми немає. Повідомлення називає деталь або обмеження. PTX також повертає 422, якщо схема непридатна для пилки.
  • 429 — досягнуто добового ліміту запитів. Скидання опівночі UTC.
  • 500 — внутрішня помилка сервера, наприклад збій завантаження файлу.