The nesting used by imposition and estimating is also available on its own. Send part outlines and a roll or a
stack of sheets, and get back where every copy goes. Nesting explains the settings and what a layout is checked
for. All calls are team-scoped under
/a/<team_slug>/nesting/api/v1/ and need an API key (see the API overview).
/a/{team_slug}/nesting/api/v1/nest/
Nest parts on a roll or on sheets.
nesting_nest ·
View in API reference
The request#
Every length uses the request's unit: pt (the default), in, mm, cm or ft (see Units and measurements).
Outlines are closed rings of [x, y] points with y pointing up, without repeating the first point, starting
anywhere.
curl -sS -H "Authorization: Api-Key $API_KEY" -H "Content-Type: application/json" \
"https://app.example.com/a/acme/nesting/api/v1/nest/" -d '{
"unit": "in",
"container": {"type": "roll", "width": 54, "margins": {"left": 0.5, "right": 0.5},
"lead_in": 6, "lead_out": 6, "segment_length": 120, "segment_policy": "within"},
"parts": [
{"id": "panel-a", "quantity": 2, "outline": [[0, 0], [30, 0], [30, 20], [0, 20]],
"rotation": {"mode": "any", "step": 5, "max_angles": 8}, "cut_method": "thru_cut"},
{"id": "label-3x2", "quantity": 10, "outline": [[0, 0], [3, 0], [3, 2], [0, 2]], "cut_method": "kiss_cut"}
],
"options": {"spacing": 0.25, "bleed": 0.0625, "time_limit_s": 5, "layouts": 1},
"include": ["outline", "cut", "transform"]
}'
container is a roll or sheets:
- Roll:
width, sidemargins(left,right),lead_inandlead_out(material before and after the parts),segment_length(the cutter's bed length) andsegment_policy:span(the default) ignores beds,withinkeeps every part inside one bed.cost_per_lengthfills in the cost in the summary.max_lengthis reserved and must benull. - Sheets:
width,height, fourmargins,max_count(the most sheets to use) andcostper sheet.
parts[]: id (unique, up to 100 characters), quantity (1 to 100,000), outline, rotation, bleed (overrides
options.bleed), meta (any object, returned on every placement of the part) and cut_method (thru_cut or
kiss_cut, used in cut files). For keeping parts together and ganging a part also takes
split (inherit, the default, allow or never), properties, own_sheet and inks.
parts[].rotation:
| Field | Values |
|---|---|
mode |
none (as drawn), flip (0° and 180°), quarter (the four quarter turns; the default), any (each part may turn) or list (the angles you give, up to 72). |
step, max_angles |
For any. step is 0.5° to 90° (default 5°). max_angles is 1 to 72 (default 8). |
grain |
along keeps the angles at 0° and 180°, across at 90° and 270°. |
mirror |
Must be false: mirroring isn't supported yet. |
options:
| Option | Meaning |
|---|---|
spacing |
The gap between parts (default 0). |
bleed |
Added around every outline before nesting (default 0). |
panelling |
Rolls: split parts wider than the roll into strips, {"overlap": 0.5, "strategy": "fewest_seams"} or "least_material". null (the default) rejects oversize parts instead. |
time_limit_s |
How long to search, from 0.1 s (default 2 s) up to the limit of the mode. |
layouts |
How many layouts to return, best first (default 1). |
anchor |
Sheets: the corner parts pack towards, lower_left (default), lower_right, upper_left or upper_right. |
objective |
auto (default), min_containers, min_length or min_cost. Accepted for later use. Nesting currently aims to minimise roll length or sheet count regardless of this value. |
seed |
Optional value for repeat runs. Identical inputs can still produce different layouts. Allow more time with time_limit_s to look for a better fit. |
method |
free (true shape, the default), guillotine (N-up) or strips, with its rules in guillotine or strips (below). |
split |
Whether a part's copies may be split across sheets or forms: {"mode": "allow", "min_saving_pct": 5} (see keeping parts together). |
ganging |
Which parts may share a sheet, from their properties (see ganging rules). Leave it out, or null, for no rules. |
stream_candidates |
Queued jobs: how many layouts found while the job runs are listed (0 to 20, default 10; 0 turns the list off). See candidates. |
include picks the geometry returned with each placement: outline, cut and transform (all three by
default). Position, size and angle are always returned.
Methods#
free: true-shape nesting of any outlines, on rolls or sheets.guillotine: N-up for rectangles on sheets, laid out so a guillotine can cut them. Rules inoptions.guillotine:gutter_mode(shared: neighbours share a cut, the default;gutter:spacingbetween them),max_stages(knife stages, 2 to 4, default 4),cut_weight(0 to 1: how many sheets a knife stroke per lift is worth),layout_penalty(0 to 5: sheets per extra distinct form),caliperandmax_lift(sheet thickness and knife lift height, which give the sheets per lift), andedge_trim(auto,alwaysornever;neveris accepted, and cut asauto).strips: parts in straight strips between slit lines. Rules inoptions.strips:content(single: one part per strip, the default;mixed: rectangles only),direction(sheets:auto,xory; rolls:auto,lanesdown the roll orbandsacross it),gutterbetween strips (nullusesspacing),rowsper strip (1 to 20),max_widthandmax_strips(1 to 100).
Keeping parts together#
By default a part's copies are split across sheets (or N-up forms) whenever that saves sheets. options.split changes
that for the whole request, and parts[].split for one part:
allow(the default): split when it saves sheets.avoid: a split layout is preferred only when it saves more thanmin_saving_pct(0 to 50, default 5). Both kinds of layout are returned, and the best whole and the best split layout both stay withinlayouts.never: every copy of a part is on one sheet design. True shape then plans repeated sheets, which takes longer: with more than 10 parts it needs a queued job (modesyncanswers400), and it takes at most 40 parts. Rolls and sheets withmax_count1 don't plan repeated sheets, so they stay synchronous.
parts[].split is inherit (the request's rule), allow or never. Rolls print one continuous layout, so the rule
doesn't apply there: the response warns instead.
Ganging rules#
Give parts properties (key → text, number or null; at most 32 per part, keys in lowercase letters, digits and
_, due as YYYY-MM-DD) and say in options.ganging which parts may share a sheet:
"options": {"ganging": {"match_on": ["coating"],
"keep_apart": [{"key": "customer", "values": ["Brand A", "Brand B"]}],
"due_within_days": 2,
"prefer_together": [{"key": "stock", "min_saving_pct": 5}]}}
match_on: parts share a sheet only when these properties are equal (text compares without case or extra spaces). A part without the property only shares with other parts without it. Thegroupproperty is always matched.keep_apart: parts holding two different listed values never share a sheet.due_within_days: parts whoseduedates are more than this many days apart never share a sheet (parts without a date are exempt).prefer_together: a soft rule. Parts with different values of the key stay together only when mixing them saves more thanmin_saving_pct, likeavoidabove.parts[].own_sheet(true): no other part shares this part's sheets.
A rule key must be a well-known property (stock, coating, finishing, customer, order, due, group) or
appear on at least one part. Each group of parts that may share is nested on its own sheets and the results are
joined; on a roll the groups follow each other as segments. A roll holds one stock, so matching on stock with two
stocks on a roll is an error.
parts[].inks ({"front": [ink], "back": [ink] | null}, where an ink is {"key", "variant", "name", "kind", "role",
"process_step"}) doesn't change a digital layout; each container lists the union of its parts' inks.
The response#
{
"id": "00000000-0000-0000-0000-000000000000", "status": "ok", "unit": "in",
"summary": {"containers": 1, "used_length": 54.2, "consumed_area": 2926.8, "part_area": 1200.0,
"utilization": 0.41, "unplaced": [], "cost": null},
"layouts": [{
"rank": 1, "method": "free", "used_length": 54.2, "utilization": 0.41, "sheet_total": 1, "form_count": 1,
"containers": [{"index": 0, "used_length": 54.2, "utilization": 0.41, "copies": 1}], "unplaced": [],
"placements": [{"part_id": "panel-a", "piece_id": "panel-a_1", "copy": 1, "container_index": 0,
"x": 0.5, "y": 6.0, "width": 30.125, "height": 20.125, "angle": 0.0, "mirrored": false,
"meta": {}, "panel": null, "transform": [1, 0, 0, 1, 0.5625, 6.0625]}],
"cut_programs": [], "strips": [], "slits": []
}],
"diagnostics": {"elapsed_s": 4.8, "warnings": []}
}
status:ok;partial(sheets: some pieces fit no sheet ormax_countran out, and are listed inunplaced); or, for jobs,cancelledwith the best layout so far.summarydescribes the best layout.costiscontainers× the sheetcost, or the used length ×cost_per_length, andnullwhen you sent no cost. For aguillotinelayoutcontainerscounts distinct forms, not printed sheets, socostis the cost of one sheet of each form: multiply the sheet cost bysheet_totalfor the whole run.- The frame. The origin is the container's corner: a sheet's lower-left corner, or the roll's left edge where it
starts. Positions include the margins and the lead-in.
container_indexis the sheet (or, on a roll kept within beds, the bed).xandyare the lower-left corner of the placed part's bounding box. transformmaps the part's outline, in the coordinates you sent, onto the container:[a, b, c, d, e, f]with x' = a·x + c·y + e and y' = b·x + d·y + f, the order PDF uses.cutis the placed outline andoutlinethe same with bleed added.- N-up and strips. A
guillotinelayout's containers are forms: each is printedcopiestimes, andsheet_totaladds them up. Each form has a knife program incut_programs(steps with positions and back-gauge settings, andtotal_strokes). Astripslayout lists itsstripsandslits. - Splits and groups. Each layout lists
split_parts(the parts on more than one sheet or form) anddistribution: for each part id,[{"container", "per_sheet", "copies"}]. With ganging rules,groupsgives each container's group and itssignature([{"container": 0, "group": 0, "signature": {"coating": "Gloss UV"}}]), a roll layout lists itssegments([{"group", "start", "end"}]along the roll), and each container carries theinksunion of its parts ({"front": [...], "back": [...]}, ornull). Thesummaryaddssplit_partsandgroup_count. diagnosticshas the time the nest took, warnings, and other details that may change between versions.
Sync and queued jobs#
mode on nest/ chooses how the request runs:
auto(the default) answers200with the result when the request is within the sync limits and the server can run it now. Otherwise it queues a job and answers202.syncnever queues:413over the sync limits,429when a synchronous request can't start right now.asyncalways queues.
A queued job answers 202 with {"id", "status", "url"} and a Location header. Poll the URL every one or two
seconds until status is succeeded, failed or cancelled; while it runs, progress shows the time spent, the
layouts found and a summary of the best one. Sync nests are stored as jobs too, so the id of a sync result works with
the job endpoints. Jobs are deleted 7 days after they are created.
/a/{team_slug}/nesting/api/v1/jobs/
Queue a nest job (the request's `mode` is ignored).
nesting_jobs_create ·
View in API reference
/a/{team_slug}/nesting/api/v1/jobs/{id}/
Status, progress (`elapsed_s`, `layouts`, `best` summary) and, once finished, the `result`.
nesting_jobs_retrieve ·
View in API reference
/a/{team_slug}/nesting/api/v1/jobs/{id}/cancel/
Ask a queued or running job to stop; it ends `cancelled` (with its best layout so far, if any).
nesting_jobs_cancel ·
View in API reference
Cancelling a job that has already finished answers 409. A cancelled job keeps its best layout so far, if it had
one.
Candidates#
While a queued job runs, the layouts it finds are listed (up to options.stream_candidates, at most 20). Sheet and
roll jobs can publish distinct arrangements before the search ends. Extra search time does not guarantee more
layouts; simple jobs may have only one useful result. Poll
jobs/<id>/candidates/?cursor=<n> with the cursor of the previous answer (start at 0): it returns the rows changed
since then, has_more when you should poll again at once, and the job's status. Each row has its seq, status
(streamed, then verified or removed once the job ends), found_ms, score (lower is better), repeats (layouts
with the same figures) and a summary. Once the list is full, a better layout replaces the worst row (same seq, a
new cursor position), and the job's final layouts are always listed. jobs/<id>/candidates/<seq>/ returns the row's
layout. A layout larger than
5 MB is listed without it (layout_kept: false) and answers 410, as does a row removed by the final checks. The
final result is always the verified list.
/a/{team_slug}/nesting/api/v1/jobs/{id}/candidates/
Layouts an async job found while running (up to `options.stream_candidates`, at most 20), listed by cursor.
nesting_jobs_candidates ·
View in API reference
/a/{team_slug}/nesting/api/v1/jobs/{id}/candidates/{seq}/
One candidate's layout (the request's `include` applies).
nesting_jobs_candidate ·
View in API reference
Cut files#
/a/{team_slug}/nesting/api/v1/jobs/{id}/cutfile/
Cut file of a succeeded job's layout: one page per sheet, or the roll.
nesting_jobs_cutfile ·
View in API reference
Download a succeeded job's layout as format=pdf (the default), dxf or cff2, with layout as the layout's
index (0 is the best). You get one page per sheet, or one for the whole roll; pages=beds gives one PDF page per
bed for a roll kept within beds. Each part is cut with its cut_method.
curl -sS -H "Authorization: Api-Key $API_KEY" -OJ \
"https://app.example.com/a/acme/nesting/api/v1/jobs/00000000-0000-0000-0000-000000000000/cutfile/?format=pdf&pages=beds"
Errors and limits#
| Status | When |
|---|---|
400 |
{"errors": [{"path": "parts[3].outline", "message": "…"}]}: an invalid field, or input that can't be nested (such as a part wider than the roll without panelling; the path is then empty). |
413 |
The body is over 5 MB, or the request is over a limit of its mode: {"detail", "limit", "value", "maximum"}. |
410 |
A candidate's layout wasn't kept (too large) or failed the final checks. |
422 |
A sync nest found no valid layout: {"detail", "warnings"}. |
429 |
More than 60 nests started in a minute by the same user; a synchronous request that can't start right now; or the team already has as many queued or running jobs as it may. |
503 |
Nesting is unavailable. Try again later. |
Lengths and coordinates may be at most 100,000 inches (in any unit). The limits of each mode (more in Sizes and limits):
| Limit | Sync | Async | Error when exceeded |
|---|---|---|---|
| Time limit (s) | 10 | 120 | The time limit is above the maximum for this mode. |
| Pieces | 1,000 | 4,000 | Too many pieces (after quantities and panelling). |
| Distinct parts | 500 | 2,000 | Too many distinct parts. |
| Points per outline | 2,000 | 2,000 | An outline has too many points; simplify it. |
| Outline points in total | 200,000 | 200,000 | Too many outline points in total; simplify the outlines. |
| Outline points in the response | 400,000 | 1,000,000 | The response would carry too many outline points; ask for fewer layouts, simpler outlines or include=["transform"] only. |
| Raster grid cells | 50,000,000 | 50,000,000 | The container is too large for the raster grid. |
| Layouts per request | 5 | 5 | Too many layouts requested. |
| Queued or running jobs per team | – | 2 | More async jobs than this at once are refused until one finishes. |
/a/{team_slug}/nesting/api/v1/limits/
The effective limits (`sync`, `async`), free sync slots in this process and the team's active jobs.
nesting_limits ·
View in API reference
limits/ returns your team's limits, whether a synchronous nest can start now, and how many of the team's jobs are
queued or running. Validation errors are always 400, whatever the mode.
Every nesting endpoint#
| Method | Path | What it does |
|---|---|---|
| GET | /a/{team_slug}/nesting/api/v1/jobs/ | The team's jobs. |
| POST | /a/{team_slug}/nesting/api/v1/jobs/ | Queue a nest job (the request's `mode` is ignored). |
| GET | /a/{team_slug}/nesting/api/v1/jobs/{id}/ | Status, progress (`elapsed_s`, `layouts`, `best` summary) and, once finished, the `result`. |
| POST | /a/{team_slug}/nesting/api/v1/jobs/{id}/cancel/ | Ask a queued or running job to stop; it ends `cancelled` (with its best layout so far, if any). |
| GET | /a/{team_slug}/nesting/api/v1/jobs/{id}/candidates/ | Layouts an async job found while running (up to `options.stream_candidates`, at most 20), listed by cursor. |
| GET | /a/{team_slug}/nesting/api/v1/jobs/{id}/candidates/{seq}/ | One candidate's layout (the request's `include` applies). |
| GET | /a/{team_slug}/nesting/api/v1/jobs/{id}/cutfile/ | Cut file of a succeeded job's layout: one page per sheet, or the roll. |
| GET | /a/{team_slug}/nesting/api/v1/limits/ | The effective limits (`sync`, `async`), free sync slots in this process and the team's active jobs. |
| POST | /a/{team_slug}/nesting/api/v1/nest/ | Nest parts on a roll or on sheets. |