Skip to main content
Use the Python client to submit a run (one task you send to Millwork; the API calls it an execution), follow its progress, and read its receipt. It includes a synchronous Solver and an asynchronous AsyncSolver. Both use the same requests and organization API key as the REST API.

Install

Requires CPython 3.11 to 3.14 and an organization API key.
The package is millwork-solver on PyPI. Import it as millwork_solver.

Make a test run

Use your organization API key and https://api.getmillwork.dev/v1. API basics explains authentication. This example submits a test run and reads its receipt without calling a model. Solver() reads SOLVERAPI_API_KEY and SOLVERAPI_BASE_URL from the environment. You can also pass them as api_key and base_url.
AsyncSolver has the same calls: await client.request(...), async for over pages and events, and async with or aclose() to close.

What the client does

Both clients expose one request call: name the REST operation by its operation ID from the API reference and pass path parameters, query values, and a body. pages walks a list one page at a time; events follows a run’s events until a final status. A test run (the API calls it Echo, mode: "echo") reaches a final status and returns a receipt. It calls no model, so it has no result content and no platform fee, and reading its result is not part of the test-run flow. You own the request key. Pass it as idempotency_key when you submit a run and the client sends it as the Idempotency-Key header. The client never makes one up for you, and a submit without one is sent once. A read (GET or HEAD) that hits a network failure or a 5xx response is retried, up to two times by default, with a doubling wait that starts at 500 milliseconds. A write with a request key is retried the same way. A write without a request key is never retried by the client. A 429 is not retried either; read retry_after_seconds and wait. Change the defaults with max_retries and retry_backoff_ms on the constructor, or with SOLVERAPI_MAX_RETRIES and SOLVERAPI_RETRY_BACKOFF_MS in the environment.

Errors

Every exception is importable from millwork_solver. An empty list is a normal answer, not an error. For what each error code means and which are safe to retry, read Errors and retries.

API basics

Authentication, request keys, and the response shapes the client returns.

Make your first API call

Send a free test run with curl and read its receipt.