API reference
POST a STEP part, get back a cut-ready flat pattern — the same engine the app runs. One authenticated request returns the geometry and bend schedule, and optionally the DXF (or dimensioned PDF / bend-table CSV). The API is included on the Starter plan and above.
Every request carries an API key. Create one in the app under
Plans & credits → API keys; the full secret
(blk_…) is shown once at creation — store it somewhere safe, because it can't be
retrieved again. Revoke a key any time from the same panel.
Send the key as a bearer token (or the X-API-Key header):
Authorization: Bearer blk_your_key_here
POST{your-api-base}/api-unfold
The request is multipart/form-data (a file plus a few fields). The exact base URL
for your account is shown in the app's API-keys panel.
| Field | Type | Required | Description |
|---|---|---|---|
step | file | yes | The STEP/STP part to unfold. |
thickness_mm | number | yes | Material thickness in millimetres (> 0). |
k_factor | number | yes | Neutral-axis K-factor, between 0 and 1. |
download | string | no | Omit for a free unfold (geometry only). Set to dxf, pdf, or csv to also return that file — this spends one download unit. |
base_face | JSON string | no | Override the base face, as a geometric locator: {"centroid":[x,y,z],"normal":[x,y,z]}. Falls back to the largest planar face with a warning. |
Unfolding is always free — a request without download returns the flat geometry,
bend schedule, and any warnings, and costs nothing. You only spend a unit when you ask for a
file. One download = one unit (allowance first, then a credit), whatever the format —
exactly like the app. A failed unfold never costs anything.
| download | Returns a file? | Cost | Plan needed |
|---|---|---|---|
| (omitted) | No — geometry only | Free | Starter+ |
dxf | DXF (CUT + BEND layers) | 1 unit | Starter+ |
pdf | Dimensioned PDF drawing | 1 unit | Starter+ |
csv | Press-brake bend-table CSV | 1 unit | Pro+ |
A 200 is always JSON. The file, when requested, arrives base64-encoded inside it:
{
"unfold_id": "…",
"status": "done",
"flat_geometry": { "outline": [...], "holes": [...], "bend_lines": [...] },
"bend_metadata": { "bends": [ { "angle_deg": 90, "direction": "up", "radius_mm": 1.5, "length_mm": 120 } ] },
"warnings": [],
"diagnostics": { "unfolder": "v2", "defeatured": false },
"charged": "allowance",
"file": {
"format": "dxf",
"filename": "bracket.dxf",
"content_type": "application/dxf",
"base64": "MAo…"
}
}
file and charged appear only when you request a download.
bend_metadata is present for parts the V2 unfolder recovered bends from.
60 requests per minute per key. Over that returns 429; retry after the next minute.
Errors are JSON with an error code and a human message.
| Status | error | Meaning |
|---|---|---|
| 400 | step_required / thickness_required / k_factor_required | Missing or invalid input. |
| 401 | invalid_api_key | Missing, unknown, or revoked key. |
| 402 | no_downloads | Out of allowance and credits. The geometry is still returned; no file. |
| 403 | plan_required | Your plan doesn't include the API, or that download format. |
| 410 | unfold_expired | The unfold expired before the file could be fetched. Not charged. |
| 422 | cannot_unfold | The part couldn't be unfolded (not sheet metal, thickness mismatch, …). Not charged. |
| 429 | rate_limited | Over 60 requests/minute. |
| 503 | unfold_unavailable | The engine is temporarily unavailable. Not charged — retry. |
curl -X POST "$BENDLINE_API/api-unfold" \
-H "Authorization: Bearer $BENDLINE_KEY" \
-F step=@bracket.step \
-F thickness_mm=2 \
-F k_factor=0.38
curl -sX POST "$BENDLINE_API/api-unfold" \
-H "Authorization: Bearer $BENDLINE_KEY" \
-F step=@bracket.step -F thickness_mm=2 -F k_factor=0.38 \
-F download=dxf \
| jq -r '.file.base64' | base64 -d > bracket.dxf
import base64, requests
r = requests.post(
f"{BENDLINE_API}/api-unfold",
headers={"Authorization": f"Bearer {BENDLINE_KEY}"},
files={"step": open("bracket.step", "rb")},
data={"thickness_mm": 2, "k_factor": 0.38, "download": "dxf"},
)
r.raise_for_status()
body = r.json()
print(body["warnings"], body["charged"])
with open("bracket.dxf", "wb") as f:
f.write(base64.b64decode(body["file"]["base64"]))