Skip to content

Developer API ​

Generate and refine CAD designs from text and reference images in your own applications. The API runs in the background using the same agent, credit balance and export serializers as the app.

API keys and credits ​

Explore the API overview from the site's API navigation link. Open API settings through Get an API key, the documentation's API tab, or Avatar → Developer API inside the app.

Sign in, open your avatar menu and choose Developer API, or visit Developer settings. Name your integration and select Create API key. Copy the secret immediately: it is shown only once. Revoke keys on the same page: select Revoke, then confirm Revoke API key. Revocation blocks new requests; already accepted work can finish. A revoked key cannot be restored.

If you are signed out, the workspace offers Sign in with Google and returns you to /developer after authentication. The same prompt appears if a key-management request reports an expired session, even when the app still shows cached account data. Temporary loading failures offer Try again or Refresh keys.

The workspace includes a named-key form, creation/last-use dates, a one-time secret panel and copyable Create / Generate / Refine / Export examples. Set PROMPT2CAD_API_KEY, then set PROJECT_ID and GENERATION_ID from the earlier API responses before running the relevant examples. Creating keys and copying examples do not generate CAD or spend credits.

Store the secret on your server. Send Authorization: Bearer p2c_api_… on every request.

Base URL: https://prompt2cad.com/api/v1 · OpenAPI specification

The workspace shows the base URL for the current environment. Preview keys belong to preview, not production; private preview clients also need the preview access cookie. The preview password is an access gate, not a substitute for Google sign-in.

During beta rollout, generation_unavailable (503) means new server-side work is temporarily disabled. That response does not start a paid generation; existing usage and status reads remain available.

Generation and paid auxiliary tools use your existing credits, with the same trial allowance and model eligibility as the app. API CAD downloads are available during the trial without a top-up. When credits run out, top up in the app to generate more. Previously generated API artifacts remain downloadable until they expire. There is no extra customer credit charge for exporting or uploading reference images in this release. Web-app downloads retain their existing purchase requirements.

Workflow ​

  1. POST /projects with { "name": "Motor bracket" }.
  2. Optionally upload references using POST /files.
  3. POST /projects/{projectId}/generations with prompt and optional imageFileIds.
  4. Poll GET /projects/{projectId}/generations/{generationId} every 5 seconds.
  5. When completed, POST /projects/{projectId}/exports with generationId and formats.
  6. Poll GET /projects/{projectId}/exports/{exportId} and download completed artifacts using their downloadUrl and your API key.
  7. Refine by submitting another prompt to the same project. The agent retains its conversation and CAD model.

Projects are server-owned. Keep their IDs in your integration. This release supports API-created projects; it does not import existing web-app projects or provide an embedded editor.

Retries ​

Creating a project, submitting a generation, requesting an export and resuming a paused generation require an Idempotency-Key header: 1–128 letters, numbers, dots, underscores, colons or hyphens. Reuse the key when retrying the same operation. Keys are scoped to your account and endpoint; different input with the same key returns 409. Use a new key for a new refinement or export.

New generation/export requests return 202 Accepted; identical retries may return 200. Acceptance means work is queued, not that a valid model has already been produced.

Images ​

Upload raw JPEG, PNG or WebP bytes to POST /files with the matching Content-Type. The response contains id, mimeType and bytes. Include up to four uploaded IDs:

json
{
  "prompt": "Model this bracket. The base is 100 mm wide.",
  "imageFileIds": ["YOUR-UPLOADED-FILE-ID"],
  "unitSystem": "metric"
}

Limits: 20 MiB and 40 megapixels per upload; 200 MB of normalized reference storage per account. Images are normalized to JPEG with a longest side of 768 pixels, belong to the uploading account, and can be reused for refinement. Include dimensions in your prompt: a reference image alone does not establish accurate scale.

Autonomous and interactive generation ​

executionMode defaults to autonomous: clarification questions accept the agent’s suggested defaults and validated room plans are automatically approved. Selected defaults appear in the generation response’s assumptions array.

Set executionMode: "interactive" for explicit questions and room-plan approval. When status is awaiting_input, read questions and planReviews:

  • POST /projects/{projectId}/generations/{generationId}/answers with { "toolCallId": "…", "answers": [{ "id": "width", "value": 1.2 }] }. Answer every question in the pending call. Internal length values are meters.
  • POST /projects/{projectId}/generations/{generationId}/approval with { "toolCallId": "…", "approved": true }, or reject with approved: false and feedback.

Generation states: accepted, running, awaiting_input, paused, completed, failed, cancelled. usage exposes billed credits and tool-call count.

The existing segment limits apply: 30 tool calls, 5,000 billed credits or 30 minutes. An in-flight model request may settle beyond those thresholds. Autonomous mode does not authorize another segment automatically. Explicitly POST .../{generationId}/resume with a new idempotency key to continue. POST .../{generationId}/cancel requests a cooperative stop; already-running work may finish and its usage may be billed.

Exports ​

Formats: step, dxf, skp, glb, dae, obj, stl, 3mf, png. OBJ is a ZIP containing OBJ and MTL companions. PNG is a perspective viewport preview, not an AI-generated photorealistic render. Format limitations match the app’s exports.

json
{
  "generationId": "YOUR-COMPLETED-GENERATION-ID",
  "fileId": "main",
  "formats": ["step", "glb", "png"]
}

