API reference

API reference

REST API reference for low-poly.com: low-poly generation methods, 3D model conversion, polygon reduction, LOD generation, mesh inspection and asset downloads, with examples, auth and rate limits.

On this page

Overview

REST over HTTPS. Tool endpoints are synchronous: upload a model and the response body is the result. Generation endpoints are asynchronous and direct — one endpoint per output type: send an input (a file or a URL), start a job, poll its status, then download the returned artifacts. Chain steps by feeding the output[].url from one call into the next call's image_url / mesh_url — there's no project or artifact id to manage.

Base URL: https://low-poly.com/api/v1

EndpointPurposeReturnsCost
POST /imageGenerate concept images from a prompt (or a variation of a reference image)application/jsonper candidate
POST /meshTurn an image into a 3D low-poly meshapplication/jsonper candidate
POST /texturePaint a texture onto a mesh using a reference imageapplication/jsonper candidate
GET /generations/{id}Poll generation statusapplication/jsonfree
GET /artifacts/{token}/rawDownload a generated artifactbinaryfree
GET /assetsSearch low-poly asset catalogueapplication/jsonfree
POST /assets/{slug}/downloadDownload a gallery asset (subscribers)binarydaily plan quota
POST /toolsRun any model tool by methodbinary or zipvaries by method
POST /tools/reduceDecimate a meshbinary (mesh)1 credit
POST /tools/convertFormat swapbinary (mesh)1 credit
POST /tools/lodLOD levels bundleapplication/zip1 / level
POST /tools/pivotRecenter pivotbinary (mesh)1 credit
POST /tools/orientRotate / re-orientbinary (mesh)1 credit
POST /tools/batchProcess many filesapplication/zip1 / success
GET /meAccount infoapplication/jsonfree

Endpoint paths on this page are shown relative to the base URL. For example, /tools resolves to https://low-poly.com/api/v1/tools.

Authentication

Send your key as a bearer token in the Authorization header. Create and rotate keys on your API keys page.

Missing or invalid keys return 401 unauthorized.

Access and billing

Every account can create a key and call every endpoint — there is no plan that unlocks the API and no plan that closes it. What the plan decides is who pays for the generations, and the API is metered separately from the browser:

  • Included allowanceStudio plan

    A fixed number of API generations per calendar month, counted separately from anything you do in the browser. Calls keep working past the allowance and fall back to spending credits from the account balance. See pricing for the current figures.

  • Metered in creditsevery other plan

    Each generation spends credits from the account balance, exactly as a browser generation used to. A plan that advertises unlimited generations means unlimited in the browser; it grants no API allowance, and its API calls spend credits like any other.

Mesh tools, conversions, status polls, artifact downloads and /me are unaffected by any of this: tools cost their usual credits on every plan, and reads are free.

A generation response carries the caller’s remaining allowance, both as headers and as an api_quota object in the body — emitted only when the plan actually includes one. Watch X-Api-Quota-Remaining to back off before you start paying overage; expect 402 insufficient_credits when the allowance is gone and the balance cannot cover the call either.

Request header
Authorization: Bearer lp_live_xxxxxxxxxxxxxxxxxxxxxxxx
Response headers (generation endpoints, allowance plans only)
X-Api-Quota-Limit:     1000
X-Api-Quota-Used:      412
X-Api-Quota-Remaining: 588

Supported formats

Maximum upload size is 100 MB per file. The output format defaults to the input extension when omitted.

ExtensionNameReadWrite
glb GLB yesyes
gltf glTF yesyes
obj OBJ yesyes
fbx FBX yesyes
3ds 3DS yesyes
stl STL yesyes
blendBlender yes—

POST /image

Generates low-poly concept image candidates from a text prompt (txt2img), or a variation of a reference image (img2img).

