KittyCAD Python SDK: getting started
The KittyCAD Python SDK is how you talk to Zoo.dev's text-to-CAD API from code. Here's how to set it up and what to watch out for.
Quick answer
The KittyCAD Python SDK (pip install kittycad) provides typed Python bindings for Zoo.dev's CAD APIs including text-to-CAD generation, file conversion, and geometry operations. It handles authentication, async polling, and multi-format output (STEP, STL, glTF, OBJ).
I spent a Friday afternoon trying to generate a STEP file from a Python script instead of the Zoo.dev browser UI. Not because the browser is bad. Because I had fourteen bracket variants to generate, and clicking through the same text box fourteen times felt like punishment for a crime I hadn't committed. The KittyCAD Python SDK turned that into a for loop and a cup of coffee. Setting it up took longer than I expected, mostly because I missed one line in the docs and spent twenty minutes convinced the API was broken. It wasn't. I was.
This is the getting-started walkthrough I wished existed that Friday. How to install the SDK, authenticate, generate geometry, handle the async polling, and actually get a file on disk that you can open in Fusion 360 without cursing.
What the SDK is#
The KittyCAD Python SDK is the official Python client for Zoo.dev's API. Zoo, for those arriving fresh, is the company behind the text-to-CAD service that generates B-Rep geometry from text prompts. The browser UI at zoo.dev is the friendly version. The API is the version for people who want to script things, automate batches, or integrate text-to-CAD into a larger pipeline.
The SDK wraps Zoo's REST API in typed Python classes. You get methods for text-to-CAD generation, file format conversion, geometry operations, and account management. It handles authentication headers, request formatting, response parsing, and the async polling loop that's necessary because generating CAD geometry takes a few seconds and the API doesn't block.
If you've used any well-structured Python API client, the shape is familiar. If you haven't, it's still not complicated. It's just a library that talks to a server and gives you files back.
Installation#
pip install kittycadThat's it. The package is on PyPI. It pulls in httpx for HTTP requests and pydantic for data validation. Python 3.8 or newer.
I'd recommend installing it in a virtual environment because I recommend installing everything in a virtual environment, but I'm not going to lecture you about dependency management. You've heard the speech.
python -m venv venv
source venv/bin/activate
pip install kittycadOn Windows, replace source venv/bin/activate with venv\Scripts\activate. You know this. I'm writing it down because I once forgot it on a client's machine and pretended I was testing something.
Authentication#
You need a Zoo API token. Get one from zoo.dev/account/api-tokens. The free tier gives you a limited number of API calls per month, which is enough for development and testing. Paid tiers give you more, obviously.
Set the token as an environment variable:
export KITTYCAD_API_TOKEN="your-token-here"The SDK picks this up automatically. You can also pass it explicitly when creating the client, but the environment variable approach keeps your token out of your script, which is where it should be. I've seen tokens committed to public repos more times than I'd like. Don't be that person.
from kittycad.client import ClientFromEnv
client = ClientFromEnv()That's your authenticated client. If the environment variable isn't set, this throws an error that's clear enough to tell you what's wrong. If the token is invalid, you'll find out when you make your first API call, which is slightly less helpful but still obvious.
Generating a part from text#
Here's the core workflow. You send a text prompt to the text-to-CAD API and get geometry back.
from kittycad.api.ml import create_text_to_cad
from kittycad.models import (
FileExportFormat,
TextToCad,
ApiCallStatus,
)
from kittycad.client import ClientFromEnv
import time
client = ClientFromEnv()
result: TextToCad = create_text_to_cad.sync(
client=client,
output_format=FileExportFormat.STEP,
body="A rectangular mounting plate, 80mm by 50mm by 4mm, with four M4 clearance holes on a 60mm by 30mm bolt pattern centered on the plate",
)
while result.status in [ApiCallStatus.QUEUED, ApiCallStatus.IN_PROGRESS]:
time.sleep(2)
result = create_text_to_cad.sync(client=client, output_format=FileExportFormat.STEP, body=result.id)
if result.status == ApiCallStatus.COMPLETED:
for name, file_data in result.outputs.items():
with open(name, "wb") as f:
f.write(file_data.get_decoded())
print(f"Saved: {name}")
else:
print(f"Generation failed: {result.status}")A few things to notice.
The output_format parameter sets what you get back. FileExportFormat.STEP is what you want for engineering work. Other options include STL, OBJ, and GLTF. I almost always use STEP. The others are for visualization or 3D printing, and if you need the differences explained, the text-to-CAD file formats post covers that in detail.
The polling loop is necessary. Text-to-CAD generation isn't instant. The API accepts your request, queues it, processes it, and returns a result. That takes anywhere from a few seconds to maybe thirty seconds depending on complexity and server load. The SDK doesn't hide this from you, which I actually appreciate. Some SDKs wrap async operations in blocking calls that feel simple but make error handling a nightmare. Here you can see exactly what's happening and add your own timeout logic if you want.
The result.outputs dictionary contains the generated files. For STEP output, you'll typically get one file. The key is the filename, the value is the encoded file data. Call .get_decoded() to get the raw bytes, write them to disk, and you're done. That STEP file opens in Fusion 360, SolidWorks, FreeCAD, or any other CAD tool that reads STEP, which is all of them.
Async version#
If you're writing async Python, which you probably are if you're building anything web-facing or dealing with multiple concurrent requests, there's an async variant:
import asyncio
from kittycad.api.ml import create_text_to_cad
from kittycad.models import FileExportFormat, ApiCallStatus
from kittycad.client import ClientFromEnv
async def generate_part(prompt: str, filename: str):
client = ClientFromEnv()
result = await create_text_to_cad.asyncio(
client=client,
output_format=FileExportFormat.STEP,
body=prompt,
)
while result.status in [ApiCallStatus.QUEUED, ApiCallStatus.IN_PROGRESS]:
await asyncio.sleep(2)
result = await create_text_to_cad.asyncio(
client=client,
output_format=FileExportFormat.STEP,
body=result.id,
)
if result.status == ApiCallStatus.COMPLETED:
for name, file_data in result.outputs.items():
with open(filename, "wb") as f:
f.write(file_data.get_decoded())
asyncio.run(generate_part(
"L-bracket, 3mm thick, 40mm legs, two 5mm holes per leg",
"bracket.step"
))This is where the batch generation story gets good. You can fire off multiple generate_part calls concurrently with asyncio.gather() and let them all poll in parallel. My fourteen-bracket Friday became a lot more pleasant once I realized I could kick all fourteen off at once and go make lunch.
File conversion#
The SDK also handles file format conversion, which is useful when you have a STEP file and need an STL for printing, or an OBJ for a rendering pipeline. This is separate from the text-to-CAD generation. You're converting an existing file, not generating new geometry.
from kittycad.api.file import create_file_conversion
from kittycad.models import FileExportFormat, FileImportFormat
from kittycad.client import ClientFromEnv
client = ClientFromEnv()
with open("bracket.step", "rb") as f:
step_data = f.read()
result = create_file_conversion.sync(
client=client,
body=step_data,
src_format=FileImportFormat.STEP,
output_format=FileExportFormat.STL,
)The conversion runs server-side on Zoo's geometry kernel, which means the output is generally cleaner than what you'd get from a random online converter. Tessellation quality for STL output is controlled by the kernel defaults. For most prototyping and printing, the defaults are fine. For high-resolution visualization, you might want to check the triangle count.
What to watch out for#
A few things I learned the hard way so you don't have to.
The polling loop needs a timeout. The example above polls forever, which is fine for a script you're babysitting but irresponsible for production code. Add a counter or a wall-clock timeout. If the API hasn't returned a result in sixty seconds, something is wrong and you should bail out rather than spin indefinitely.
Prompt quality matters enormously. The SDK doesn't interpret your prompt. It passes it to the same model that powers the Zoo.dev browser UI. Vague prompts produce vague geometry. Specific dimensions, feature counts, and spatial relationships give you better results. This is true of all text-to-CAD tools, but it's easy to forget when you're writing prompts as string literals in a Python script instead of typing them into a chat interface.
Rate limits exist. The free tier has a monthly cap on API calls. If you're running batch generation in a loop during development, you can burn through your allocation fast. I did this on day two and had to wait until the next month. Check your account page for current limits.
Error responses are structured. When the API returns an error, the SDK gives you a typed error object with a message, not just an HTTP status code. Read the message. It's usually specific enough to tell you what went wrong. "Invalid API token" is clear. "Model generation failed" means the AI couldn't produce valid geometry for your prompt, which happens more often with complex or contradictory descriptions.
The generated STEP files need the same verification you'd apply to any text-to-CAD output. Dimensions drift. Holes end up slightly off. Features that should be symmetric aren't always symmetric. The SDK gives you the file. It doesn't guarantee the file is correct. Measure everything that matters before you send it anywhere. I've written about this in the accuracy post, and the advice hasn't changed.
Where this fits#
The KittyCAD Python SDK is the scripting layer for Zoo.dev's text-to-CAD service. If you're generating one part occasionally, the browser UI is easier. If you're generating many parts, integrating text-to-CAD into a pipeline, or building something that needs programmatic access to CAD generation, the SDK is how you do it.
The text-to-CAD API Python post covers the broader API story. The Zoo text-to-CAD API tutorial walks through a more complete project. The text-to-CAD API overview explains what's available beyond just generation.
For my own workflow, the SDK replaced about two hours of clicking per week with a script I run while doing other things. The bracket variants that started this whole adventure now generate overnight and wait in a folder for me to review in the morning. The coffee is better when you drink it instead of clicking through a browser for the fourteenth time.
Newsletter
Get new TexoCAD thoughts in your inbox
New articles, product updates, and practical ideas on Text-to-CAD, AI CAD, and CAD workflows.