Skip to main content

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"
}'
FieldRequiredNotes
nameyesDisplay name for the part.
unitsyesmm or in.
stepFileyesThe STEP geometry. Raw STEP text by default; gzip-compressed then base64-encoded if stepFileCompression is set.
stepFileCompressionnoThe 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.
sourceFilenoOriginal 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"
}
}
First call creates a Project

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 after fast is 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). unitCost is totalCost divided by quantity; the quantity comes from your estimate preset, not from the request.
  • cycleTimeSeconds: machining cycle time (machine time plus tool changes). setupTimeSeconds appears in breakdown but is not included in cycleTimeSeconds.
  • 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's units. machineId is reserved and currently always null.