Content-Type: application/json or multipart/form-data (for img2img's reference image).

Request parameters

  • promptstringrequired

    What to generate. Max 2000 characters.

  • countinteger 1-8optional default: 1

    Number of candidates.

  • modestringoptional default: txt2img

    txt2img or img2img.

  • image / image_urlbinary or stringoptional

    Reference image, required when mode=img2img. Provide the file as multipart image, or a public URL as image_url — not both.

  • strengthnumber 0.05-1.0optional default: 0.6

    How much the img2img output may drift from the reference.

Response

201 Created returns the generation: id, status, current progress, and output (empty until the job completes — poll /generations/{id}).

Prompt to candidatescurl
curl -X POST https://low-poly.com/api/v1/image \
  -H "Authorization: Bearer lp_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "low-poly modular sci-fi crate, game asset, clean silhouette",
    "count": 4
  }'
Variation of your own referencecurl
curl -X POST https://low-poly.com/api/v1/image \
  -H "Authorization: Bearer lp_live_..." \
  -F "prompt=same crate, weathered metal" \
  -F "mode=img2img" \
  -F "image=@crate-concept.png"

POST /mesh

Turns an image into a 3D low-poly mesh. Bring your own image, or chain the output[0].url from a prior /image call.

Content-Type: application/json or multipart/form-data.

Request parameters

  • image / image_urlbinary or stringrequired

    The source image — multipart image, or a public URL as image_url. Exactly one of the two.

  • countinteger 1-8optional default: 1

    Number of mesh candidates.

Response

Same shape as /image — poll /generations/{id} for the resulting mesh(es).

Upload your own photocurl
curl -X POST https://low-poly.com/api/v1/mesh \
  -H "Authorization: Bearer lp_live_..." \
  -F "image=@product-photo.jpg"
Chain from a generated imagecurl
curl -X POST https://low-poly.com/api/v1/mesh \
  -H "Authorization: Bearer lp_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "image_url": "https://low-poly.com/api/v1/artifacts/64_hex_artifact_token/raw" }'

POST /texture

Paints a texture onto a mesh, using a reference image for appearance. Both a mesh and an image are required — there's no project lineage to infer one from the other.

Content-Type: application/json or multipart/form-data.

Request parameters

  • mesh / mesh_urlbinary or stringrequired

    The mesh to texture — multipart mesh, or a public URL as mesh_url.

  • image / image_urlbinary or stringrequired

    The reference image — multipart image, or a public URL as image_url.

  • countinteger 1-8optional default: 1

    Number of texture candidates.

Response

Same shape as /image — poll /generations/{id} for the textured mesh.

Your own mesh + referencecurl
curl -X POST https://low-poly.com/api/v1/texture \
  -H "Authorization: Bearer lp_live_..." \
  -F "mesh=@crate.glb" \
  -F "image=@crate-concept.png"
Chain from prior generationscurl
curl -X POST https://low-poly.com/api/v1/texture \
  -H "Authorization: Bearer lp_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "mesh_url": "https://low-poly.com/api/v1/artifacts/64_hex_mesh_token/raw",
    "image_url": "https://low-poly.com/api/v1/artifacts/64_hex_image_token/raw"
  }'

GET /generations/{id}

Polls and refreshes a generation. When status becomes success, download each item in output[].url.

Requestcurl
curl https://low-poly.com/api/v1/generations/918 \
  -H "Authorization: Bearer lp_live_..."
Success shapejson
{
  "data": {
    "id": 918,
    "kind": "mesh",
    "status": "success",
    "output": [
      {
        "url": "/api/v1/artifacts/64_hex_artifact_token/raw",
        "mime_type": "model/gltf-binary",
        "size_bytes": 812433
      }
    ],
    "credits_consumed": 10,
    "credits_remaining": 4810
  }
}

GET /artifacts/{token}/raw

Downloads a generated image, model or texture artifact. The artifact token is non-enumerable and still checked against the bearer key's user.

Requestcurl
curl https://low-poly.com/api/v1/artifacts/64_hex_artifact_token/raw \
  -H "Authorization: Bearer lp_live_..." \
  -o generated-model.glb

GET /assets/category/{slug}

Same response shape as /assets, scoped to one category. Returns 404 if the category slug doesn't exist.

