Skip to main content
← API reference

Parts from SVG and DXF

A drawing instead of coordinates — inline on a part, or imported first.

Parts from a file (SVG · DXF)

A part does not have to arrive as coordinates. Put an SVG or DXF document in parts[].source and the server reads the outline — and its holes — out of it with the same parser the CutOptim app uses when you drop a drawing on its Nesting mode. The file replaces ONLY the geometry: qty, material, allowedRotations, minQuality, priority and meta behave exactly as they do on a polygon part, so a part library that already exists as CAD files needs no path-and-arc flattener of your own.

One source describes ONE part; a drawing holding several separate components is a 400 that points you at the import endpoint below. The response then carries an imported block saying how many rows came from a file, how many vertices they produced, and which units those files declared — reported, never applied, because this API converts nothing.

Nothing is stored. The bytes exist only as the request body, are parsed in memory, and are gone when the response is written: no disk, no database, no temporary file, no log line. There is nothing to delete afterwards and nothing retained — the same statelessness every other endpoint keeps.

POST /v1/optimize/nest

{
  "parts": [
    {
      "source": {
        "content": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 400 200\">\n  <path d=\"M0 0 H120 V80 H0 Z\"/>\n  <path d=\"M40 30 H80 V50 H40 Z\"/>\n</svg>",
        "filename": "washer-plate.svg"
      },
      "qty": 4,
      "meta": { "erpId": "ART-8891" }
    }
  ],
  "stock": [{ "w": 2440, "h": 1220 }]
}

Field names and types are the contract, so the tables below stay in English in every language — a translated field name would document an API that does not exist.

{
  "imported": { "parts": 1, "vertices": 8, "units": [] },
  "parts_after_import": [
    {
      "name": "washer-plate",
      "polygon": [[0, 0], [120, 0], [120, 80], [0, 80]],
      "holes": [[[40, 30], [80, 30], [80, 50], [40, 50]]],
      "qty": 4,
      "meta": { "erpId": "ART-8891" }
    }
  ]
}

parts[].source — geometry from an SVG / DXF file

Read this part's outline out of an SVG or DXF FILE instead of listing coordinates. The same parser the CutOptim app uses for its Nesting mode runs server-side, so a part library that already exists as CAD files needs no path/arc flattener of your own.

The file replaces ONLY the geometry. qty, material, allowedRotations, minQuality, priority and meta behave exactly as they do on a polygon part.

Exactly ONE outline per source. Holes are folded in automatically (a ring contained in another becomes a hole), so a typical single-part drawing — outline plus bolt holes — is one outline. A file describing several separate parts is a 400 that names POST /v1/import/nest, which splits it.

Nothing is stored. The bytes exist only as this request body, are parsed in memory and are gone when the response is written: no disk, no database, no temp file, no log line. There is nothing to delete and nothing retained.

Units are reported, never applied. A DXF may declare $INSUNITS; it comes back in imported.units and several disagreeing files produce a warning, but coordinates pass through verbatim — this API converts nothing (see the unit rule on /v1/optimize/nest).

FieldTypeDescription
contentstring · requiredThe file TEXT — not base64, not a URL, not a multipart upload: both formats are text documents, so they travel inside the JSON body like any other field. Max 4,000,000 characters per file and 8,000,000 across the request; over either is a 413. ⚠️ The HTTP body cap differs by path: 10 MB on /v1/optimize/nest and /v1/import/nest, but the DEFAULT 1 MB on /v1/validate/nest, which is the only nest path that needs no key. A source body over 1 MB therefore validates on the optimize path, not the free one.
format"svg" | "dxf"Omit to sniff the content (an <svg tag ⇒ svg, otherwise dxf). An explicit format always wins — including over a misleading filename extension.
filenamestringUsed for format detection AND as the part name when the row has no name (extension stripped). Never touches a filesystem.
flattenTolerancenumber · default 0.2Curve / arc flattening tolerance, in the FILE's own coordinate unit. Larger = fewer vertices. This is the lever when a dense outline trips the 2,000-vertex per-ring cap.

imported — what the files contributed (response, absent without a source)

