Overview
MeshPilot turns a text prompt or an image into a production-ready 3D model (a .glb with PBR materials) - and then keeps working on it: iterate on a model conversationally, auto-rig it for animation, or plan a whole set of matching parts. It is built for AI agents end to end.
Two ways in. Pay per call: an unpaid request returns a 402 with the price and your agent pays it in USDC on Solana via x402, straight from its own wallet. Or link an agent through the dashboard’s connect flow (no keys pasted anywhere) and fund it with a card. Every generation runs through Model Safeguard automatically.
Everything below is also machine-readable: GET /api/generate returns a self-describing guide with the live price, so an agent can learn the whole API from one request.
Quickstart
See the price first - an unpaid call returns a 402 with the exact payment terms:
curl -i -X POST https://meshpilot.cc/api/generate \
-H "Content-Type: application/json" \
-d '{"prompt":"a low-poly oak tree","texture":true}'
# HTTP/1.1 402 Payment Required
# { "x402Version": 1, "accepts": [{
# "network": "solana:5eykt4Us…",
# "maxAmountRequired": "200000", // $0.20 (6 decimals)
# "asset": "EPjFWdd5…TDt1v", // USDC mint
# "payTo": "…", "extra": { "feePayer": "…" }
# }]}Pay it in a few lines - build the partially-signed USDC transfer and resend:
import {
createSolanaPaymentPayload, solanaKeyToBytes, solanaPublicKey,
parsePaymentRequired, extractPaymentDetails,
} from "@blockrun/llm";
const r1 = await fetch(URL, { method: "POST", body }); // -> 402
const d = extractPaymentDetails(
parsePaymentRequired(r1.headers.get("x-payment-required")), "solana");
const header = await createSolanaPaymentPayload(
await solanaKeyToBytes(KEY), await solanaPublicKey(KEY),
d.recipient, d.amount, d.extra.feePayer);
const res = await fetch(URL, { method: "POST", body,
headers: { "X-Payment": header } }); // -> model
const { model_url, safeguard } = await res.json();Request & response
POST /api/generate with a JSON body - every knob is optional except one input:
{
"prompt": "a low-poly oak tree", // text (or use "image" / "images")
"image": "https://… | data:…", // model THIS image directly
"images": ["https://…"], // reference images to guide the look
"texture": true, // default true - PBR materials
"detail": "high", // "low" | "medium" | "high" preset
"faces": 250000, // exact triangles, 1k-1M (overrides detail)
"texture_size": 2048, // 1024 | 2048 | 4096 PBR texture res
"license": "CC-BY-4.0", // stamped into the GLB's metadata
"plan": true, // default true - the brain refines vague prompts
"async": false // see Async jobs
}On success:
{
"model_url": "https://meshpilot.cc/api/model?file=…",
"format": "glb",
"textured": true,
"detail": "high",
"faces": 243230, // triangles actually used
"safeguard": { "reference_vetted": true, "floaters_removed": 2 },
"license": "CC-BY-4.0", // what you stamped (or null)
"model_license": "…", // the generator's own terms
"model_id": "…", // use with /api/rig
"ref": "https://…", // pass back to iterate (see below)
"api": { "version": "…", "whats_new": [ "…" ], "all_commands": "…" }
}The api block appears on every successful response: the current API version, the latest changes, and where the full command surface lives - so your agent stays current automatically just by using the API.
model_url is valid for 48 hours - download the file promptly (and re-generate if you need it again later). Generated models are delivery artifacts, not an archive.
All commands
Everything the API does, as copy-paste calls. Each is paid per call (or free where noted).
# discover everything (free) - live prices, every knob, examples
curl https://meshpilot.cc/api/generate
# text -> textured 3D model ($0.20; default: 250k tris, 2048px textures)
POST /api/generate { "prompt": "a brass compass" }
# image -> 3D model
POST /api/generate { "image": "https://…/photo.jpg" }
# match an existing art style: prompt = the subject, images = the LOOK
# (palette, materials, shading, detail are matched from the reference)
POST /api/generate { "prompt": "a health potion",
"images": ["https://…/your-game-screenshot.png"] }
# or steer the look with text only
POST /api/generate { "prompt": "a treasure chest",
"style": "low-poly PS1, flat shaded, limited palette" }
# dial EVERYTHING: exact triangles, texture res, license stamp
POST /api/generate { "prompt": "…", "faces": 500000,
"texture_size": 4096, "license": "CC-BY-4.0" }
# fast low-poly untextured ($0.10)
POST /api/generate { "prompt": "…", "texture": false, "detail": "low" }
# long generation without timeouts -> poll a job
POST /api/generate { "prompt": "…", "async": true }
GET /api/job/<job_id>
# iterate on the last model like a chat
POST /api/generate { "edit": "make it rusty", "from_ref": "<ref>" }
# plan a whole SET of matching parts (free planning call)
POST /api/plan { "prompt": "a robot", "mode": "set" }
# auto-rig any generated model for animation ($0.10)
POST /api/rig { "model_id": "<from generate>" }
# split a model into named parts ($0.10, open-vocabulary); each part
# returns attachments = where it touches its neighbours, so an
# avatar editor can snap a swapped part into place
POST /api/segment { "model_id": "<from generate>", "queries": ["head","torso","arm","leg"] }
# raw prompt, skip the planning brain
POST /api/generate { "prompt": "…", "plan": false }Async jobs
High-detail textured generations can take minutes; pass "async": true and the call returns in seconds with a job to poll. Payment is settled on submission.
// POST /api/generate { …, "async": true }
{ "job_id": "…", "status": "processing",
"poll_url": "https://meshpilot.cc/api/job/…" }
// GET poll_url every ~10s:
{ "status": "processing" } // keep polling
{ "status": "done", "model_url": "…",
"safeguard": { … }, "faces": 243230, "ref": "…" }Iterate
Every response includes a ref. Send it back as from_ref with an edit instruction to keep refining the same model - your agent just holds one string between turns; there is no session.
// "make it green", "add gold trim", "more weathered", …
POST /api/generate
{ "edit": "make it green", "from_ref": "<ref from the last response>" }Sets (/api/plan)
Building a kit - a robot with swappable heads, arms, legs? POST /api/plan decomposes the request into individual parts that share one style, then you generate each part as its own model:
POST /api/plan { "prompt": "a robot", "mode": "set" }
// -> { "style": "sleek matte white hard-surface …",
// "parts": [ { "name": "Head", "prompt": "Robot head, …" },
// { "name": "Torso", "prompt": "Robot torso, …" }, … ],
// "detail": "high", "texture": true }
// then loop: POST /api/generate { "prompt": part.prompt, … } per partWithout "mode": "set", /api/plan refines a single prompt into a clean generator spec.
Rigging (/api/rig)
Turn any generated model into an animatable one - a skeleton plus skinning weights, returned as a compressed, game-ready GLB:
POST /api/rig { "model_id": "<from generate>" }
// -> { "model_url": "…", "model_id": "…", "format": "glb", "rigged": true }Model Safeguard
Every AI model makes mistakes - ours included. In image-to-3D the failures are predictable: stray fragments, phantom props, shadow debris. So every generation is quality-controlled automatically: a vision model inspects the reference image before any GPU time is spent (a dirty reference is regenerated), and the finished mesh is swept for disconnected floating geometry, preserving the full PBR material. The response reports what happened in the safeguard field. No flags - always on.
Payment (x402)
Payments are USDC on Solana. Your agent sends a partially-signed TransferCheckedbuilt from the 402’s requirements - MeshPilot is the fee payer (shown in extra.feePayer), so the agent needs no SOL, only USDC. The payment settles immediately on acceptance and is automatically refundedif generation then fails, so your agent is never charged for a model it didn’t get. The receipt (the transaction signature) comes back in the X-PAYMENT-RESPONSE header.
Errors
402 payment required / invalid - body repeats "accepts" with the payment terms
400 bad request - missing prompt/image, or malformed JSON
502 generation failed - on Solana the payment is auto-refunded:
{ "error": "generation failed: …", "refunded": true, "refund_tx": "…" }
503 a capability (e.g. rigging) is temporarily unavailableFAQ
How long does a model take? Untextured ~1 minute. Textured high-detail can take a few minutes - use async and poll.
Do I need an account? Only if you want one. A funded wallet is enough for the x402 path; accounts exist for card funding and linked agents via the dashboard.
How long do models stay downloadable? 48 hours from generation - grab the file right away. Your agent already has it the moment the call returns.
What formats? GLB (geometry + PBR textures in one file). It drops into Unity, Unreal, Blender, Godot, Three.js, and slicers.
Who owns the output? You do, within the generator’s terms - the response discloses them in model_license, and your own license is stamped into the file.
Can I dial quality? Yes - faces sets the exact triangle budget (1k-100k) and texture: false skips materials for a cheaper, faster mesh.
