Recipes
End-to-end Python and Node.js examples for text-to-3D and multi-view photo-to-3D.
End-to-end snippets you can drop into a project. Both examples submit a job, poll until done, and return the mesh bytes.
Generate from text: Python
import requests, time, os
BASE = "https://api.suzanne3d.com"
KEY = os.environ["SUZANNE_API_KEY"]
def generate_from_text(prompt: str, faces: int = 100_000) -> bytes:
s = requests.Session()
s.headers["Authorization"] = f"Bearer {KEY}"
r = s.post(f"{BASE}/v1/generations/text-to-3d", json={
"model": "sculptor",
"prompt": prompt,
"params": {"faces": faces, "pbr": True},
"outputs": ["glb"],
})
r.raise_for_status()
job_id = r.json()["job_id"]
while True:
time.sleep(5)
job = s.get(f"{BASE}/v1/jobs/{job_id}").json()
if job["status"] == "done":
return s.get(job["outputs"][0]["download_url"]).content
if job["status"] in ("failed", "cancelled"):
raise RuntimeError(job.get("error") or "job did not complete")Generate from 4 photos: Node.js
import fs from "node:fs/promises";
const BASE = "https://api.suzanne3d.com";
const KEY = process.env.SUZANNE_API_KEY;
const auth = { Authorization: `Bearer ${KEY}` };
async function uploadView(path) {
const { upload_id, upload_url } = await fetch(`${BASE}/v1/uploads`, {
method: "POST", headers: auth,
}).then(r => r.json());
// Crucial: do NOT set Content-Type. The presigned URL is signed without it.
await fetch(upload_url, { method: "PUT", body: await fs.readFile(path) });
return upload_id;
}
export async function generateFrom4Views({ front, back, left, right }) {
const ids = {
front: await uploadView(front),
back: await uploadView(back),
left: await uploadView(left),
right: await uploadView(right),
};
const { job_id } = await fetch(`${BASE}/v1/generations/photo-to-3d`, {
method: "POST",
headers: { ...auth, "content-type": "application/json" },
body: JSON.stringify({
model: "sculptor",
images_upload_ids: ids,
params: { faces: 100000, pbr: true },
outputs: ["glb"],
}),
}).then(r => r.json());
while (true) {
await new Promise(r => setTimeout(r, 5000));
const job = await fetch(`${BASE}/v1/jobs/${job_id}`, { headers: auth }).then(r => r.json());
if (job.status === "done") {
const r = await fetch(job.outputs[0].download_url, { headers: auth, redirect: "follow" });
return new Uint8Array(await r.arrayBuffer());
}
if (["failed", "cancelled"].includes(job.status)) throw new Error(JSON.stringify(job.error));
}
}Want an LLM coding agent to wire this into your own stack? See Integrate with Claude Code.