API reference

Turn your own code into textured 3D models. JSON over HTTPS, authenticated with a single header.

Base URL: https://polyvia-ai.com/api/v1. Generations run asynchronously: create one, then poll it or stream its progress until it lands on a terminal status.

Authentication

Generate a key in Settings → API keys. Keys have the form pv_live_… and you'll see each one only once — we keep just a hash. Pass it in the X-API-Key header with every request. Revoked keys, and keys belonging to suspended accounts, are refused.

Get your API key

Check your key
curl https://polyvia-ai.com/api/v1/me \
  -H "X-API-Key: $POLYVIA_API_KEY"

Create a generation

POST/api/v1/generations

Reserves the quoted credits right away and queues the job. On success you pay only what the generation actually used (never above the quote; any difference is returned automatically); if it fails, you get everything back. Pricing: text 9 (untextured) / 17 (textured); image 25; low-poly 34; +8 for HD (4K) textures, +17 for 8K textures, +17 for ULTRA geometry, +5 for the T-pose pre-step, +5 for each additional export format.

FieldTypeDescription
type"text" | "image"Required.
promptstringNeeded for text. Between 3 and 1024 characters.
image_urlstring (URL)Needed for image. A public http(s) link to a JPEG, PNG or WebP of at most 10 MB. We download it ourselves; if that fails, the generation fails and is refunded.
options.model"STANDARD" | "LOWPOLY" | "LOWPOLY_PRO"STANDARD by default. LOWPOLY = low poly ready for games, LOWPOLY_PRO = low poly that supports quads (preview).
options.quality"FAST" | "STANDARD" | "ULTRA"STANDARD by default. ULTRA = finely detailed geometry (STANDARD model only); FAST = quicker texturing.
options.texture"NONE" | "STANDARD" | "PBR"Default STANDARD.
options.texture_quality"STANDARD" | "HD" | "EXTREME"STANDARD by default. HD = 4K maps, EXTREME = 8K maps. Has no effect when texture is NONE.
options.texture_4kbooleanLegacy alias for texture_quality HD; deprecated.
options.polycountintegerDesired triangle count, 500–2,000,000 (over 1,500,000 requires ULTRA; low-poly models have a lower cap). Leave out for adaptive.
options.quadbooleanfalse by default. Quad topology; you receive the model as FBX.
options.smart_low_polybooleanfalse by default. Low poly with a hand-modelled look (STANDARD model), max 20,000 faces.
options.seedintegerOptional. Reusing a seed with identical input reproduces the same mesh.
options.formatsarrayChoose any of GLB FBX OBJ USDZ STL. Defaults to ["GLB"].
options.negative_promptstringText generations only, max 255 characters.
options.t_posebooleanImage generations only. false by default. Puts the subject into a T-pose before modelling (useful for rigging).
options.remove_backgroundbooleanStill accepted for compatibility, but has no effect: the subject is always isolated for you.
options.parent_asset_idstringRemix source: any asset you own, or any public one.
Text to 3D
curl -X POST https://polyvia-ai.com/api/v1/generations \
  -H "X-API-Key: $POLYVIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "text",
    "prompt": "a weathered bronze viking helmet with horns",
    "options": { "texture": "PBR", "formats": ["GLB", "USDZ"] }
  }'
Image to 3D
curl -X POST https://polyvia-ai.com/api/v1/generations \
  -H "X-API-Key: $POLYVIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "type": "image", "image_url": "https://example.com/chair.png" }'
202 Accepted
{ "id": "cmf0x8k2p0001l50g7h3d9q2a", "status": "QUEUED", "credits_charged": 15, "credits_remaining": 485 }

Get a generation

GET/api/v1/generations/:id

status takes one of QUEUED RUNNING SUCCEEDED FAILED CANCELED. type takes one of text image multiview texture retopology rig animate convert (studio steps are listed here as well). Once it is SUCCEEDED, files contains signed download URLs that last one hour — fetch the generation again to get new ones.

Request
curl https://polyvia-ai.com/api/v1/generations/cmf0x8k2p0001l50g7h3d9q2a \
  -H "X-API-Key: $POLYVIA_API_KEY"
200 OK
{
  "id": "cmf0x8k2p0001l50g7h3d9q2a",
  "type": "text",
  "status": "SUCCEEDED",
  "progress": 100,
  "error": null,
  "credits_charged": 15,
  "created_at": "2026-09-21T10:00:00.000Z",
  "started_at": "2026-09-21T10:00:01.000Z",
  "finished_at": "2026-09-21T10:01:32.000Z",
  "asset": { "id": "…", "slug": "a-weathered-bronze-viking-helmet-9q2a0b1c", "title": "A weathered bronze viking helmet with horns", "thumbnail_url": "https://…" },
  "files": [
    { "format": "GLB", "bytes": 4812201, "url": "https://…", "expires_at": "2026-09-21T11:05:00.000Z" }
  ]
}

Stream progress (SSE)

GET/api/v1/generations/:id/stream

Returns a text/event-stream. You get the current state straight away, then each change as it happens. Every event is one data: line carrying JSON; lines beginning with : are heartbeats, sent every 15 seconds. We close the stream once a terminal status is reached. Each stream you open uses one request of your rate limit.

Request
curl -N https://polyvia-ai.com/api/v1/generations/cmf0x8k2p0001l50g7h3d9q2a/stream \
  -H "X-API-Key: $POLYVIA_API_KEY"
Events
data: {"jobId":"cmf0x8k2p0001l50g7h3d9q2a","status":"RUNNING","progress":42,"assetId":null,"error":null}

: ping

data: {"jobId":"cmf0x8k2p0001l50g7h3d9q2a","status":"SUCCEEDED","progress":100,"assetId":"cmf0x9…"}
FieldTypeDescription
jobIdstringThe generation id.
statusstringQUEUED | RUNNING | SUCCEEDED | FAILED | CANCELED
progressinteger0–100.
assetIdstring | nullSet on SUCCEEDED.
errorstring | nullPlain-language reason, present when FAILED.

Account

GET/api/v1/me

Request
curl https://polyvia-ai.com/api/v1/me -H "X-API-Key: $POLYVIA_API_KEY"
200 OK
{ "id": "…", "email": "you@example.com", "plan": "PRO", "credits": 475, "max_active_jobs": 3, "active_jobs": 1 }

Rate limits

Every key gets 60 requests per minute (sliding window). Each response includes X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix seconds). Go over and you receive 429 plus a Retry-After header in seconds. On top of that, your plan limits how many generations may be queued or running at the same time (max_active_jobs in /me).

Errors

All errors share one shape:

{ "error": { "code": "insufficient_credits", "message": "This generation costs 25 credits." } }

Error codes never change. The message field is in English regardless of the language you view this site in.

CodeHTTP statusDescription
invalid_request400Validation failed on the body or parameters. The message tells you which field.
unauthorized401X-API-Key is absent, malformed or revoked.
insufficient_credits402Your balance doesn't cover this generation.
forbidden403The account is suspended, or you don't own this resource.
not_found404That generation (or endpoint) doesn't exist.
too_many_active_jobs409You've hit your plan's limit on simultaneous generations. Let one finish first.
rate_limited429More than 60 requests per minute. Check Retry-After.
internal_error500Something went wrong on our end. You can safely retry.