OpenAPI spec and SDK
The public OpenAPI 3.1 document for the Windpaint API, what it covers and where it's incomplete, and the Python client preview.
OpenAPI spec
The API publishes an OpenAPI 3.1 document of every public endpoint:
https://api.windpaint.ai/v1/openapi.json
It needs no authentication and is cached for 5 minutes. Use it to generate a client, import the API into Postman or Insomnia, or point an API explorer at it.
curl -s https://api.windpaint.ai/v1/openapi.json | jq '.info, (.paths | keys | length)'
What’s in it:
- Servers:
https://api.windpaint.ai. - Security: one scheme,
apiKey, an HTTP bearer token applied to every operation:Authorization: Bearer aak_.... Public operations such asGET /v1/errorswork without it. - Tags: Generation, Workflows, Runs, Projects, API Keys, Webhooks and Billing.
- Operation ids:
<tag>_<action>, for examplegeneration_run_capability,generation_status,workflows_run_workflowandbilling_get_balance. Generated clients use them as method names. - Request bodies: complete, including every submit field.
- Status codes: submits and workflow run starts are
202;GET /v1/generation/assets/{id}/contentis200or302; uploads and otherPOSTendpoints, such as estimate, cancel and webhook test, are201.
Known gaps
- Most response bodies are untyped. They appear as an empty schema (
{}). Use the endpoint pages in this reference for response shapes. In short: submits return a bare{status, request_id, status_url, cancel_url, credits_estimate}, status returns the bare request status object, and most other endpoints wrap results in{"data": ...}(see Response envelopes). X-Windpaint-Projectisn’t declared as a parameter. It’s described in the spec’sinfo.description. Generation, workflow and run endpoints accept it; see Project scoping.- Uploads are described with one multipart part named
file. The server accepts any part name. - Headers such as
Idempotency-Key,Preferand theX-RateLimit-*response headers aren’t in the spec. See Idempotency, Synchronous mode and Rate limits.
Python client preview
The Python client is a preview. Its functions and return values may change before a packaged release.
The preview is one file, windpaint_client.py, that uses only the Python standard library and needs Python 3.10 or later. It isn’t on PyPI; you copy the file into your project. Ask support for the current version.
It reads its configuration from the environment; there’s no client object:
| Variable | Required | Meaning |
|---|---|---|
WINDPAINT_API_KEY | Yes | An aak_ API key. |
WINDPAINT_API_URL | No | Defaults to https://api.windpaint.ai. |
WINDPAINT_PROJECT | No | Project id or slug, sent as X-Windpaint-Project. |
import windpaint_client as wp
# Image by capability, wait for it, download the first output
req = wp.run("image.generate", prompt="a lighthouse at dusk", aspect_ratio="16:9")
done = wp.wait(req["request_id"])
wp.download(done["outputs"][0]["url"], "lighthouse.png")
# Upload a start frame and animate it
frame = wp.upload_file("lighthouse.png")
req = wp.run("video.generate", prompt="waves roll in, slow push-in", inputs={"start_frame": [frame]})
done = wp.wait(req["request_id"])
wp.download(done["video"]["url"], "lighthouse.mp4")
| Function | What it does |
|---|---|
capabilities(), models() | The catalog lists (the data array). |
estimate(capability, **args) | POST /v1/generation/estimate. Returns the whole data object, including credits. |
run(capability, **args) | Submit by capability. Returns status, request_id, status_url, cancel_url, credits_estimate. |
submit(model, **args) | Submit by model; image_urls fill the model’s primary input slot. Same return value. |
status(request_id), cancel(request_id) | Read or cancel a job. |
wait(request_id, timeout_s=1800, interval_s=2.0) | Polls with backoff up to 15 seconds. Returns the final status, raises RuntimeError if the job ends failed, nsfw or canceled, and TimeoutError after timeout_s. |
upload(data, content_type, filename), upload_file(path) | Upload a file. Returns the asset URL, which you can pass as an input. |
download(url, path) | Downloads an asset. It follows the redirect to the signed storage URL without sending your API key there. |
generate(model, out_path, **args) | submit, wait, then download the first output to out_path. |
Every keyword argument goes into the request body as is, so new fields such as num_outputs or preset work without a client update. HTTP errors raise WindpaintError, with .status and the raw .body.
The preview doesn’t send Idempotency-Key headers, retry failed requests, or use Prefer: wait or the event stream.