What the request's source files contributed. ABSENT when every part carried polygon coordinates, which is what keeps such a request byte-identical to before the feature existed.

FieldTypeDescription
partsintegerPart ROWS whose geometry came from a file.
verticesintegerTotal vertices those files produced, after flattening (outlines + holes) — the number to watch against the 2,000-vertex per-ring cap.
units("mm" | "in")[]Distinct units the files DECLARED (DXF $INSUNITS); empty when none did. Reporting only — more than one entry also raises a warning, because mixing units silently produces a plan that validates and is physically wrong, and the server must not "fix" it by converting — no field in this API asserts a unit.

POST /v1/import/nest — one file, every outline

When a single drawing holds several different parts, import it first: this endpoint returns every closed outline it contains, largest first, in exactly the shape a parts[] row wants. Paste in the ones you need, add your own qty and material, and post that to /v1/optimize/nest. It is also how you see what is in a file before spending a solve on it.

It needs a key — flattening arbitrary geometry is real CPU work, and anonymous CPU is a bad trade — but it reserves nothing: your quota is untouched and no rate-limit headers come back, exactly like polling a job.

POST /v1/import/nest
Authorization: Bearer co_live_…

{
  "content": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 400 200\">\n  <path d=\"M0 0 H120 V80 H0 Z\"/>\n  <path d=\"M40 30 H80 V50 H40 Z\"/>\n</svg>",
  "filename": "washer-plate.svg"
}
{
  "format": "svg",
  "parts": [
    {
      "name": "washer-plate",
      "polygon": [[0, 0], [120, 0], [120, 80], [0, 80]],
      "holes": [[[40, 30], [80, 30], [80, 50], [40, 50]]]
    }
  ],
  "vertices": 8,
  "warnings": [],
  "engineEnabled": true,
  "contractVersion": "1"
}

POST /v1/import/nest — request

The same four fields parts[].source takes, at the top level. See NestSource for the caps, the sniffing rule and the no-storage guarantee.

FieldTypeDescription
contentstring · requiredThe file TEXT (not base64) — the same 4,000,000-character cap as parts[].source.
format"svg" | "dxf"Omit to sniff; an explicit value wins over the filename extension.
filenamestringUsed for detection and to NAME the parts: one outline keeps the bare name, several are numbered <name> 1, <name> 2, …
flattenTolerancenumber · default 0.2Curve / arc flattening tolerance in the file's own unit.

POST /v1/import/nest — response

FieldTypeDescription
format"svg" | "dxf"The parser that actually ran — useful when you let the server sniff.
partsNestImportedPart[]One entry per closed outline, largest first — each already in the shape a parts[] row wants: paste it in and add your own qty / material / allowedRotations. Deterministic: the same bytes always give the same vertices in the same order.
parts[].namestringNamed from filename: one outline keeps the bare name, several are numbered.
parts[].polygonnumber[][]An ordered ring of ≥3 vertices. May be given closed (first == last) or open; the DTO layer normalises. Winding order is not required — it is oriented internally.
parts[].holesnumber[][][]Present only when the outline actually contained a ring.
verticesintegerTotal vertices after flattening, outlines and holes together. Compare against the 2,000-per-ring cap before you build a big request.
sourceUnit"mm" | "in"A DXF $INSUNITS declaration when the file carries one. REPORTED, NEVER APPLIED — the API converts nothing, so this is information for you, not a transformation we performed. Absent for SVG (the format has no unit) and for a DXF that declares none.
warningsstring[]What the parser could not honour — e.g. an SVG <use> clone (not expanded), or geometry that never closed into a contour. SVG transform= attributes (on the element and its groups) are applied, and shapes inside <defs>, <clipPath>, <mask> or hidden with display:none are not read. Empty means the file was read whole.
engineEnabledbooleanWhether THIS deployment can also SOLVE a nest. Importing works everywhere (it is pure parsing); on a deployment without the nesting engine /v1/optimize/nest answers 503, and this flag tells you that up front. Mirrors the field on /v1/validate/nest.
contractVersionstringNest contract version. Currently "1".