PartWorkAIAPI
Programmatic access to Text-to-CAD generation, file import/export, and part management.
All API requests require authentication via an API key. Include your key in the X-API-Key header:
X-API-Key: pk_live_your_api_key_here
API keys can be scoped with specific permissions:
| Permission | Description |
|---|---|
generate |
Create CAD models from text prompts |
export |
Export models to STEP, STL, 3MF, GLB formats |
import |
Upload CAD files (STEP, IGES, DXF, BREP, OBJ) |
parts:read |
List and retrieve conversations and parts |
Generate a CAD model with a single API call:
curl -X POST https://api.partwork.ai/v1/generate \
-H "X-API-Key: pk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Create a 2 inch cube with rounded edges",
"conversation_id": null
}'
Response:
{
"job_id": "job_abc123xyz",
"status": "pending",
"conversation_id": "conv_def456"
}
Poll for completion:
curl https://api.partwork.ai/v1/job/job_abc123xyz \
-H "X-API-Key: pk_live_your_api_key"
When complete:
{
"job_id": "job_abc123xyz",
"status": "completed",
"result": {
"model_url": "https://...",
"thumbnail_url": "https://...",
"part_id": "part_789"
}
}
Base URL: https://api.partwork.ai/v1
Generate a CAD model from a text prompt. Returns a job ID for polling.
null for new
{
"job_id": "job_abc123xyz",
"status": "pending",
"conversation_id": "conv_def456"
}
Get the status of a generation job. Poll until status is completed or failed.
{
"job_id": "job_abc123xyz",
"status": "pending",
"progress": 45
}
{
"job_id": "job_abc123xyz",
"status": "completed",
"result": {
"model_url": "https://...",
"thumbnail_url": "https://...",
"part_id": "part_789"
}
}
{
"job_id": "job_abc123xyz",
"status": "failed",
"error": "Could not generate model from prompt"
}
Export a part to STEP, STL, 3MF, or GLB format.
step, stl, 3mf, or glb
{
"download_url": "https://...",
"expires_at": "2025-01-15T12:00:00Z"
}
Get a presigned URL for uploading a CAD file. Supported formats: STEP, IGES, DXF, BREP, OBJ.
{
"upload_url": "https://s3.amazonaws.com/...",
"upload_id": "upload_xyz789",
"expires_at": "2025-01-15T12:00:00Z"
}
Process an uploaded CAD file after uploading to the presigned URL.
{
"job_id": "job_process123",
"status": "pending"
}
List your conversations (projects).
{
"conversations": [
{
"id": "conv_abc123",
"name": "Mounting Bracket",
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-01-15T14:22:00Z"
}
],
"next_cursor": "eyJsYXN0..."
}
Get details of a specific conversation including its parts.
{
"id": "conv_abc123",
"name": "Mounting Bracket",
"parts": [
{
"id": "part_xyz789",
"name": "Base Plate",
"model_url": "https://...",
"thumbnail_url": "https://..."
}
],
"created_at": "2025-01-15T10:30:00Z"
}
Get a presigned download URL for a file (STEP, STL, 3MF, GLB, or thumbnail). Use this to download generated models or exported files.
{
"download_url": "https://s3.amazonaws.com/...",
"expires_in": 3600
}
s3_key can be found in the job result (e.g., result.step_key) or extracted from file URLs. The presigned URL expires after 1 hour.
API requests are rate limited based on your tier. Limits reset at the start of each period.
| Tier | Requests/Min | Requests/Day | Generations/Month |
|---|---|---|---|
| Free | 60 | 1,000 | 100 |
| Standard | 120 | 10,000 | 1,000 |
| Pro | 300 | 50,000 | 5,000 |
Every response includes rate limit information:
| Header | Description |
|---|---|
X-RateLimit-Limit |
Maximum requests per minute for your tier |
X-RateLimit-Remaining |
Requests remaining in current window |
X-RateLimit-Reset |
Unix timestamp when the window resets |
429 Too Many Requests. Use the X-RateLimit-Reset header to know when to retry.
The API uses standard HTTP status codes and returns error details in the response body.
| Status | Description |
|---|---|
400 |
Bad Request - Invalid parameters or request body |
401 |
Unauthorized - Missing or invalid API key |
403 |
Forbidden - API key lacks required permission |
404 |
Not Found - Resource does not exist |
429 |
Too Many Requests - Rate limit exceeded |
500 |
Internal Server Error - Something went wrong |
{
"error": "Invalid API key",
"code": "invalid_api_key",
"details": null
}
| Code | Description |
|---|---|
invalid_api_key |
API key is missing, malformed, or revoked |
permission_denied |
API key lacks the required permission |
rate_limit_exceeded |
Too many requests - slow down |
generation_limit_exceeded |
Monthly generation quota reached |
invalid_prompt |
Prompt is empty or too long |
job_not_found |
Job ID does not exist or has expired |
import requests
import time
API_KEY = "pk_live_your_api_key"
BASE_URL = "https://api.partwork.ai/v1"
headers = {
"X-API-Key": API_KEY,
"Content-Type": "application/json"
}
# Generate a part
response = requests.post(
f"{BASE_URL}/generate",
headers=headers,
json={"prompt": "Create a 50mm diameter gear with 20 teeth"}
)
job = response.json()
print(f"Job started: {job['job_id']}")
# Poll for completion
while True:
status = requests.get(
f"{BASE_URL}/job/{job['job_id']}",
headers=headers
).json()
if status["status"] == "completed":
print(f"Model URL: {status['result']['model_url']}")
break
elif status["status"] == "failed":
print(f"Error: {status['error']}")
break
time.sleep(2)
# Download STEP file (if step_key is in result)
if "step_key" in status["result"]:
download = requests.post(
f"{BASE_URL}/download",
headers=headers,
json={"s3_key": status["result"]["step_key"]}
).json()
print(f"STEP download: {download['download_url']}")
# Or export to a different format
export = requests.post(
f"{BASE_URL}/export",
headers=headers,
json={
"part_id": status["result"]["part_id"],
"format": "stl"
}
).json()
print(f"STL download: {export['download_url']}")
const API_KEY = 'pk_live_your_api_key';
const BASE_URL = 'https://api.partwork.ai/v1';
const headers = {
'X-API-Key': API_KEY,
'Content-Type': 'application/json'
};
async function generatePart(prompt) {
// Start generation
const response = await fetch(`${BASE_URL}/generate`, {
method: 'POST',
headers,
body: JSON.stringify({ prompt })
});
const job = await response.json();
console.log(`Job started: ${job.job_id}`);
// Poll for completion
while (true) {
const statusRes = await fetch(`${BASE_URL}/job/${job.job_id}`, { headers });
const status = await statusRes.json();
if (status.status === 'completed') {
return status.result;
} else if (status.status === 'failed') {
throw new Error(status.error);
}
await new Promise(r => setTimeout(r, 2000));
}
}
// Usage
generatePart('Create a 2 inch cube with rounded edges')
.then(result => console.log('Model URL:', result.model_url))
.catch(err => console.error('Error:', err));
# Generate a part
curl -X POST https://api.partwork.ai/v1/generate \
-H "X-API-Key: pk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{"prompt": "Create a mounting bracket with 4 holes"}'
# Check job status
curl https://api.partwork.ai/v1/job/job_abc123 \
-H "X-API-Key: pk_live_your_api_key"
# Download a STEP file (using s3_key from job result)
curl -X POST https://api.partwork.ai/v1/download \
-H "X-API-Key: pk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{"s3_key": "parts/abc123/model.step"}'
# Export to STL
curl -X POST https://api.partwork.ai/v1/export \
-H "X-API-Key: pk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{"part_id": "part_xyz789", "format": "stl"}'
# List conversations
curl https://api.partwork.ai/v1/conversations \
-H "X-API-Key: pk_live_your_api_key"