Query parameters

  • qstringoptional

    Search text.

  • tagstringoptional

    Tag slug.

  • sortstringoptional default: recent

    One of recent, popular, cheap, name.

  • pageintegeroptional default: 1

    Page number.

  • per_pageinteger 1-96optional default: 24

    Items per page.

Requestcurl
curl "https://low-poly.com/api/v1/assets/category/vehicles?sort=popular"

GET /assets/categories

Lists asset categories. No authentication required.

Requestcurl
curl https://low-poly.com/api/v1/assets/categories

GET /assets/{slug}

Returns metadata for one published asset: description, category, tags, gallery media, available formats and download endpoint.

Requestcurl
curl https://low-poly.com/api/v1/assets/low-poly-crate

POST /assets/{slug}/download

Downloads a gallery asset. Requires an active subscription on the key owner's account; each download counts against the plan's daily allowance (the X-Downloads-Remaining response header tells you what's left). Pass format as a query or form field.

Request parameters

  • formatstringoptional default: glb

    One of the formats returned by /assets/{slug}, usually glb, fbx or obj.

Requestcurl
curl -X POST "https://low-poly.com/api/v1/assets/low-poly-crate/download?format=glb" \
  -H "Authorization: Bearer lp_live_..." \
  -o low-poly-crate.glb

POST /tools

Run the low-poly tool suite through a single programmable endpoint. Pass method to choose the operation; the method-specific endpoints below remain available for fixed integrations.

Content-Type: multipart/form-data

Request parameters

  • methodstringrequired

    One of reduce, convert, lod, pivot, orient, batch. Aliases like simplify, decimate, format, recenter and rotate are accepted.

  • filebinaryoptional

    Input mesh for single-file methods. Required for reduce, convert, lod, pivot and orient.

  • files[]binary[]optional

    Input meshes for batch.

  • ratio, ratios, format, axismixedoptional

    Use the same method-specific fields documented in the dedicated sections below.

Response

The response is the same as the selected method: a mesh binary, a ZIP archive, or a structured API error.

Requestcurl
curl -X POST https://low-poly.com/api/v1/tools \
  -H "Authorization: Bearer lp_live_..." \
  -F "method=reduce" \
  -F "file=@tree.glb" \
  -F "ratio=0.25" \
  -F "format=glb" \
  -o tree-low.glb

POST /tools/reduce

Decimate a mesh while preserving its silhouette.

Content-Type: multipart/form-data

Request parameters

  • filebinaryrequired

    Input mesh. The extension must match a supported format.

  • rationumber 0.05–1.0optional default: 0.25

    Fraction of triangles to keep. 0.25 = keep 25%.

  • formatstringoptional default: input format

    Output format. One of glb, gltf, obj, fbx, 3ds.

Response

200 OK — application/octet-stream, body is the processed mesh.

X-Tris-In
Input triangle count
X-Tris-Out
Output triangle count
X-Credits-Cost
Credits charged for this call
X-Credits-Remaining
Credits left on the account
X-RateLimit-*
Standard rate-limit headers (see Rate limits)
Requestcurl
curl -X POST https://low-poly.com/api/v1/tools/reduce \
  -H "Authorization: Bearer lp_live_..." \
  -F "file=@dragon.glb" \
  -F "ratio=0.25" \
  -F "format=glb" \
  -o dragon-low.glb
Response headers200 OK
Content-Type:          application/octet-stream
Content-Disposition:   attachment; filename="dragon-low.glb"
X-Tris-In:             184502
X-Tris-Out:            46125
X-Credits-Cost:        1
X-Credits-Remaining:   4819

POST /tools/convert

Format swap, no decimation. Same fields as /tools/reduce; ratio is forced to 1.0.

Content-Type: multipart/form-data

Request parameters

  • filebinaryrequired

    Input mesh.

  • formatstringrequired

    Target format. Must differ from the input to be useful.

Response

200 OK — application/octet-stream, body is the converted mesh. Same headers as /tools/reduce.

Requestcurl
curl -X POST https://low-poly.com/api/v1/tools/convert \
  -H "Authorization: Bearer lp_live_..." \
  -F "file=@character.fbx" \
  -F "format=glb" \
  -o character.glb

POST /tools/lod

Generate several decimated levels from one model in a single call. Returns a ZIP, one file per ratio.

Content-Type: multipart/form-data

Request parameters

  • filebinaryrequired

    Input mesh.

  • ratioscsv (0<r≤1)optional default: 0.6,0.3,0.15,0.05

    Comma-separated list of ratios, one per level. Clamped to [0.005, 1.0].

  • formatstringoptional default: input format

    Output format applied to every level.

Response

200 OK — application/zip. Entries are named {stem}-lod{i}-r{ratio}.{ext}.

X-Lod-Levels
Number of LOD levels in the archive
X-Credits-Cost
Credits charged (1 per level)
X-Credits-Remaining
Credits left on the account
Requestcurl
curl -X POST https://low-poly.com/api/v1/tools/lod \
  -H "Authorization: Bearer lp_live_..." \
  -F "file=@tree.glb" \
  -F "ratios=0.6,0.3,0.15,0.05" \
  -F "format=glb" \
  -o tree-lod.zip
Archive contentszip
tree-lod0-r0.60.glb
tree-lod1-r0.30.glb
tree-lod2-r0.15.glb
tree-lod3-r0.05.glb

POST /tools/pivot

Recenter a model's pivot point.

Content-Type: multipart/form-data

Request parameters

  • filebinaryrequired

    Input mesh.

  • modestringoptional default: center

    One of center (bounding-box center), origin (world origin), ground (XZ-centered, Y at minimum).

  • formatstringoptional default: input format

    Output format.

Response

200 OK — application/octet-stream. X-Pivot-Mode echoes the applied mode; X-Credits-Cost / X-Credits-Remaining report billing.

Requestcurl
curl -X POST https://low-poly.com/api/v1/tools/pivot \
  -H "Authorization: Bearer lp_live_..." \
  -F "file=@prop.glb" \
  -F "mode=ground" \
  -o prop-ground.glb

POST /tools/orient

Rotate or re-orient a model. The rotation is baked into the vertex positions — the resulting file imports identity-rotated.

Content-Type: multipart/form-data

Request parameters

  • filebinaryrequired

    Input mesh.

  • presetstringoptional default: y-up-to-z-up

    One of y-up-to-z-up, z-up-to-y-up, rotate-x-90, rotate-x-180, rotate-x-270, rotate-y-90, rotate-y-180, rotate-y-270, rotate-z-90, rotate-z-180, rotate-z-270, flip-x, flip-y, flip-z, custom.

  • rxnumber -360..360optional default: 0

    X Euler angle in degrees. Only used when preset=custom.

  • rynumber -360..360optional default: 0

    Y Euler angle in degrees. Only used when preset=custom.

  • rznumber -360..360optional default: 0

    Z Euler angle in degrees. Only used when preset=custom. Applied in XYZ order.

  • formatstringoptional default: input format

    Output format.

Response

200 OK — application/octet-stream. X-Orient-Preset echoes the applied preset; X-Credits-Cost / X-Credits-Remaining report billing.

Requestcurl
curl -X POST https://low-poly.com/api/v1/tools/orient \
  -H "Authorization: Bearer lp_live_..." \
  -F "file=@asset.glb" \
  -F "preset=z-up-to-y-up" \
  -o asset-yup.glb
Custom Eulercurl
curl -X POST https://low-poly.com/api/v1/tools/orient \
  -H "Authorization: Bearer lp_live_..." \
  -F "file=@asset.glb" \
  -F "preset=custom" \
  -F "rx=0" -F "ry=90" -F "rz=0" \
  -o asset-rot.glb

POST /tools/batch

Process many files in a single request. Returns a ZIP, one decimated file per input. Files that fail processing are skipped from the ZIP and reported in X-Batch-Error-List; you are billed only for successful files.

Content-Type: multipart/form-data

Request parameters

  • files[]binary (repeated)required

    Up to 500 files per batch.

  • rationumber 0.05–1.0optional default: 0.25

    Decimation ratio applied to every file.

Response

200 OK — application/zip named batch.zip. Each entry is {originalName}-low.{ext}.

X-Batch-Count
Files submitted
X-Batch-Succeeded
Files that processed successfully
X-Batch-Errors
Files that failed processing
X-Batch-Error-List
JSON array of {name, error} (empty when 0)
X-Credits-Cost
Credits charged (1 per successful file)
X-Credits-Remaining
Credits left on the account
Requestcurl
curl -X POST https://low-poly.com/api/v1/tools/batch \
  -H "Authorization: Bearer lp_live_..." \
  -F "files[]=@rock_01.obj" \
  -F "files[]=@rock_02.obj" \
  -F "files[]=@rock_03.obj" \
  -F "ratio=0.3" \
  -o rocks-low.zip

GET /me

Inspect the authenticated account: user, credit balance, key id. Does not consume credits.

Response

200 OK — application/json

Requestcurl
curl https://low-poly.com/api/v1/me \
  -H "Authorization: Bearer lp_live_..."
Response200 OK
{
  "user": {
    "id": 42,
    "email": "you@studio.com",
    "name": "You"
  },
  "credits": {
    "balance": 4820
  },
  "key": {
    "id": 17
  }
}

Rate limits

Per-key, per-minute caps by endpoint group: generation submits (/image, /mesh, /texture) 20; /generations/{id} and /me 120; /tools/reduce and /tools/convert 60; /tools/lod, /tools/pivot and /tools/orient 30; /tools/batch 10.

The limited subject is the key, not the account: each key gets its own budget, so a runaway script on one integration cannot starve another, and a suspect key can be revoked without throttling everything else you run. Issue one key per integration.

Rate limits are per minute and apply on every plan, including plans with an included allowance — they are a burst ceiling, not a quota. The monthly allowance is a separate thing entirely; see Access and billing.

Hitting a cap returns 429 rate_limited. Some tool endpoints additionally include X-RateLimit-* headers in their responses; treat the 429 body as the source of truth.

Response headers (tool endpoints)
X-RateLimit-Limit:     60
X-RateLimit-Remaining: 58
X-RateLimit-Reset:     1763251200

Errors

All errors return JSON with a stable code string. Branch on code; message is for humans.

StatusCodeWhen
400missing_fileNo file field, or upload error
400missing_input/image, /mesh, /texture: neither the file field nor its *_url counterpart was provided
400invalid_input/image, /mesh, /texture: both the file field and its *_url counterpart were provided
400invalid_urlAn *_url field isn't an http(s) URL
400unsupported_formatExtension not in the supported list
400bad_mode/tools/pivot: invalid mode value
400missing_files/tools/batch: no files
400too_many/tools/batch: more than 500 files
401unauthorizedMissing or invalid bearer token
402insufficient_creditsNothing can pay for the call: the plan’s included API allowance is used up (or the plan has none) and the credit balance is too low
402subscription_required/assets/{slug}/download: no active subscription on the account
429download_limit_reached/assets/{slug}/download: the plan's daily download allowance is used up
404not_foundGeneration or artifact not owned by this key
413file_too_largeUpload exceeds the 100 MB limit
415content_mismatch/image, /mesh, /texture: file contents don't match the declared/detected extension. Tool endpoints report the same situation as 400 unsupported_format
422fetch_failedAn *_url field could not be fetched (unreachable, too large, not public)
429rate_limitedPer-minute cap exceeded
500processing_failedMesh pipeline raised an error; message carries the detail
Error shapejson
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests"
  }
}

CORS

By default, cross-origin browser access is restricted to this site's own origin — Access-Control-Allow-Origin is never * unless the operator explicitly opts in. Preflight OPTIONS requests are answered on every /api/v1/* path. Server-side integrations (curl, SDKs, backends) are unaffected by CORS; if you need to call the API from a browser app on another domain, proxy the calls through your own backend so your key stays secret anyway.