> For the complete documentation index, see [llms.txt](https://docs.projectsim.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.projectsim.ai/api-reference/assets.md).

# Assets

## List Assets

> List your assets, newest first.\
> \
> Cursor-paginated — pass the previous page's \`next\_cursor\`, and a\
> null \`next\_cursor\` means you have reached the end. \`status\`\
> filters on the latest job's status.\
> \
> Deleted assets are omitted. Download URLs are not included here;\
> retrieve a single asset to get them.

```json
{"openapi":"3.1.0","info":{"title":"projectsim API","version":"1.0.0-beta"},"security":[{"ProjectSimToken":[]}],"components":{"securitySchemes":{"ProjectSimToken":{"bearerFormat":"kps_live_...","description":"A per-user API token. The tenant is the user, so no request body carries a user id. Tokens without the `kps_` prefix are rejected before any lookup.","scheme":"bearer","type":"http"}},"schemas":{"AssetListResponse":{"properties":{"assets":{"items":{"$ref":"#/components/schemas/AssetSummary"},"title":"Assets","type":"array"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Null on the last page.","title":"Next Cursor"}},"required":["assets"],"title":"AssetListResponse","type":"object"},"AssetSummary":{"properties":{"batch_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Batch Id"},"batch_index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Batch Index"},"created_at":{"format":"date-time","title":"Created At","type":"string"},"id":{"title":"Id","type":"string"},"job":{"anyOf":[{"$ref":"#/components/schemas/AssetJobRef"},{"type":"null"}]},"kind":{"description":"Provenance: object_reconstruction · procedural_generation · scene_decomposition","title":"Kind","type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"variation_set_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Variation Set Id"}},"required":["id","kind","created_at"],"title":"AssetSummary","type":"object"},"AssetJobRef":{"description":"The asset's latest job, inlined. Assets have no status of their own.","properties":{"current_stage":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Current Stage"},"job_id":{"title":"Job Id","type":"string"},"progress":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Progress"},"status":{"title":"Status","type":"string"}},"required":["job_id","status"],"title":"AssetJobRef","type":"object"},"Problem":{"description":"An RFC 7807 error, the shape every failure uses.\n\nDeclared explicitly because the handlers replace FastAPI's default\nvalidation response; without this the spec would advertise\n`HTTPValidationError`, whose `detail` is a list rather than a string,\nand every generated client would crash parsing a 422.","properties":{"detail":{"description":"Human-readable explanation of this occurrence.","title":"Detail","type":"string"},"errors":{"anyOf":[{"items":{"$ref":"#/components/schemas/ValidationDetail"},"type":"array"},{"type":"null"}],"description":"Present on a 422; one entry per failing field.","title":"Errors"},"instance":{"description":"Identifies this occurrence; quote it to support.","title":"Instance","type":"string"},"path":{"title":"Path","type":"string"},"request_id":{"description":"Also returned in the X-Request-Id response header.","title":"Request Id","type":"string"},"status":{"title":"Status","type":"integer"},"title":{"title":"Title","type":"string"},"type":{"description":"Stable URI identifying the error class.","title":"Type","type":"string"}},"required":["type","title","status","detail","instance","path","request_id"],"title":"Problem","type":"object"},"ValidationDetail":{"description":"One field-level validation failure.","properties":{"loc":{"description":"Dotted path to the offending field.","title":"Loc","type":"string"},"msg":{"title":"Msg","type":"string"},"type":{"title":"Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationDetail","type":"object"}}},"paths":{"/v1/assets":{"get":{"description":"List your assets, newest first.\n\nCursor-paginated — pass the previous page's `next_cursor`, and a\nnull `next_cursor` means you have reached the end. `status`\nfilters on the latest job's status.\n\nDeleted assets are omitted. Download URLs are not included here;\nretrieve a single asset to get them.","operationId":"list_assets","parameters":[{"in":"query","name":"status","required":false,"schema":{"anyOf":[{"enum":["queued","running","complete","failed","canceled"],"type":"string"},{"type":"null"}],"title":"Status"}},{"in":"query","name":"limit","required":false,"schema":{"default":50,"maximum":100,"minimum":1,"title":"Limit","type":"integer"}},{"in":"query","name":"cursor","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssetListResponse"}}},"description":"Successful Response"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Missing or invalid API token"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Request body too large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Request failed validation"}},"summary":"List Assets","tags":["assets"]}}}}
```

## Create Asset Measured

> Create a millimetre-accurate asset, measured against a ChArUco board.\
> \
> Same pipeline as \`POST /v1/assets/standard\` plus a metric-scale\
> stage, so this route \*\*requires\*\* \`inputs.capture\`: one video clip\
> (MP4 or MOV) of the object standing next to a printed ChArUco board,\
> by HTTPS URL or inline as base64. That capture is what the scale stage\
> measures against; without it the request is a \`422\`.\
> \
> Exactly one \`inputs.images\` entry is required. \`inputs.text\` is not\
> accepted on this route, even when an image is also supplied.\
> \
> Everything else — \`params\`, \`effective\_params\`,\
> \`Idempotency-Key\`, the \`202\` + \`job\_id\` handoff, the 600-asset\
> account limit — matches \`POST /v1/assets/standard\`.

```json
{"openapi":"3.1.0","info":{"title":"projectsim API","version":"1.0.0-beta"},"security":[{"ProjectSimToken":[]}],"components":{"securitySchemes":{"ProjectSimToken":{"bearerFormat":"kps_live_...","description":"A per-user API token. The tenant is the user, so no request body carries a user id. Tokens without the `kps_` prefix are rejected before any lookup.","scheme":"bearer","type":"http"}},"schemas":{"CreateMeasuredAssetRequest":{"additionalProperties":false,"properties":{"inputs":{"$ref":"#/components/schemas/MeasuredAssetInputs"},"name":{"anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}],"title":"Name"},"params":{"anyOf":[{"$ref":"#/components/schemas/Params"},{"type":"null"}]}},"required":["inputs"],"title":"CreateMeasuredAssetRequest","type":"object"},"MeasuredAssetInputs":{"additionalProperties":false,"description":"Exactly one subject image and one capture video.","properties":{"capture":{"description":"Exactly one video clip (MP4 or MOV) of the object next to a printed ChArUco board, by HTTPS URL or inline as base64.","items":{"$ref":"#/components/schemas/CaptureInput"},"maxItems":1,"minItems":1,"title":"Capture","type":"array"},"images":{"items":{"$ref":"#/components/schemas/ImageInput"},"maxItems":1,"minItems":1,"title":"Images","type":"array"}},"required":["images","capture"],"title":"MeasuredAssetInputs","type":"object"},"CaptureInput":{"additionalProperties":false,"description":"One video clip of the object beside a ChArUco board.\n\nThe measurement reference for `POST /v1/assets/measured`: the object\nstands on the floor next to the printed board and is filmed in one clip\nwalking around it. The clip comes either by HTTPS URL or inline as\nbase64, exactly one of the two.","properties":{"data":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The capture video (MP4 or MOV) as base64, up to 500 MB decoded. Stored as part of the create call, so a payload that is not a supported clip is a `422` here rather than a failed job. Inflates the request by a third: prefer `url` for a large clip.","title":"Data"},"url":{"anyOf":[{"format":"uri","maxLength":2083,"minLength":1,"type":"string"},{"type":"null"}],"description":"HTTPS URL of the capture video (MP4 or MOV).","title":"Url"}},"title":"CaptureInput","type":"object"},"ImageInput":{"additionalProperties":false,"properties":{"data":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Data"},"url":{"anyOf":[{"format":"uri","maxLength":2083,"minLength":1,"type":"string"},{"type":"null"}],"title":"Url"}},"title":"ImageInput","type":"object"},"Params":{"additionalProperties":false,"properties":{"mesh":{"$ref":"#/components/schemas/MeshParams","default":{"quality":"standard"}},"physics":{"$ref":"#/components/schemas/PhysicsParams","default":{"body":"rigid","collision":"auto","simulator":"isaac_sim_physx"}},"texture":{"$ref":"#/components/schemas/TextureParams","default":{"resolution":4096}},"variation":{"$ref":"#/components/schemas/VariationParams","default":{"variation_type":"general","wildness":"moderate"}}},"title":"Params","type":"object"},"MeshParams":{"additionalProperties":false,"properties":{"quality":{"default":"standard","enum":["standard","low","ultra_low"],"title":"Quality","type":"string"}},"title":"MeshParams","type":"object"},"PhysicsParams":{"additionalProperties":false,"properties":{"body":{"default":"rigid","description":"Physical behavior of the bodies: rigid preserves shape; deformable uses soft-body simulation.","enum":["rigid","deformable"],"title":"Body","type":"string"},"collision":{"default":"auto","enum":["auto","convex_hull","convex_decomposition","coacd","bounding_box","sdf"],"title":"Collision","type":"string"},"simulator":{"default":"isaac_sim_physx","description":"Target runtime. Native formats and physics engine are derived internally; agnostic delivers FBX and GLB plus physics sidecar.","enum":["isaac_sim_physx","isaac_sim_newton","mujoco","sapien","genesis","agnostic"],"title":"Simulator","type":"string"}},"title":"PhysicsParams","type":"object"},"TextureParams":{"additionalProperties":false,"properties":{"resolution":{"default":4096,"enum":[1024,2048,4096,8192],"title":"Resolution","type":"integer"}},"title":"TextureParams","type":"object"},"VariationParams":{"additionalProperties":false,"description":"How an image-method set's variants are generated. Ignored otherwise.\n\nA deliberate subset of the generator's options: what a customer steers,\nnot how many images it makes. Count is the set's `count`, one image per\nmember, so it is not reachable from here. The generator's custom prompt\nis not steered here either — it comes from the set's `seed.text` — and\nthe subject name comes from the set's `name`.","properties":{"variation_type":{"default":"general","enum":["texture","general"],"title":"Variation Type","type":"string"},"wildness":{"default":"moderate","enum":["subtle","moderate","bold","wild"],"title":"Wildness","type":"string"}},"title":"VariationParams","type":"object"},"CreateAssetResponse":{"properties":{"effective_params":{"additionalProperties":true,"title":"Effective Params","type":"object"},"id":{"title":"Id","type":"string"},"job_id":{"title":"Job Id","type":"string"},"status":{"title":"Status","type":"string"}},"required":["id","job_id","status","effective_params"],"title":"CreateAssetResponse","type":"object"},"Problem":{"description":"An RFC 7807 error, the shape every failure uses.\n\nDeclared explicitly because the handlers replace FastAPI's default\nvalidation response; without this the spec would advertise\n`HTTPValidationError`, whose `detail` is a list rather than a string,\nand every generated client would crash parsing a 422.","properties":{"detail":{"description":"Human-readable explanation of this occurrence.","title":"Detail","type":"string"},"errors":{"anyOf":[{"items":{"$ref":"#/components/schemas/ValidationDetail"},"type":"array"},{"type":"null"}],"description":"Present on a 422; one entry per failing field.","title":"Errors"},"instance":{"description":"Identifies this occurrence; quote it to support.","title":"Instance","type":"string"},"path":{"title":"Path","type":"string"},"request_id":{"description":"Also returned in the X-Request-Id response header.","title":"Request Id","type":"string"},"status":{"title":"Status","type":"integer"},"title":{"title":"Title","type":"string"},"type":{"description":"Stable URI identifying the error class.","title":"Type","type":"string"}},"required":["type","title","status","detail","instance","path","request_id"],"title":"Problem","type":"object"},"ValidationDetail":{"description":"One field-level validation failure.","properties":{"loc":{"description":"Dotted path to the offending field.","title":"Loc","type":"string"},"msg":{"title":"Msg","type":"string"},"type":{"title":"Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationDetail","type":"object"}}},"paths":{"/v1/assets/measured":{"post":{"description":"Create a millimetre-accurate asset, measured against a ChArUco board.\n\nSame pipeline as `POST /v1/assets/standard` plus a metric-scale\nstage, so this route **requires** `inputs.capture`: one video clip\n(MP4 or MOV) of the object standing next to a printed ChArUco board,\nby HTTPS URL or inline as base64. That capture is what the scale stage\nmeasures against; without it the request is a `422`.\n\nExactly one `inputs.images` entry is required. `inputs.text` is not\naccepted on this route, even when an image is also supplied.\n\nEverything else — `params`, `effective_params`,\n`Idempotency-Key`, the `202` + `job_id` handoff, the 600-asset\naccount limit — matches `POST /v1/assets/standard`.","operationId":"create_asset_measured","parameters":[{"in":"header","name":"Idempotency-Key","required":false,"schema":{"anyOf":[{"maxLength":255,"type":"string"},{"type":"null"}],"title":"Idempotency-Key"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMeasuredAssetRequest"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAssetResponse"}}},"description":"Successful Response"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Missing or invalid API token"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Not enough credits. `payment-required`: no card on file yet (the first 40 credits are free, but a card is required before the first request), a failed payment, or an ended subscription; fix it in the dashboard. `overage-cap-reached`: this period's overage cap would be exceeded (the detail says how many credits are left); requests resume when credits reset on the billing date, or change the cap in the dashboard. `credit-limit-reached` (accounts invoiced by Kaedim): the request needs more than is left of this month's included credits and any overage allowance (the detail says how many are left); send a smaller request, wait for next month (UTC), or contact Kaedim for more. Nothing is created or reserved."},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Request body too large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Request failed validation"}},"summary":"Create Asset Measured","tags":["assets"]}}}}
```

## Create Asset Standard

> Create an asset from one image or an object description.\
> \
> Returns \`202\` immediately with a \`job\_id\`; the asset is not ready\
> yet. Poll \`GET /v1/jobs/{job\_id}\`, or subscribe to\
> \`asset.completed\`.\
> \
> Provide exactly one of \`inputs.images\` or \`inputs.text\`. A text\
> description is expanded into a canonical reference image, which then\
> enters the same reconstruction pipeline as an uploaded image.\
> \
> Every input image is either an HTTPS URL or inline base64 —\
> there is no upload step. An inline image is stored as part of\
> this call, so its format is checked here and a payload that is\
> not a supported image is a \`422\`; an image given by URL is\
> retrieved by the job's first internal stage instead, and a URL\
> that fails or does not hold an image fails that job rather than\
> this call.\
> \
> Request \`params\` deep-merge over your defaults from\
> \`GET /v1/settings\`, and the fully resolved result comes back as\
> \`effective\_params\`, so the job is reproducible from its own\
> record alone.\
> \
> Limits: 1 image (≤ 100 MB, PNG, JPEG or WebP), or text up to\
> 10,000 characters. An account given a\
> lifetime asset limit gets a \`429\` for a request past it,\
> variation-set members included.\
> \
> This route does not measure metric scale, so \`inputs.capture\` is\
> not accepted — sending it is a \`422\`. For a millimetre-accurate\
> asset use \`POST /v1/assets/measured\`.\
> \
> Pass \`Idempotency-Key\` to make a retry safe — a replay returns\
> this same response instead of creating a second asset, and\
> reusing the key with a different body is a \`409\`.\
> \
> There is no rerun endpoint: iterating means creating a new asset.

```json
{"openapi":"3.1.0","info":{"title":"projectsim API","version":"1.0.0-beta"},"security":[{"ProjectSimToken":[]}],"components":{"securitySchemes":{"ProjectSimToken":{"bearerFormat":"kps_live_...","description":"A per-user API token. The tenant is the user, so no request body carries a user id. Tokens without the `kps_` prefix are rejected before any lookup.","scheme":"bearer","type":"http"}},"schemas":{"CreateAssetRequest":{"additionalProperties":false,"properties":{"inputs":{"$ref":"#/components/schemas/AssetInputs"},"name":{"anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}],"title":"Name"},"params":{"anyOf":[{"$ref":"#/components/schemas/Params"},{"type":"null"}]}},"required":["inputs"],"title":"CreateAssetRequest","type":"object"},"AssetInputs":{"additionalProperties":false,"properties":{"images":{"items":{"$ref":"#/components/schemas/ImageInput"},"maxItems":1,"title":"Images","type":"array"},"text":{"anyOf":[{"maxLength":10000,"minLength":1,"pattern":"\\S","type":"string"},{"type":"null"}],"description":"Object description used to generate a starting reference image. Provide either text or one image, not both.","title":"Text"}},"title":"AssetInputs","type":"object"},"ImageInput":{"additionalProperties":false,"properties":{"data":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Data"},"url":{"anyOf":[{"format":"uri","maxLength":2083,"minLength":1,"type":"string"},{"type":"null"}],"title":"Url"}},"title":"ImageInput","type":"object"},"Params":{"additionalProperties":false,"properties":{"mesh":{"$ref":"#/components/schemas/MeshParams","default":{"quality":"standard"}},"physics":{"$ref":"#/components/schemas/PhysicsParams","default":{"body":"rigid","collision":"auto","simulator":"isaac_sim_physx"}},"texture":{"$ref":"#/components/schemas/TextureParams","default":{"resolution":4096}},"variation":{"$ref":"#/components/schemas/VariationParams","default":{"variation_type":"general","wildness":"moderate"}}},"title":"Params","type":"object"},"MeshParams":{"additionalProperties":false,"properties":{"quality":{"default":"standard","enum":["standard","low","ultra_low"],"title":"Quality","type":"string"}},"title":"MeshParams","type":"object"},"PhysicsParams":{"additionalProperties":false,"properties":{"body":{"default":"rigid","description":"Physical behavior of the bodies: rigid preserves shape; deformable uses soft-body simulation.","enum":["rigid","deformable"],"title":"Body","type":"string"},"collision":{"default":"auto","enum":["auto","convex_hull","convex_decomposition","coacd","bounding_box","sdf"],"title":"Collision","type":"string"},"simulator":{"default":"isaac_sim_physx","description":"Target runtime. Native formats and physics engine are derived internally; agnostic delivers FBX and GLB plus physics sidecar.","enum":["isaac_sim_physx","isaac_sim_newton","mujoco","sapien","genesis","agnostic"],"title":"Simulator","type":"string"}},"title":"PhysicsParams","type":"object"},"TextureParams":{"additionalProperties":false,"properties":{"resolution":{"default":4096,"enum":[1024,2048,4096,8192],"title":"Resolution","type":"integer"}},"title":"TextureParams","type":"object"},"VariationParams":{"additionalProperties":false,"description":"How an image-method set's variants are generated. Ignored otherwise.\n\nA deliberate subset of the generator's options: what a customer steers,\nnot how many images it makes. Count is the set's `count`, one image per\nmember, so it is not reachable from here. The generator's custom prompt\nis not steered here either — it comes from the set's `seed.text` — and\nthe subject name comes from the set's `name`.","properties":{"variation_type":{"default":"general","enum":["texture","general"],"title":"Variation Type","type":"string"},"wildness":{"default":"moderate","enum":["subtle","moderate","bold","wild"],"title":"Wildness","type":"string"}},"title":"VariationParams","type":"object"},"CreateAssetResponse":{"properties":{"effective_params":{"additionalProperties":true,"title":"Effective Params","type":"object"},"id":{"title":"Id","type":"string"},"job_id":{"title":"Job Id","type":"string"},"status":{"title":"Status","type":"string"}},"required":["id","job_id","status","effective_params"],"title":"CreateAssetResponse","type":"object"},"Problem":{"description":"An RFC 7807 error, the shape every failure uses.\n\nDeclared explicitly because the handlers replace FastAPI's default\nvalidation response; without this the spec would advertise\n`HTTPValidationError`, whose `detail` is a list rather than a string,\nand every generated client would crash parsing a 422.","properties":{"detail":{"description":"Human-readable explanation of this occurrence.","title":"Detail","type":"string"},"errors":{"anyOf":[{"items":{"$ref":"#/components/schemas/ValidationDetail"},"type":"array"},{"type":"null"}],"description":"Present on a 422; one entry per failing field.","title":"Errors"},"instance":{"description":"Identifies this occurrence; quote it to support.","title":"Instance","type":"string"},"path":{"title":"Path","type":"string"},"request_id":{"description":"Also returned in the X-Request-Id response header.","title":"Request Id","type":"string"},"status":{"title":"Status","type":"integer"},"title":{"title":"Title","type":"string"},"type":{"description":"Stable URI identifying the error class.","title":"Type","type":"string"}},"required":["type","title","status","detail","instance","path","request_id"],"title":"Problem","type":"object"},"ValidationDetail":{"description":"One field-level validation failure.","properties":{"loc":{"description":"Dotted path to the offending field.","title":"Loc","type":"string"},"msg":{"title":"Msg","type":"string"},"type":{"title":"Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationDetail","type":"object"}}},"paths":{"/v1/assets/standard":{"post":{"description":"Create an asset from one image or an object description.\n\nReturns `202` immediately with a `job_id`; the asset is not ready\nyet. Poll `GET /v1/jobs/{job_id}`, or subscribe to\n`asset.completed`.\n\nProvide exactly one of `inputs.images` or `inputs.text`. A text\ndescription is expanded into a canonical reference image, which then\nenters the same reconstruction pipeline as an uploaded image.\n\nEvery input image is either an HTTPS URL or inline base64 —\nthere is no upload step. An inline image is stored as part of\nthis call, so its format is checked here and a payload that is\nnot a supported image is a `422`; an image given by URL is\nretrieved by the job's first internal stage instead, and a URL\nthat fails or does not hold an image fails that job rather than\nthis call.\n\nRequest `params` deep-merge over your defaults from\n`GET /v1/settings`, and the fully resolved result comes back as\n`effective_params`, so the job is reproducible from its own\nrecord alone.\n\nLimits: 1 image (≤ 100 MB, PNG, JPEG or WebP), or text up to\n10,000 characters. An account given a\nlifetime asset limit gets a `429` for a request past it,\nvariation-set members included.\n\nThis route does not measure metric scale, so `inputs.capture` is\nnot accepted — sending it is a `422`. For a millimetre-accurate\nasset use `POST /v1/assets/measured`.\n\nPass `Idempotency-Key` to make a retry safe — a replay returns\nthis same response instead of creating a second asset, and\nreusing the key with a different body is a `409`.\n\nThere is no rerun endpoint: iterating means creating a new asset.","operationId":"create_asset_standard","parameters":[{"in":"header","name":"Idempotency-Key","required":false,"schema":{"anyOf":[{"maxLength":255,"type":"string"},{"type":"null"}],"title":"Idempotency-Key"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAssetRequest"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAssetResponse"}}},"description":"Successful Response"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Missing or invalid API token"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Not enough credits. `payment-required`: no card on file yet (the first 40 credits are free, but a card is required before the first request), a failed payment, or an ended subscription; fix it in the dashboard. `overage-cap-reached`: this period's overage cap would be exceeded (the detail says how many credits are left); requests resume when credits reset on the billing date, or change the cap in the dashboard. `credit-limit-reached` (accounts invoiced by Kaedim): the request needs more than is left of this month's included credits and any overage allowance (the detail says how many are left); send a smaller request, wait for next month (UTC), or contact Kaedim for more. Nothing is created or reserved."},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Request body too large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Request failed validation"}},"summary":"Create Asset Standard","tags":["assets"]}}}}
```

## Get Asset

> Retrieve one asset, with fresh download URLs.\
> \
> This is both the record and the download surface: every entry in\
> \`files\` carries a presigned URL valid for one hour. Do not cache\
> those URLs — call this again to mint new ones.\
> \
> Files appear only once the asset completes; there are no partial\
> downloads. Returns \`404\` if the asset does not exist or was\
> deleted.

```json
{"openapi":"3.1.0","info":{"title":"projectsim API","version":"1.0.0-beta"},"security":[{"ProjectSimToken":[]}],"components":{"securitySchemes":{"ProjectSimToken":{"bearerFormat":"kps_live_...","description":"A per-user API token. The tenant is the user, so no request body carries a user id. Tokens without the `kps_` prefix are rejected before any lookup.","scheme":"bearer","type":"http"}},"schemas":{"AssetDetail":{"properties":{"batch_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Batch Id"},"batch_index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Batch Index"},"created_at":{"format":"date-time","title":"Created At","type":"string"},"dimensions":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Dimensions"},"effective_params":{"additionalProperties":true,"description":"Your defaults merged with the request params and frozen at create, so the job is reproducible from this record. Same shape as GET /v1/settings.","title":"Effective Params","type":"object"},"files":{"description":"Empty until the asset completes; no partial downloads.","items":{"$ref":"#/components/schemas/AssetFileEntry"},"title":"Files","type":"array"},"id":{"title":"Id","type":"string"},"job":{"anyOf":[{"$ref":"#/components/schemas/AssetJobRef"},{"type":"null"}]},"kind":{"description":"Provenance: object_reconstruction · procedural_generation · scene_decomposition","title":"Kind","type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"scene_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scene Id"},"variation_set_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Variation Set Id"}},"required":["id","kind","created_at","effective_params","files"],"title":"AssetDetail","type":"object"},"AssetFileEntry":{"description":"A deliverable, with a download URL minted for this response.","properties":{"expires_at":{"format":"date-time","title":"Expires At","type":"string"},"kind":{"description":"fbx · glb · obj · usd · mjcf · urdf · physics_sidecar · simready_glb · simready_fbx · simready_sidecar · texture · preview · …","title":"Kind","type":"string"},"path":{"description":"Where the file sits in the asset's deliverable folder, relative to it. A USD references its textures by these paths, so lay the files out this way to open it textured.","title":"Path","type":"string"},"url":{"description":"Presigned GET, valid for one hour.","title":"Url","type":"string"}},"required":["kind","path","url","expires_at"],"title":"AssetFileEntry","type":"object"},"AssetJobRef":{"description":"The asset's latest job, inlined. Assets have no status of their own.","properties":{"current_stage":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Current Stage"},"job_id":{"title":"Job Id","type":"string"},"progress":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Progress"},"status":{"title":"Status","type":"string"}},"required":["job_id","status"],"title":"AssetJobRef","type":"object"},"Problem":{"description":"An RFC 7807 error, the shape every failure uses.\n\nDeclared explicitly because the handlers replace FastAPI's default\nvalidation response; without this the spec would advertise\n`HTTPValidationError`, whose `detail` is a list rather than a string,\nand every generated client would crash parsing a 422.","properties":{"detail":{"description":"Human-readable explanation of this occurrence.","title":"Detail","type":"string"},"errors":{"anyOf":[{"items":{"$ref":"#/components/schemas/ValidationDetail"},"type":"array"},{"type":"null"}],"description":"Present on a 422; one entry per failing field.","title":"Errors"},"instance":{"description":"Identifies this occurrence; quote it to support.","title":"Instance","type":"string"},"path":{"title":"Path","type":"string"},"request_id":{"description":"Also returned in the X-Request-Id response header.","title":"Request Id","type":"string"},"status":{"title":"Status","type":"integer"},"title":{"title":"Title","type":"string"},"type":{"description":"Stable URI identifying the error class.","title":"Type","type":"string"}},"required":["type","title","status","detail","instance","path","request_id"],"title":"Problem","type":"object"},"ValidationDetail":{"description":"One field-level validation failure.","properties":{"loc":{"description":"Dotted path to the offending field.","title":"Loc","type":"string"},"msg":{"title":"Msg","type":"string"},"type":{"title":"Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationDetail","type":"object"}}},"paths":{"/v1/assets/{asset_id}":{"get":{"description":"Retrieve one asset, with fresh download URLs.\n\nThis is both the record and the download surface: every entry in\n`files` carries a presigned URL valid for one hour. Do not cache\nthose URLs — call this again to mint new ones.\n\nFiles appear only once the asset completes; there are no partial\ndownloads. Returns `404` if the asset does not exist or was\ndeleted.","operationId":"get_asset","parameters":[{"in":"path","name":"asset_id","required":true,"schema":{"title":"Asset Id","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssetDetail"}}},"description":"Successful Response"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Missing or invalid API token"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Request body too large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Request failed validation"}},"summary":"Get Asset","tags":["assets"]}}}}
```

## Delete Asset

> Delete an asset and its stored data.\
> \
> \`204\` on success, and idempotent — deleting an already-deleted\
> asset succeeds. Inputs and outputs are hard-deleted from S3\
> within 30 days; an ID, timestamps and a deletion record remain\
> for billing and audit.\
> \
> Returns \`409\` while a job is still running — wait for it to\
> finish. Also \`409\` for an asset created by a variation set,\
> whose provenance would silently break: delete the set instead.

```json
{"openapi":"3.1.0","info":{"title":"projectsim API","version":"1.0.0-beta"},"security":[{"ProjectSimToken":[]}],"components":{"securitySchemes":{"ProjectSimToken":{"bearerFormat":"kps_live_...","description":"A per-user API token. The tenant is the user, so no request body carries a user id. Tokens without the `kps_` prefix are rejected before any lookup.","scheme":"bearer","type":"http"}},"schemas":{"Problem":{"description":"An RFC 7807 error, the shape every failure uses.\n\nDeclared explicitly because the handlers replace FastAPI's default\nvalidation response; without this the spec would advertise\n`HTTPValidationError`, whose `detail` is a list rather than a string,\nand every generated client would crash parsing a 422.","properties":{"detail":{"description":"Human-readable explanation of this occurrence.","title":"Detail","type":"string"},"errors":{"anyOf":[{"items":{"$ref":"#/components/schemas/ValidationDetail"},"type":"array"},{"type":"null"}],"description":"Present on a 422; one entry per failing field.","title":"Errors"},"instance":{"description":"Identifies this occurrence; quote it to support.","title":"Instance","type":"string"},"path":{"title":"Path","type":"string"},"request_id":{"description":"Also returned in the X-Request-Id response header.","title":"Request Id","type":"string"},"status":{"title":"Status","type":"integer"},"title":{"title":"Title","type":"string"},"type":{"description":"Stable URI identifying the error class.","title":"Type","type":"string"}},"required":["type","title","status","detail","instance","path","request_id"],"title":"Problem","type":"object"},"ValidationDetail":{"description":"One field-level validation failure.","properties":{"loc":{"description":"Dotted path to the offending field.","title":"Loc","type":"string"},"msg":{"title":"Msg","type":"string"},"type":{"title":"Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationDetail","type":"object"}}},"paths":{"/v1/assets/{asset_id}":{"delete":{"description":"Delete an asset and its stored data.\n\n`204` on success, and idempotent — deleting an already-deleted\nasset succeeds. Inputs and outputs are hard-deleted from S3\nwithin 30 days; an ID, timestamps and a deletion record remain\nfor billing and audit.\n\nReturns `409` while a job is still running — wait for it to\nfinish. Also `409` for an asset created by a variation set,\nwhose provenance would silently break: delete the set instead.","operationId":"delete_asset","parameters":[{"in":"path","name":"asset_id","required":true,"schema":{"title":"Asset Id","type":"string"}}],"responses":{"204":{"description":"Successful Response"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Missing or invalid API token"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Request body too large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Request failed validation"}},"summary":"Delete Asset","tags":["assets"]}}}}
```
