Walkthrough: estimate a part
This end-to-end guide ties the individual endpoints together into a realistic flow: upload a part, run a program against it, and read back a cost-and-time estimate.
Overview
POST /parts → create a part from a STEP file (async)
GET /parts/{id} → poll until status: ready
POST /programs → create a program for the ready part (async)
GET /programs/{id} → poll until status: ready
GET /programs/{id}/estimate → read cost & time
Every create call is asynchronous: the Engine processes the work in the
background, so you submit the request, then poll the corresponding GET
endpoint until status transitions from processing to ready (or failed).
The conventions are uniform across endpoints: every success response wraps its
payload in a top-level data object, and polls return 202 while the Engine
is still working and 200 once the resource is ready or failed. All money
values are integers in USD cents; all durations are integers in
seconds.
1. Create a part
Send a STEP file in the JSON body. Compressing it with gzip and encoding it as
base64 is recommended, since the request body is capped at 25 MB. Writes
require an Idempotency-Key so retries are safe.
curl -X POST https://app.toolpath.com/api/public/v0/parts \
-H "Authorization: Bearer tp_live_xxxxxxxxxxxx" \
-H "Idempotency-Key: 5f3c9b2a-1d4e-4f8a-9c2b-7e1a3b6d8c40" \
-H "Content-Type: application/json" \
-d '{
"name": "bracket",
"units": "mm",
"stepFile": "H4sIAAAAAAAA…",
"stepFileCompression": "gzip+base64"
}'
| Field | Required | Notes |
|---|---|---|
name | yes | Display name for the part. |
units | yes | mm or in. |
stepFile | yes | The STEP geometry. Raw STEP text by default; gzip-compressed then base64-encoded if stepFileCompression is set. |
stepFileCompression | no | The only supported value is gzip+base64. When set, stepFile is decoded and decompressed; when omitted, stepFile is taken as raw STEP text. Compressing is recommended to stay under the body size limit. |
sourceFile | no | Original filename, for your own reference. |
You get back 202 Accepted with the new part and a Location header pointing
at the poll URL:
{
"data": {
"id": "abcd1234",
"status": "processing",
"name": "bracket",
"units": "mm",
"createdAt": "2026-06-10T17:00:00.000Z"
}
}
2. Poll the part until it's ready
curl https://app.toolpath.com/api/public/v0/parts/abcd1234 \
-H "Authorization: Bearer tp_live_xxxxxxxxxxxx"
Returns 202 while the Engine is still detecting features and 200 once the
part is ready (or failed). Poll with backoff (see
Rate limits) until you see:
{
"data": {
"id": "abcd1234",
"status": "ready",
"name": "bracket",
"units": "mm",
"createdAt": "2026-06-10T17:00:00.000Z"
}
}
3. Create a program
Once the part is ready, create a program for it. The program uses the API
key creator's default cut config and its linked tool libraries.
curl -X POST https://app.toolpath.com/api/public/v0/programs \
-H "Authorization: Bearer tp_live_xxxxxxxxxxxx" \
-H "Idempotency-Key: 9b1c7e2a-3f6d-4a91-8c0b-2d5e8f1a4c93" \
-H "Content-Type: application/json" \
-d '{ "partId": "abcd1234" }'
If the part's feature detection hasn't finished yet, this returns
409 Conflict; wait for step 2 to report ready first. On success you get
202 Accepted with the new program:
{
"data": {
"id": "efgh5678",
"status": "processing",
"partId": "abcd1234",
"setups": [],
"createdAt": "2026-06-10T17:05:00.000Z",
"updatedAt": "2026-06-10T17:05:00.000Z"
}
}
The first program for a part auto-creates a Project named
API: <part-name> (<timestamp>), where the timestamp is the part's creation
time, so the part shows up in the Toolpath web UI. Subsequent calls for the
same part reuse that Project.
4. Poll the program until it's ready
curl https://app.toolpath.com/api/public/v0/programs/efgh5678 \
-H "Authorization: Bearer tp_live_xxxxxxxxxxxx"
Just like the part poll, this returns 202 while the Engine is still working
and 200 once the program is ready (or failed). Poll with backoff until
you see 200; the setups array is populated once strategy finishes:
{
"data": {
"id": "efgh5678",
"status": "ready",
"partId": "abcd1234",
"setups": [
{
"id": "ijkl9012",
"position": 1,
"isMultiAxis": false,
"machiningTimeSeconds": 420,
"features": [
{ "type": "through_hole", "label": "hole 1" }
],
"tools": [
{
"id": "mnop3456",
"toolNumber": 1,
"name": "Carbide 1/4 Endmill",
"type": "flat_endmill",
"diameter": 0.25,
"unit": "in"
}
]
}
],
"createdAt": "2026-06-10T17:05:00.000Z",
"updatedAt": "2026-06-10T17:06:30.000Z"
}
}
5. Request the estimate
curl "https://app.toolpath.com/api/public/v0/programs/efgh5678/estimate?timings=fast" \
-H "Authorization: Bearer tp_live_xxxxxxxxxxxx"
The timings query param selects the estimate variant:
fast(default): heuristic estimate, available as soon as the program is ready.refined: simulation-based estimate; may still be computing afterfastis ready.
While the Engine is still computing, this endpoint returns 202 with a
processing envelope carrying an ETA instead of the estimate; once the
estimate is ready it returns 200 with the estimate in data (see step 6).
A 422 means the Engine reported an error for this program.
{
"data": {
"programId": "efgh5678",
"status": "processing",
"etaSeconds": 30
}
}
Poll with backoff until you get a 200 back.
6. Read the result
A ready estimate comes back with 200, wrapped in data like every other
response. Costs are integer USD cents; times are integer seconds.
{
"data": {
"programId": "efgh5678",
"status": "ready",
"currency": "USD",
"timings": "fast",
"totalCost": 4250,
"subtotalCost": 4250,
"discountCost": 0,
"quantity": 1,
"unitCost": 4250,
"cycleTimeSeconds": 480,
"breakdown": {
"machineTimeSeconds": 420,
"toolChangeSeconds": 60,
"setupTimeSeconds": 60
},
"costBreakdown": {
"machiningCost": 3000,
"setupCost": 750,
"materialCost": 400,
"otherCost": 100
},
"assumptions": {
"material": "6061 Aluminum",
"stock": [3.94, 3.15, 0.98],
"machineId": null
}
}
}
Key fields:
totalCost/unitCost: price in cents (4250= $42.50).unitCostistotalCostdivided byquantity; the quantity comes from your estimate preset, not from the request.cycleTimeSeconds: machining cycle time (machine time plus tool changes).setupTimeSecondsappears inbreakdownbut is not included incycleTimeSeconds.costBreakdown: where the cost comes from (machining, setup, material, other).assumptions: the material and stock dimensions[x, y, z]the estimate was computed against. Stock dimensions are always in inches in v0, regardless of the part'sunits.machineIdis reserved and currently alwaysnull.