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).
| Field | Type | Description |
|---|---|---|
| content | string · required | The 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. |
| filename | string | Used for format detection AND as the part name when the row has no name (extension stripped). Never touches a filesystem. |
| flattenTolerance | number · default 0.2 | Curve / 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.
| Field | Type | Description |
|---|---|---|
| parts | integer | Part ROWS whose geometry came from a file. |
| vertices | integer | Total 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.
| Field | Type | Description |
|---|---|---|
| content | string · required | The 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. |
| filename | string | Used for detection and to NAME the parts: one outline keeps the bare name, several are numbered <name> 1, <name> 2, … |
| flattenTolerance | number · default 0.2 | Curve / arc flattening tolerance in the file's own unit. |
POST /v1/import/nest — response
| Field | Type | Description |
|---|---|---|
| format | "svg" | "dxf" | The parser that actually ran — useful when you let the server sniff. |
| parts | NestImportedPart[] | 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[].name | string | Named from filename: one outline keeps the bare name, several are numbered. |
| parts[].polygon | number[][] | 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[].holes | number[][][] | Present only when the outline actually contained a ring. |
| vertices | integer | Total 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. |
| warnings | string[] | 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. |
| engineEnabled | boolean | Whether 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. |
| contractVersion | string | Nest contract version. Currently "1". |