Use a completed generation and a file ID from its files array (main is the default). Exports capture that generation’s immutable model snapshot and revision; later refinements cannot change an export already requested. Check each artifact’s status: an export may complete with some formats failed. Maximum artifact size is 40 MB.

Artifacts expire 7 days after export creation (expiresAt is Unix milliseconds). Use a new idempotency key to request another export after expiry. DELETE /projects/{id} makes the project and its artifacts inaccessible and cleans up associated assets.

Limits and errors ​

Account-wide limits across all keys: 120 requests/minute, 10 image uploads/minute, 3 active generations, 3 active exports, one generation/project, 20 active keys. JSON bodies are limited to 200 KB.

Errors contain error.code, error.message, requestId. Responses include X-Request-ID; 429 includes Retry-After. Retry network errors and 503 using the same idempotency key. Resolve invalid input or conflicts before changing requests. Polling never creates a paid generation. GET /usage returns credits and limits. GET /projects/{id} returns the latest 20 lightweight summaries (ID, prompt, status, revision, timestamps and pause reason). Read a generation individually for usage, questions, files and output; older generation IDs remain readable individually.

JavaScript example ​

Node 22+, with PROMPT2CAD_API_KEY set. Set RUN_ID to reuse operation identities after restarting. A paused/failed operation stops the example instead of authorizing more expenditure automatically.

js
import { randomUUID } from "node:crypto";
import { writeFile } from "node:fs/promises";
const origin = "https://prompt2cad.com";
const run = process.env.RUN_ID || randomUUID();
const headers = { Authorization: `Bearer ${process.env.PROMPT2CAD_API_KEY}` };
async function api(path, body, operation) {
  const response = await fetch(`${origin}/api/v1${path}`, {
    method: body === undefined ? "GET" : "POST",
    headers: { ...headers, "Content-Type": "application/json",
      ...(operation ? { "Idempotency-Key": `${run}:${operation}` } : {}) },
    body: body === undefined ? undefined : JSON.stringify(body),
  });
  const result = await response.json();
  if (!response.ok) throw new Error(JSON.stringify(result));
  return result;
}
async function poll(path) {
  for (let i = 0; i < 420; i++) {
    const result = await api(path);
    if (result.status === "completed") return result;
    if (!["accepted", "running"].includes(result.status)) throw new Error(JSON.stringify(result));
    await new Promise(resolve => setTimeout(resolve, 5000));
  }
  throw new Error("Polling timed out; retain the operation ID and reconnect");
}
const project = await api("/projects", { name: "Bracket" }, "project");
const base = `/projects/${project.id}`;
const generation = await api(`${base}/generations`, {
  prompt: "Create an L bracket, 100 mm wide, with 6 mm walls and two mounting holes.",
}, "generate");
console.log({ run, projectId: project.id, generationId: generation.id });
await poll(`${base}/generations/${generation.id}`);
const exported = await api(`${base}/exports`, {
  generationId: generation.id, formats: ["step", "png"],
}, "export");
const result = await poll(`${base}/exports/${exported.id}`);
for (const artifact of result.artifacts) {
  if (artifact.status !== "completed") { console.error(artifact); continue; }
  const response = await fetch(`${origin}${artifact.downloadUrl}`, { headers });
  if (!response.ok) throw new Error(await response.text());
  await writeFile(artifact.filename, Buffer.from(await response.arrayBuffer()));
}

Python example ​

Python 3, using only its standard library:

python
import json, os, time, uuid
from pathlib import Path
from urllib.request import Request, urlopen
origin = "https://prompt2cad.com"
run = os.environ.get("RUN_ID", str(uuid.uuid4()))
headers = {"Authorization": "Bearer " + os.environ["PROMPT2CAD_API_KEY"]}
def api(path, body=None, operation=None):
    h = dict(headers, **{"Content-Type": "application/json"})
    if operation:
        h["Idempotency-Key"] = run + ":" + operation
    data = None if body is None else json.dumps(body).encode()
    with urlopen(Request(origin + "/api/v1" + path, data=data, headers=h), timeout=60) as response:
        return json.load(response)
def poll(path):
    for _ in range(420):
        result = api(path)
        if result["status"] == "completed":
            return result
        if result["status"] not in ("accepted", "running"):
            raise RuntimeError(result)
        time.sleep(5)
    raise TimeoutError("Retain the operation ID and reconnect")
project = api("/projects", {"name": "Bracket"}, "project")
base = "/projects/" + project["id"]
generation = api(base + "/generations", {
    "prompt": "Create an L bracket, 100 mm wide, with 6 mm walls and two mounting holes."
}, "generate")
print({"run": run, "projectId": project["id"], "generationId": generation["id"]})
poll(base + "/generations/" + generation["id"])
exported = api(base + "/exports", {"generationId": generation["id"], "formats": ["step", "png"]}, "export")
result = poll(base + "/exports/" + exported["id"])
for artifact in result["artifacts"]:
    if artifact["status"] != "completed":
        print(artifact)
        continue
    with urlopen(Request(origin + artifact["downloadUrl"], headers=headers), timeout=60) as response:
        Path(artifact["filename"]).write_bytes(response.read())

Next: SketchUp integration · Export formats

Docs for Prompt2CAD — derived from the source code at the commit that built them.