> 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/variation-sets.md).

# Variation Sets

## Create High Fidelity Variation Set

> Order a high-fidelity variation set from one image, text, or both.\
> \
> Each member reconstructs a generated variation as its own asset.\
> \`seed.variation\_references\` accepts up to eight optional reference\
> images for style, palette or detail.\
> \
> Every member runs the full reconstruction pipeline, so it is the slower\
> path and costs per member, and it does not articulate. \`seed.text\`, when\
> given, is the image generator's custom prompt, and the set's \`name\`\
> grounds the generator's subject identification. \`params.physics.body\`\
> is \`rigid\` (default) or \`deformable\`. \`params.variation\` steers the image\
> generator.\
> \
> Returns \`202\` with a \`job\_id\` for the set. Exactly \`count\` member\
> assets are created at once, each with a stable \`variant\_index\` from 1\
> to \`count\`, and each is a full \`/v1/assets\` citizen. \`params\` apply to\
> every member, and each member freezes its own \`effective\_params\`.\
> \
> Limits: \`count\` 1–100, and at most 5 sets queued or running at once\
> (\`409\` beyond that). Every member counts toward an account's\
> asset limit, if it has one, so a set that would cross it is a \`429\`. Pass\
> \`Idempotency-Key\`: a timed-out retry without one duplicates the\
> entire order.

```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":{"CreateHighFidelityVariationSetRequest":{"additionalProperties":false,"properties":{"count":{"description":"How many variants, 1–100.","maximum":100,"minimum":1,"title":"Count","type":"integer"},"name":{"anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}],"title":"Name"},"params":{"anyOf":[{"$ref":"#/components/schemas/Params"},{"type":"null"}]},"seed":{"$ref":"#/components/schemas/HighFidelitySeed"}},"required":["count","seed"],"title":"CreateHighFidelityVariationSetRequest","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"},"HighFidelitySeed":{"additionalProperties":false,"properties":{"images":{"description":"One subject image. Provide an image, text, or both.","items":{"$ref":"#/components/schemas/ImageInput"},"maxItems":1,"title":"Images","type":"array"},"text":{"anyOf":[{"maxLength":2000,"minLength":1,"pattern":"\\S","type":"string"},{"type":"null"}],"description":"Subject description. Provide an image, text, or both.","title":"Text"},"variation_references":{"description":"Up to eight optional reference images to guide variations in style, palette or detail; these do not replace the subject.","items":{"$ref":"#/components/schemas/ImageInput"},"maxItems":8,"title":"Variation References","type":"array"}},"title":"HighFidelitySeed","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"},"CreateVariationSetResponse":{"properties":{"count":{"title":"Count","type":"integer"},"id":{"title":"Id","type":"string"},"job_id":{"title":"Job Id","type":"string"},"method":{"title":"Method","type":"string"},"status":{"title":"Status","type":"string"}},"required":["id","job_id","status","method","count"],"title":"CreateVariationSetResponse","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/variation-sets/high-fidelity":{"post":{"description":"Order a high-fidelity variation set from one image, text, or both.\n\nEach member reconstructs a generated variation as its own asset.\n`seed.variation_references` accepts up to eight optional reference\nimages for style, palette or detail.\n\nEvery member runs the full reconstruction pipeline, so it is the slower\npath and costs per member, and it does not articulate. `seed.text`, when\ngiven, is the image generator's custom prompt, and the set's `name`\ngrounds the generator's subject identification. `params.physics.body`\nis `rigid` (default) or `deformable`. `params.variation` steers the image\ngenerator.\n\nReturns `202` with a `job_id` for the set. Exactly `count` member\nassets are created at once, each with a stable `variant_index` from 1\nto `count`, and each is a full `/v1/assets` citizen. `params` apply to\nevery member, and each member freezes its own `effective_params`.\n\nLimits: `count` 1–100, and at most 5 sets queued or running at once\n(`409` beyond that). Every member counts toward an account's\nasset limit, if it has one, so a set that would cross it is a `429`. Pass\n`Idempotency-Key`: a timed-out retry without one duplicates the\nentire order.","operationId":"create_high_fidelity_variation_set","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/CreateHighFidelityVariationSetRequest"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateVariationSetResponse"}}},"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."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Idempotency key reused, or too many sets in flight"},"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"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Account asset limit reached"}},"summary":"Create High Fidelity Variation Set","tags":["variation-sets"]}}}}
```

## Create Procedural Variation Set

> Create related variants from one generated procedural object class.\
> \
> Use this endpoint for variations in shape, proportions and configuration\
> within one object family, especially geometric objects such as cabinets\
> and containers. A nonblank text brief is required; optionally include\
> a reference image alongside it.\
> \`params.physics.body\` is \`rigid\`; \`params.physics.articulated\` defaults\
> to \`true\` for moving parts, or set it to \`false\` for a jointless asset.\
> Each variant is sampled from the same generated class.\
> \
> Returns \`202\` with a set \`job\_id\`. Exactly \`count\` member assets are\
> created at once, with stable \`variant\_index\` values from 1 to \`count\`.\
> Body behavior and articulation are passed to class generation. This\
> pipeline currently authors rigid-body USD; simulator, collision, mesh,\
> texture and variation selections do not steer procedural generation.\
> \
> Limits: \`count\` 10–500, and at most 5 sets queued or running at once\
> (\`409\` beyond that). Every member counts toward an account's\
> asset limit, if it has one, so a set that would cross it is a \`429\`. Reuse an\
> \`Idempotency-Key\` when retrying the same request to avoid creating\
> another set.

```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":{"CreateProceduralVariationSetRequest":{"additionalProperties":false,"properties":{"count":{"description":"How many variants, 10–500.","maximum":500,"minimum":10,"title":"Count","type":"integer"},"name":{"anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}],"title":"Name"},"params":{"anyOf":[{"$ref":"#/components/schemas/ProceduralParams"},{"type":"null"}]},"seed":{"$ref":"#/components/schemas/ProceduralSeed"}},"required":["count","seed"],"title":"CreateProceduralVariationSetRequest","type":"object"},"ProceduralParams":{"additionalProperties":false,"properties":{"mesh":{"$ref":"#/components/schemas/MeshParams","default":{"quality":"standard"}},"physics":{"$ref":"#/components/schemas/ProceduralPhysicsParams","default":{"articulated":true,"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":"ProceduralParams","type":"object"},"MeshParams":{"additionalProperties":false,"properties":{"quality":{"default":"standard","enum":["standard","low","ultra_low"],"title":"Quality","type":"string"}},"title":"MeshParams","type":"object"},"ProceduralPhysicsParams":{"additionalProperties":false,"properties":{"articulated":{"default":true,"description":"Generate independently moving parts connected by joints. False requests a jointless rigid asset.","title":"Articulated","type":"boolean"},"body":{"const":"rigid","default":"rigid","description":"Procedural generation currently authors rigid bodies.","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":"ProceduralPhysicsParams","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"},"ProceduralSeed":{"additionalProperties":false,"properties":{"images":{"description":"A reference photo for the class generator.","items":{"$ref":"#/components/schemas/ImageInput"},"maxItems":1,"title":"Images","type":"array"},"text":{"description":"A brief for the class: what the object is, its parts and how they move, materials, rough size. Required and must contain non-whitespace text; optionally add a reference image.","maxLength":2000,"minLength":1,"pattern":"\\S","title":"Text","type":"string"}},"required":["text"],"title":"ProceduralSeed","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"},"CreateVariationSetResponse":{"properties":{"count":{"title":"Count","type":"integer"},"id":{"title":"Id","type":"string"},"job_id":{"title":"Job Id","type":"string"},"method":{"title":"Method","type":"string"},"status":{"title":"Status","type":"string"}},"required":["id","job_id","status","method","count"],"title":"CreateVariationSetResponse","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/variation-sets/procedural":{"post":{"description":"Create related variants from one generated procedural object class.\n\nUse this endpoint for variations in shape, proportions and configuration\nwithin one object family, especially geometric objects such as cabinets\nand containers. A nonblank text brief is required; optionally include\na reference image alongside it.\n`params.physics.body` is `rigid`; `params.physics.articulated` defaults\nto `true` for moving parts, or set it to `false` for a jointless asset.\nEach variant is sampled from the same generated class.\n\nReturns `202` with a set `job_id`. Exactly `count` member assets are\ncreated at once, with stable `variant_index` values from 1 to `count`.\nBody behavior and articulation are passed to class generation. This\npipeline currently authors rigid-body USD; simulator, collision, mesh,\ntexture and variation selections do not steer procedural generation.\n\nLimits: `count` 10–500, and at most 5 sets queued or running at once\n(`409` beyond that). Every member counts toward an account's\nasset limit, if it has one, so a set that would cross it is a `429`. Reuse an\n`Idempotency-Key` when retrying the same request to avoid creating\nanother set.","operationId":"create_procedural_variation_set","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/CreateProceduralVariationSetRequest"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateVariationSetResponse"}}},"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."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Idempotency key reused, or too many sets in flight"},"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"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Account asset limit reached"}},"summary":"Create Procedural Variation Set","tags":["variation-sets"]}}}}
```

## Get Variation Set

> Retrieve a variation set — live progress and download pointers.\
> \
> The poll surface for a set. \`counts\` is derived from the member\
> jobs on every read, so it never drifts.\
> \
> \`manifest\` is null until the set is terminal, then it is the\
> permanent table of contents: every shipped file by key, with\
> size and checksum, so you can cache it, diff it and verify\
> against it. \`bundle.state\` is \`none\`, \`pending\` or \`ready\`, and a\
> ready bundle carries a URL valid for 24 hours.\
> \
> A set may finish \`partial\`, meaning some members failed.

```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":{"VariationSetDetail":{"properties":{"bundle":{"$ref":"#/components/schemas/BundleState"},"count":{"title":"Count","type":"integer"},"counts":{"$ref":"#/components/schemas/MemberCounts"},"created_at":{"format":"date-time","title":"Created At","type":"string"},"id":{"title":"Id","type":"string"},"manifest":{"anyOf":[{"$ref":"#/components/schemas/ManifestRef"},{"type":"null"}],"description":"Null until the set is terminal."},"method":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Method"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The set job's status. `partial` means some members failed.","title":"Status"}},"required":["id","count","created_at","counts","bundle"],"title":"VariationSetDetail","type":"object"},"BundleState":{"properties":{"expires_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"title":"Expires At"},"state":{"description":"none · pending · ready","title":"State","type":"string"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Set once ready; valid for 24 hours.","title":"Url"}},"required":["state"],"title":"BundleState","type":"object"},"MemberCounts":{"description":"Derived from the member jobs on every read, so it never drifts.","properties":{"canceled":{"default":0,"title":"Canceled","type":"integer"},"complete":{"title":"Complete","type":"integer"},"failed":{"title":"Failed","type":"integer"},"queued":{"title":"Queued","type":"integer"},"requested":{"title":"Requested","type":"integer"},"running":{"title":"Running","type":"integer"}},"required":["requested","queued","running","complete","failed"],"title":"MemberCounts","type":"object"},"ManifestRef":{"properties":{"expires_at":{"format":"date-time","title":"Expires At","type":"string"},"url":{"description":"Presigned GET, valid for 24 hours.","title":"Url","type":"string"}},"required":["url","expires_at"],"title":"ManifestRef","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/variation-sets/{set_id}":{"get":{"description":"Retrieve a variation set — live progress and download pointers.\n\nThe poll surface for a set. `counts` is derived from the member\njobs on every read, so it never drifts.\n\n`manifest` is null until the set is terminal, then it is the\npermanent table of contents: every shipped file by key, with\nsize and checksum, so you can cache it, diff it and verify\nagainst it. `bundle.state` is `none`, `pending` or `ready`, and a\nready bundle carries a URL valid for 24 hours.\n\nA set may finish `partial`, meaning some members failed.","operationId":"get_variation_set","parameters":[{"in":"path","name":"set_id","required":true,"schema":{"title":"Set Id","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VariationSetDetail"}}},"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 Variation Set","tags":["variation-sets"]}}}}
```

## Delete Variation Set

> Delete a variation set and all of its members.\
> \
> \`204\`, and idempotent. Returns \`409\` while the set's job is still\
> active.\
> \
> This is the only way to remove an asset belonging to a set —\
> individual members cannot be 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":{"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/variation-sets/{set_id}":{"delete":{"description":"Delete a variation set and all of its members.\n\n`204`, and idempotent. Returns `409` while the set's job is still\nactive.\n\nThis is the only way to remove an asset belonging to a set —\nindividual members cannot be deleted.","operationId":"delete_variation_set","parameters":[{"in":"path","name":"set_id","required":true,"schema":{"title":"Set 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 Variation Set","tags":["variation-sets"]}}}}
```

## List Members

> List a set's member assets, with their download URLs.\
> \
> The primary way to pull a set: each member's \`files\` arrive with\
> presigned URLs valid for 24 hours, so you can page through and\
> download members in parallel.\
> \
> Ordered by \`variant\_index\`; the cursor is the last index you saw.\
> \`status\` filters on the member's own job. Indexes are never\
> renumbered, so gaps in a \`partial\` set stay legible and a\
> specific member can be re-fetched reliably.

```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":{"MemberListResponse":{"properties":{"members":{"items":{"$ref":"#/components/schemas/MemberEntry"},"title":"Members","type":"array"},"next_cursor":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"The last variant_index of this page; null when done.","title":"Next Cursor"}},"required":["members"],"title":"MemberListResponse","type":"object"},"MemberEntry":{"properties":{"asset_id":{"title":"Asset Id","type":"string"},"files":{"items":{"$ref":"#/components/schemas/MemberFileEntry"},"title":"Files","type":"array"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"variant_index":{"description":"Stable label, 1..count. Never renumbered.","title":"Variant Index","type":"integer"}},"required":["variant_index","asset_id","files"],"title":"MemberEntry","type":"object"},"MemberFileEntry":{"description":"A member's deliverable with a fresh download URL.","properties":{"expires_at":{"format":"date-time","title":"Expires At","type":"string"},"kind":{"title":"Kind","type":"string"},"path":{"description":"Where the file sits in the member'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 24 hours.","title":"Url","type":"string"}},"required":["kind","path","url","expires_at"],"title":"MemberFileEntry","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/variation-sets/{set_id}/assets":{"get":{"description":"List a set's member assets, with their download URLs.\n\nThe primary way to pull a set: each member's `files` arrive with\npresigned URLs valid for 24 hours, so you can page through and\ndownload members in parallel.\n\nOrdered by `variant_index`; the cursor is the last index you saw.\n`status` filters on the member's own job. Indexes are never\nrenumbered, so gaps in a `partial` set stay legible and a\nspecific member can be re-fetched reliably.","operationId":"list_members","parameters":[{"in":"path","name":"set_id","required":true,"schema":{"title":"Set Id","type":"string"}},{"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":[{"minimum":1,"type":"integer"},{"type":"null"}],"title":"Cursor"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberListResponse"}}},"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 Members","tags":["variation-sets"]}}}}
```

## Request Bundle

> Build a single ZIP of the set's deliverables.\
> \
> Returns \`202\` and no URL — the build is asynchronous. Poll\
> \`bundle\` on the set, or wait for \`variation\_set.bundle\_ready\`\
> (or \`variation\_set.bundle\_failed\`).\
> Calling this again while a build is pending or already ready\
> returns the current state rather than rebuilding.\
> \
> Bundles are derived artefacts, built only when requested; the\
> member files are the durable record.

```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":{"BundleRequest":{"additionalProperties":false,"properties":{"format":{"const":"zip","default":"zip","title":"Format","type":"string"}},"title":"BundleRequest","type":"object"},"BundleResponse":{"properties":{"job_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Present when this call started the build.","title":"Job Id"},"state":{"description":"none · pending · ready","title":"State","type":"string"}},"required":["state"],"title":"BundleResponse","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/variation-sets/{set_id}/bundle":{"post":{"description":"Build a single ZIP of the set's deliverables.\n\nReturns `202` and no URL — the build is asynchronous. Poll\n`bundle` on the set, or wait for `variation_set.bundle_ready`\n(or `variation_set.bundle_failed`).\nCalling this again while a build is pending or already ready\nreturns the current state rather than rebuilding.\n\nBundles are derived artefacts, built only when requested; the\nmember files are the durable record.","operationId":"request_bundle","parameters":[{"in":"path","name":"set_id","required":true,"schema":{"title":"Set Id","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BundleRequest"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BundleResponse"}}},"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":"Request Bundle","tags":["variation-sets"]}}}}
```
