{
  "components": {
    "headers": {
      "RateLimit": {
        "description": "What is left of each window, `\"<policy>\";r=<remaining>;t=<seconds until it starts over>`.",
        "schema": {
          "type": "string"
        }
      },
      "RateLimit-Limit": {
        "description": "The limit of the window closest to running out.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimit-Policy": {
        "description": "Every window this request was counted in, `\"<policy>\";q=<limit>;w=<seconds>` (draft-ietf-httpapi-ratelimit-headers-11).",
        "schema": {
          "type": "string"
        }
      },
      "RateLimit-Remaining": {
        "description": "What is left of that window.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimit-Reset": {
        "description": "Seconds until that window starts over.",
        "schema": {
          "type": "integer"
        }
      },
      "Retry-After": {
        "description": "Seconds to wait before sending it again.",
        "schema": {
          "type": "integer"
        }
      }
    },
    "parameters": {
      "GameId": {
        "in": "path",
        "name": "game_id",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/GameId"
        }
      },
      "JobId": {
        "in": "path",
        "name": "job_id",
        "required": true,
        "schema": {
          "format": "uuid",
          "type": "string"
        }
      },
      "Tool": {
        "in": "path",
        "name": "tool",
        "required": true,
        "schema": {
          "enum": [
            "generate_image",
            "generate_sprite",
            "edit_image",
            "generate_spritesheet",
            "generate_sound",
            "generate_music",
            "cast_voice",
            "voice_line",
            "dialogue",
            "generate_3d_model",
            "generate_skybox",
            "find_material",
            "get_material",
            "inspect_model",
            "optimize_model",
            "fracture_model",
            "lod_model",
            "rig_model",
            "render_model",
            "finalize_model",
            "build_level",
            "author_skin",
            "retexture_model",
            "generate_video",
            "edit_video",
            "lip_sync",
            "cutout",
            "upscale",
            "transcribe_words",
            "caption_video",
            "split_stems",
            "isolate_voice",
            "beat_grid",
            "mask_subject",
            "make_shorts",
            "search_footage",
            "detect_chords",
            "backing_track",
            "brand_kit",
            "resize_design",
            "make_deck",
            "list_characters",
            "get_character",
            "restyle_character",
            "author_motion",
            "retarget_clips",
            "review",
            "play"
          ],
          "type": "string"
        }
      }
    },
    "responses": {
      "RateLimited": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "description": "A window is full: `rate_limited` (requests), `submit_rate_limited` (jobs started),\n`kind_rate_limited` (video and 3D, or pictures; `family` says which) or\n`too_many_jobs` (queued or running at once). Nothing was held or charged.\n",
        "headers": {
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "RateLimit-Limit": {
            "$ref": "#/components/headers/RateLimit-Limit"
          },
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimit-Policy"
          },
          "RateLimit-Remaining": {
            "$ref": "#/components/headers/RateLimit-Remaining"
          },
          "RateLimit-Reset": {
            "$ref": "#/components/headers/RateLimit-Reset"
          },
          "Retry-After": {
            "$ref": "#/components/headers/Retry-After"
          }
        }
      },
      "Refusal": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "description": "A refusal or a failure; clients branch on `code`."
      }
    },
    "schemas": {
      "ApiKey": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "display_prefix": {
            "type": "string"
          },
          "expires_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "last_used_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "monthly_credit_cap": {
            "type": [
              "integer",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "scopes": {
            "items": {
              "$ref": "#/components/schemas/Scope"
            },
            "type": "array"
          }
        },
        "required": [
          "id",
          "name",
          "display_prefix",
          "scopes",
          "expires_at",
          "last_used_at",
          "created_at",
          "monthly_credit_cap"
        ],
        "type": "object"
      },
      "Batch": {
        "properties": {
          "batch_key": {
            "type": "string"
          },
          "created": {
            "type": "integer"
          },
          "estimate_credits": {
            "type": "integer"
          },
          "existing": {
            "type": "integer"
          },
          "items": {
            "items": {
              "properties": {
                "created": {
                  "type": "boolean"
                },
                "error": {
                  "$ref": "#/components/schemas/Error"
                },
                "estimate_credits": {
                  "type": "integer"
                },
                "job_id": {
                  "format": "uuid",
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "retries": {
                  "description": "Earlier failed jobs of this same content that ran again.",
                  "type": "integer"
                },
                "skipped": {
                  "type": "boolean"
                },
                "status": {
                  "$ref": "#/components/schemas/JobStatus"
                }
              },
              "required": [
                "name",
                "created"
              ],
              "type": "object"
            },
            "type": "array"
          },
          "notes": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "refused": {
            "type": "integer"
          },
          "style_source": {
            "enum": [
              "game",
              "manifest",
              "none"
            ],
            "type": "string"
          }
        },
        "required": [
          "batch_key",
          "estimate_credits",
          "style_source",
          "created",
          "existing",
          "refused",
          "items"
        ],
        "type": "object"
      },
      "CapturedView": {
        "properties": {
          "entered": {
            "type": "boolean"
          },
          "front_door": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/FrontDoor"
              },
              {
                "type": "null"
              }
            ]
          },
          "game_id": {
            "$ref": "#/components/schemas/GameId"
          },
          "height": {
            "type": "integer"
          },
          "jpeg_base64": {
            "type": [
              "string",
              "null"
            ]
          },
          "preview_url": {
            "type": "string"
          },
          "touch": {
            "type": "boolean"
          },
          "view": {
            "$ref": "#/components/schemas/DrivenView"
          },
          "width": {
            "type": "integer"
          }
        },
        "required": [
          "game_id",
          "preview_url",
          "entered",
          "view"
        ],
        "type": "object"
      },
      "Check": {
        "additionalProperties": true,
        "properties": {
          "verdict": {
            "$ref": "#/components/schemas/Verdict"
          }
        },
        "required": [
          "verdict"
        ],
        "type": "object"
      },
      "Click": {
        "description": "Press this control first, like a player pressing Play: `true` for the convention,\n`[data-fpx-start]`, or a CSS selector (at most 200 characters).\n",
        "oneOf": [
          {
            "type": "boolean"
          },
          {
            "maxLength": 200,
            "type": "string"
          }
        ]
      },
      "ClipAudit": {
        "properties": {
          "clips": {
            "items": {
              "properties": {
                "drives_armature": {
                  "type": "boolean"
                },
                "fcurves": {
                  "type": "integer"
                },
                "findings": {
                  "items": {
                    "type": "string"
                  },
                  "type": "array"
                },
                "foot_slide_m": {
                  "description": "-1 = no foot bones.",
                  "type": "number"
                },
                "frame_end": {
                  "type": "number"
                },
                "frame_start": {
                  "type": "number"
                },
                "ground_speed_mps": {
                  "description": "Move the body at this speed and a planted foot stays put; -1 = not locomotion.",
                  "type": "number"
                },
                "in_place": {
                  "type": "boolean"
                },
                "locomotion": {
                  "type": "boolean"
                },
                "loop_seam_deg": {
                  "description": "The largest bone turn between the last frame and the first.",
                  "type": "number"
                },
                "max_rotation_deg": {
                  "type": "number"
                },
                "name": {
                  "type": "string"
                },
                "root_motion_m": {
                  "description": "-1 = not measured.",
                  "type": "number"
                },
                "root_rise_m": {
                  "type": "number"
                },
                "seconds": {
                  "type": "number"
                },
                "static_pose": {
                  "type": "boolean"
                }
              },
              "required": [
                "name",
                "drives_armature",
                "seconds",
                "static_pose",
                "root_motion_m",
                "in_place",
                "foot_slide_m",
                "findings"
              ],
              "type": "object"
            },
            "type": "array"
          },
          "clips_total": {
            "type": "integer"
          },
          "error": {
            "type": "string"
          },
          "expected": {
            "properties": {
              "matched": {
                "items": {
                  "properties": {
                    "clip": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    }
                  },
                  "type": "object"
                },
                "type": "array"
              },
              "missing": {
                "items": {
                  "type": "string"
                },
                "type": "array"
              }
            },
            "type": "object"
          },
          "findings": {
            "and each expected name no clip answers to.": null,
            "description": "Every clip's findings",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "foot_bones": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "fps": {
            "type": "number"
          },
          "measured": {
            "description": "false = nothing below was measured; `error` says why.",
            "type": "boolean"
          },
          "rig_height_m": {
            "type": "number"
          },
          "root_bone": {
            "type": "string"
          }
        },
        "required": [
          "measured"
        ],
        "type": "object"
      },
      "ClipAuditInput": {
        "additionalProperties": false,
        "properties": {
          "asset_id": {
            "description": "A model a job of yours made.",
            "format": "uuid",
            "type": "string"
          },
          "expected": {
            "description": "Clip names your code plays; a pack's `Rig|Alien_Walk` answers to `walk`.",
            "items": {
              "maxLength": 64,
              "minLength": 1,
              "type": "string"
            },
            "maxItems": 32,
            "type": "array"
          },
          "model_base64": {
            "description": "The model (GLB, glTF or FBX, at most 12 MB). Or `asset_id`.",
            "type": "string"
          }
        },
        "type": "object"
      },
      "CommunityGame": {
        "additionalProperties": true,
        "description": "One game as every public surface sends it. `viewer` is the caller's; `community` is the owner's one word.\n",
        "properties": {
          "community": {
            "enum": [
              "listed",
              "pending",
              "off",
              "removed"
            ],
            "type": "string"
          },
          "counts": {
            "properties": {
              "comments": {
                "type": "integer"
              },
              "plays": {
                "type": "integer"
              },
              "remixes": {
                "type": "integer"
              },
              "stars": {
                "type": "integer"
              },
              "views": {
                "type": "integer"
              }
            },
            "required": [
              "stars",
              "plays",
              "remixes",
              "comments",
              "views"
            ],
            "type": "object"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "display_title": {
            "type": [
              "string",
              "null"
            ]
          },
          "framework": {
            "type": [
              "string",
              "null"
            ]
          },
          "game_id": {
            "$ref": "#/components/schemas/GameId"
          },
          "genre": {
            "type": [
              "string",
              "null"
            ]
          },
          "listed_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "meta": {
            "type": [
              "object",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "owner": {
            "properties": {
              "avatar_url": {
                "type": "string"
              },
              "display_name": {
                "type": "string"
              },
              "username": {
                "type": "string"
              }
            },
            "required": [
              "username"
            ],
            "type": "object"
          },
          "play_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "poster_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "remixed_from": {
            "properties": {
              "game_id": {
                "$ref": "#/components/schemas/GameId"
              },
              "name": {
                "type": "string"
              }
            },
            "required": [
              "name",
              "game_id"
            ],
            "type": "object"
          },
          "screenshot_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "slug": {
            "type": [
              "string",
              "null"
            ]
          },
          "thumbnail_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "updated_at": {
            "type": "string"
          },
          "viewer": {
            "properties": {
              "can_remix": {
                "type": "boolean"
              },
              "follows_owner": {
                "type": "boolean"
              },
              "owns": {
                "type": "boolean"
              },
              "starred": {
                "type": "boolean"
              }
            },
            "required": [
              "starred",
              "owns",
              "follows_owner",
              "can_remix"
            ],
            "type": "object"
          }
        },
        "required": [
          "game_id",
          "name",
          "counts",
          "owner",
          "viewer"
        ],
        "type": "object"
      },
      "Credits": {
        "additionalProperties": true,
        "description": "The account's credits; `balance` and `plan` are stable.",
        "properties": {
          "balance": {
            "type": "integer"
          },
          "plan": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "Deliveries": {
        "properties": {
          "deliveries": {
            "items": {
              "$ref": "#/components/schemas/Delivery"
            },
            "type": "array"
          },
          "job_id": {
            "format": "uuid",
            "type": "string"
          },
          "webhook_url": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "job_id",
          "webhook_url",
          "deliveries"
        ],
        "type": "object"
      },
      "Delivery": {
        "properties": {
          "attempts": {
            "items": {
              "$ref": "#/components/schemas/DeliveryAttempt"
            },
            "type": "array"
          },
          "delivery": {
            "minimum": 1,
            "type": "integer"
          },
          "state": {
            "description": "Its last attempt's state.",
            "type": "string"
          }
        },
        "required": [
          "delivery",
          "state",
          "attempts"
        ],
        "type": "object"
      },
      "DeliveryAttempt": {
        "properties": {
          "attempt": {
            "maximum": 4,
            "minimum": 1,
            "type": "integer"
          },
          "attempted_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "due_at": {
            "format": "date-time",
            "type": "string"
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "finished_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "state": {
            "description": "`failed` = the next attempt is queued; `gave_up` = nothing more is tried.",
            "enum": [
              "pending",
              "sending",
              "delivered",
              "failed",
              "gave_up"
            ],
            "type": "string"
          },
          "status_code": {
            "description": "The receiver's HTTP status",
            "type": [
              "integer",
              "null"
            ],
            "when it answered.": null
          }
        },
        "required": [
          "attempt",
          "state",
          "due_at",
          "attempted_at",
          "finished_at",
          "status_code",
          "error"
        ],
        "type": "object"
      },
      "Draft": {
        "properties": {
          "game_id": {
            "$ref": "#/components/schemas/GameId"
          },
          "name": {
            "type": "string"
          },
          "project_id": {
            "format": "uuid",
            "type": "string"
          },
          "status": {
            "const": "draft",
            "type": "string"
          }
        },
        "required": [
          "game_id",
          "project_id",
          "name",
          "status"
        ],
        "type": "object"
      },
      "DraftBuild": {
        "properties": {
          "code": {
            "type": "string"
          },
          "content_key": {
            "type": "string"
          },
          "error": {
            "type": "string"
          },
          "files": {
            "type": "integer"
          },
          "game_id": {
            "$ref": "#/components/schemas/GameId"
          },
          "log_tail": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "note": {
            "type": "string"
          },
          "preview_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "skipped_empty": {
            "type": "integer"
          },
          "status": {
            "enum": [
              "succeeded",
              "failed"
            ],
            "type": "string"
          }
        },
        "required": [
          "game_id",
          "status",
          "content_key",
          "files",
          "log_tail"
        ],
        "type": "object"
      },
      "DrivenView": {
        "description": "The capture's answer.",
        "properties": {
          "declared": {
            "type": "boolean"
          },
          "entered": {
            "type": "boolean"
          },
          "error": {
            "type": "string"
          },
          "frozen": {
            "type": "boolean"
          },
          "missing": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "state": {
            "description": "__FPX_STATE__() after the hold; null when not declared."
          },
          "verbs": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "view": {
            "type": [
              "string",
              "null"
            ]
          },
          "views": {
            "items": {
              "properties": {
                "motion": {
                  "type": "boolean"
                },
                "name": {
                  "type": "string"
                }
              },
              "type": "object"
            },
            "type": "array"
          }
        },
        "type": "object"
      },
      "Error": {
        "additionalProperties": true,
        "properties": {
          "code": {
            "type": "string"
          },
          "error": {
            "type": "string"
          },
          "family": {
            "description": "Which window a `kind_rate_limited` counted in.",
            "enum": [
              "video_3d",
              "images"
            ],
            "type": "string"
          },
          "limit": {
            "description": "A rate refusal's limit.",
            "type": "integer"
          },
          "retry_after_seconds": {
            "description": "`Retry-After`, in the body.",
            "type": "integer"
          },
          "window_seconds": {
            "description": "A rate refusal's window.",
            "type": "integer"
          }
        },
        "type": "object"
      },
      "Estimate": {
        "properties": {
          "confirm_threshold_credits": {
            "type": "integer"
          },
          "estimate_credits": {
            "type": "integer"
          },
          "requires_confirmation": {
            "type": "boolean"
          },
          "tool": {
            "type": "string"
          }
        },
        "required": [
          "tool",
          "estimate_credits",
          "confirm_threshold_credits",
          "requires_confirmation"
        ],
        "type": "object"
      },
      "FollowAnswer": {
        "properties": {
          "followers_count": {
            "type": "integer"
          },
          "success": {
            "type": "boolean"
          }
        },
        "type": "object"
      },
      "FrontDoor": {
        "properties": {
          "changed": {
            "description": "null = could not be told.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "error": {
            "type": "string"
          },
          "found": {
            "type": "boolean"
          },
          "name": {
            "type": "string"
          },
          "pressed": {
            "type": "boolean"
          },
          "screen_after": {
            "type": [
              "string",
              "null"
            ]
          },
          "screen_before": {
            "type": [
              "string",
              "null"
            ]
          },
          "selector": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "GameId": {
        "pattern": "^[0-9a-f]{32}$",
        "type": "string"
      },
      "Job": {
        "properties": {
          "charged_credits": {
            "type": "integer"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "error": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "properties": {
                  "code": {
                    "type": "string"
                  },
                  "message": {
                    "type": "string"
                  }
                },
                "required": [
                  "code",
                  "message"
                ],
                "type": "object"
              }
            ]
          },
          "estimate_credits": {
            "type": "integer"
          },
          "finished_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "input": {
            "additionalProperties": true,
            "type": "object"
          },
          "job_id": {
            "format": "uuid",
            "type": "string"
          },
          "outputs": {
            "items": {
              "$ref": "#/components/schemas/JobAsset"
            },
            "type": "array"
          },
          "own_key": {
            "description": "Ran on the account's own provider key; held and charged nothing.",
            "type": "boolean"
          },
          "result": {},
          "started_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "$ref": "#/components/schemas/JobStatus"
          },
          "tool": {
            "type": "string"
          },
          "waived_credits": {
            "type": "integer"
          },
          "waived_reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "webhook_secret": {
            "description": "The job's webhook signing secret (`whsec_…`). On the submit response only, never on a read.",
            "type": "string"
          },
          "webhook_url": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "job_id",
          "tool",
          "status",
          "input",
          "estimate_credits",
          "charged_credits",
          "waived_credits",
          "waived_reason",
          "own_key",
          "webhook_url",
          "outputs",
          "result",
          "error",
          "created_at",
          "started_at",
          "finished_at"
        ],
        "type": "object"
      },
      "JobAsset": {
        "properties": {
          "asset_id": {
            "format": "uuid",
            "type": "string"
          },
          "content_type": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "provenance": {
            "additionalProperties": true,
            "type": "object"
          },
          "size_bytes": {
            "type": "integer"
          },
          "url": {
            "description": "Presigned, good for an hour.",
            "type": [
              "string",
              "null"
            ]
          },
          "url_expires_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "asset_id",
          "name",
          "content_type",
          "size_bytes",
          "url",
          "url_expires_at",
          "provenance"
        ],
        "type": "object"
      },
      "JobPage": {
        "properties": {
          "jobs": {
            "description": "Newest first. A listed job never carries `webhook_secret`.",
            "items": {
              "$ref": "#/components/schemas/Job"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "Pass as `cursor` for the next page; null = this was the last.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "jobs",
          "next_cursor"
        ],
        "type": "object"
      },
      "JobStatus": {
        "enum": [
          "queued",
          "running",
          "succeeded",
          "failed",
          "cancelled"
        ],
        "type": "string"
      },
      "JudgeInput": {
        "additionalProperties": false,
        "description": "One of `image_base64` (at most 12 MB, 4096 px a side) or `asset_id`.",
        "properties": {
          "asset_id": {
            "format": "uuid",
            "type": "string"
          },
          "backdrop": {
            "enum": [
              "green",
              "magenta"
            ],
            "type": "string"
          },
          "game_id": {
            "$ref": "#/components/schemas/GameId"
          },
          "image_base64": {
            "contentEncoding": "base64",
            "type": "string"
          },
          "palette": {
            "items": {
              "pattern": "^#[0-9a-fA-F]{6}$",
              "type": "string"
            },
            "maxItems": 16,
            "type": "array"
          },
          "role": {
            "enum": [
              "character",
              "part",
              "face",
              "effect",
              "ui_icon",
              "prop",
              "tile",
              "strip",
              "key_art",
              "background"
            ],
            "type": "string"
          },
          "transparent": {
            "description": "accept_asset only",
            "type": "boolean"
          },
          "trim": {
            "description": "Default true for key_sprite",
            "false for accept_asset.": null,
            "type": "boolean"
          },
          "trim_pad": {
            "default": 2,
            "maximum": 64,
            "minimum": 0,
            "type": "integer"
          }
        },
        "type": "object"
      },
      "Judged": {
        "properties": {
          "bytes": {
            "type": "integer"
          },
          "cause": {
            "type": [
              "string",
              "null"
            ]
          },
          "content_type": {
            "type": "string"
          },
          "cutout": {
            "type": "boolean"
          },
          "keyed_by": {
            "type": [
              "string",
              "null"
            ]
          },
          "measurements": {
            "additionalProperties": true,
            "type": [
              "object",
              "null"
            ]
          },
          "message": {
            "type": [
              "string",
              "null"
            ]
          },
          "notes": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "png_base64": {
            "contentEncoding": "base64",
            "description": "Present when accepted.",
            "type": "string"
          },
          "role": {
            "type": "string"
          },
          "trimmed": {
            "properties": {
              "height": {
                "type": "integer"
              },
              "width": {
                "type": "integer"
              },
              "x": {
                "type": "integer"
              },
              "y": {
                "type": "integer"
              }
            },
            "type": [
              "object",
              "null"
            ]
          },
          "verdict": {
            "enum": [
              "accept",
              "reject"
            ],
            "type": "string"
          }
        },
        "required": [
          "verdict",
          "role",
          "cutout",
          "notes"
        ],
        "type": "object"
      },
      "LookInput": {
        "additionalProperties": false,
        "properties": {
          "click": {
            "$ref": "#/components/schemas/Click"
          },
          "height": {
            "default": 844,
            "maximum": 2560,
            "minimum": 200,
            "type": "integer"
          },
          "hold_ms": {
            "default": 600,
            "maximum": 5000,
            "minimum": 0,
            "type": "integer"
          },
          "touch": {
            "default": true,
            "type": "boolean"
          },
          "verbs": {
            "items": {
              "pattern": "^[A-Za-z0-9_.-]{1,64}$",
              "type": "string"
            },
            "maxItems": 6,
            "type": "array"
          },
          "view": {
            "description": "Omit for the page as loaded.",
            "pattern": "^[A-Za-z0-9_.-]{1,64}$",
            "type": "string"
          },
          "width": {
            "default": 390,
            "maximum": 2560,
            "minimum": 200,
            "type": "integer"
          }
        },
        "type": "object"
      },
      "MobileCheck": {
        "properties": {
          "desktop": {
            "properties": {
              "fps_p95": {
                "type": [
                  "number",
                  "null"
                ]
              }
            },
            "type": "object"
          },
          "failures": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "frames": {
            "items": {
              "$ref": "#/components/schemas/MobileFrame"
            },
            "type": "array"
          },
          "game_id": {
            "$ref": "#/components/schemas/GameId"
          },
          "notes": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "preview_url": {
            "type": "string"
          },
          "verdict": {
            "$ref": "#/components/schemas/Verdict"
          }
        },
        "required": [
          "game_id",
          "preview_url",
          "verdict",
          "desktop",
          "frames",
          "failures",
          "notes"
        ],
        "type": "object"
      },
      "MobileFrame": {
        "properties": {
          "controls": {
            "$ref": "#/components/schemas/Check"
          },
          "device": {
            "type": "string"
          },
          "drew": {
            "$ref": "#/components/schemas/Check"
          },
          "error": {
            "description": "Why the frame was not observed.",
            "type": "string"
          },
          "fps": {
            "$ref": "#/components/schemas/Check"
          },
          "height": {
            "type": "integer"
          },
          "hud": {
            "$ref": "#/components/schemas/Check"
          },
          "orientation": {
            "enum": [
              "portrait",
              "landscape"
            ],
            "type": "string"
          },
          "targets": {
            "$ref": "#/components/schemas/Check"
          },
          "verdict": {
            "$ref": "#/components/schemas/Verdict"
          },
          "width": {
            "type": "integer"
          }
        },
        "required": [
          "device",
          "orientation",
          "width",
          "height",
          "verdict"
        ],
        "type": "object"
      },
      "Model": {
        "properties": {
          "aliases": {
            "description": "Older names that still resolve.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "available": {
            "type": "boolean"
          },
          "caps": {
            "additionalProperties": true,
            "description": "What the model takes (aspect ratios, references, seconds, rig…).",
            "type": "object"
          },
          "fallback": {
            "description": "What the pick falls back to when no model is named.",
            "type": "string"
          },
          "id": {
            "description": "The name `model` takes.",
            "type": "string"
          },
          "kind": {
            "enum": [
              "image",
              "image_edit",
              "sound",
              "music",
              "voice",
              "video",
              "video_edit",
              "lip_sync",
              "model3d",
              "skybox"
            ],
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "one_line": {
            "type": "string"
          },
          "plan": {
            "enum": [
              "any",
              "paid"
            ],
            "type": "string"
          },
          "price_rows": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "prices": {
            "items": {
              "properties": {
                "credits": {
                  "type": "integer"
                },
                "row": {
                  "type": "string"
                }
              },
              "required": [
                "row",
                "credits"
              ],
              "type": "object"
            },
            "type": "array"
          },
          "reason": {
            "description": "With plan paid, the sentence a free plan is refused with.",
            "type": "string"
          },
          "recommended": {
            "description": "Our pick for its kind; omitting `model` runs it.",
            "type": "boolean"
          },
          "runs": {
            "properties": {
              "needs": {
                "type": "string"
              },
              "runner": {
                "type": "string"
              },
              "where": {
                "enum": [
                  "hosted",
                  "local"
                ],
                "type": "string"
              }
            },
            "required": [
              "where"
            ],
            "type": "object"
          }
        },
        "required": [
          "id",
          "kind",
          "label",
          "one_line",
          "runs",
          "recommended",
          "caps",
          "price_rows",
          "plan",
          "available",
          "prices"
        ],
        "type": "object"
      },
      "Models": {
        "properties": {
          "models": {
            "items": {
              "$ref": "#/components/schemas/Model"
            },
            "type": "array"
          }
        },
        "required": [
          "models"
        ],
        "type": "object"
      },
      "PlayAnswer": {
        "properties": {
          "answer": {
            "enum": [
              "yes",
              "no",
              "unclear"
            ],
            "type": "string"
          },
          "note": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "PlayInput": {
        "additionalProperties": false,
        "properties": {
          "confirm_cost": {
            "type": "boolean"
          },
          "criteria": {
            "items": {
              "maxLength": 300,
              "minLength": 1,
              "type": "string"
            },
            "maxItems": 12,
            "type": "array"
          },
          "game_id": {
            "$ref": "#/components/schemas/GameId"
          },
          "max_acts": {
            "default": 16,
            "maximum": 30,
            "minimum": 1,
            "type": "integer"
          },
          "orientation": {
            "description": "Turn the phone from the game's own orientation.",
            "enum": [
              "portrait",
              "landscape"
            ],
            "type": "string"
          },
          "premise": {
            "maxLength": 1500,
            "minLength": 40,
            "type": "string"
          },
          "viewport": {
            "default": "phone",
            "enum": [
              "phone",
              "desktop"
            ],
            "type": "string"
          },
          "webhook_url": {
            "pattern": "^https://",
            "type": "string"
          }
        },
        "required": [
          "game_id"
        ],
        "type": "object"
      },
      "PlayResult": {
        "description": "A succeeded `play` job's `result` (also its `report.json` output): the report `funtools play\nreport` files, plus how the round went. Its outputs are `report.json` and one `act-NN.jpg` per act.\n",
        "properties": {
          "act": {
            "$ref": "#/components/schemas/PlayAnswer"
          },
          "acts": {
            "type": "integer"
          },
          "blocked": {
            "description": "A new player cannot start or act, or a defect is high.",
            "type": "boolean"
          },
          "blocking": {
            "type": "string"
          },
          "confidence": {
            "type": "number"
          },
          "confusions": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "criteria": {
            "items": {
              "properties": {
                "id": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                },
                "text": {
                  "type": "string"
                },
                "verdict": {
                  "enum": [
                    "pass",
                    "fail",
                    "inconclusive"
                  ],
                  "type": "string"
                }
              },
              "type": "object"
            },
            "type": "array"
          },
          "defects": {
            "items": {
              "properties": {
                "actual": {
                  "type": "string"
                },
                "expected": {
                  "type": "string"
                },
                "severity": {
                  "enum": [
                    "high",
                    "medium",
                    "low"
                  ],
                  "type": "string"
                },
                "shot": {
                  "description": "The act frame that shows it.",
                  "type": "string"
                },
                "step": {
                  "type": "integer"
                },
                "title": {
                  "type": "string"
                }
              },
              "type": "object"
            },
            "maxItems": 3,
            "type": "array"
          },
          "end": {
            "properties": {
              "answer": {
                "enum": [
                  "won",
                  "lost",
                  "neither"
                ],
                "type": "string"
              },
              "note": {
                "type": "string"
              }
            },
            "type": "object"
          },
          "ended_early": {
            "type": [
              "string",
              "null"
            ]
          },
          "frames": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "goal": {
            "$ref": "#/components/schemas/PlayAnswer"
          },
          "model": {
            "type": "string"
          },
          "notes": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "replayed": {
            "description": "Times the round was replayed from the start.",
            "type": "integer"
          },
          "report_problems": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "start": {
            "$ref": "#/components/schemas/PlayAnswer"
          },
          "steps": {
            "type": "integer"
          },
          "viewport": {
            "type": "string"
          }
        },
        "required": [
          "start",
          "goal",
          "act",
          "end",
          "confusions",
          "criteria",
          "defects",
          "blocking",
          "confidence",
          "blocked",
          "acts",
          "steps",
          "replayed",
          "frames"
        ],
        "type": "object"
      },
      "Preview": {
        "properties": {
          "built_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "content_key": {
            "type": [
              "string",
              "null"
            ]
          },
          "game_id": {
            "$ref": "#/components/schemas/GameId"
          },
          "preview_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "source": {
            "enum": [
              "draft_build",
              "upload",
              null
            ],
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "game_id",
          "preview_url",
          "source",
          "content_key",
          "built_at"
        ],
        "type": "object"
      },
      "Pricing": {
        "properties": {
          "confirm_threshold_credits": {
            "type": "integer"
          },
          "tools": {
            "items": {
              "$ref": "#/components/schemas/ToolPrice"
            },
            "type": "array"
          }
        },
        "required": [
          "tools",
          "confirm_threshold_credits"
        ],
        "type": "object"
      },
      "ReviewInput": {
        "additionalProperties": false,
        "properties": {
          "confirm_cost": {
            "type": "boolean"
          },
          "facts": {
            "description": "Measured facts the seats read before the captures, one per line and numbered (F1, F2, …), each naming its instrument; the seats cite them by id. `funtools playtest --hosted` sends the block its local seats read. Your own measurements: nothing here is checked.",
            "maxLength": 4000,
            "type": "string"
          },
          "game_id": {
            "$ref": "#/components/schemas/GameId"
          },
          "images": {
            "items": {
              "additionalProperties": false,
              "properties": {
                "data_base64": {
                  "description": "PNG, JPEG or WebP, at most 700 KB.",
                  "type": "string"
                },
                "name": {
                  "description": "<view>-<viewport>",
                  "pattern": "^[A-Za-z0-9_.-]{1,64}$",
                  "type": "string"
                }
              },
              "required": [
                "name",
                "data_base64"
              ],
              "type": "object"
            },
            "maxItems": 12,
            "type": "array"
          },
          "premise": {
            "description": "The store description, four to six plain sentences. The seats know nothing else.",
            "maxLength": 1500,
            "minLength": 40,
            "type": "string"
          },
          "seats": {
            "default": "full",
            "description": "full = player, ux, skeptic (each re-reads the phone captures on the same axes; no separate mobile seat); quick = player, skeptic.",
            "enum": [
              "full",
              "quick"
            ],
            "type": "string"
          },
          "webhook_url": {
            "pattern": "^https://",
            "type": "string"
          }
        },
        "required": [
          "game_id",
          "premise"
        ],
        "type": "object"
      },
      "ReviewResult": {
        "description": "A succeeded `review` job's `result` (also stored as its `review.json` output).",
        "properties": {
          "errors": {
            "items": {
              "properties": {
                "error": {
                  "type": "string"
                },
                "persona": {
                  "type": "string"
                }
              },
              "type": "object"
            },
            "type": "array"
          },
          "frames": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "frames_missed": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "mean": {
            "additionalProperties": {
              "type": [
                "number",
                "null"
              ]
            },
            "type": "object"
          },
          "model": {
            "description": "A neutral label for the panel",
            "never a vendor.": null,
            "type": "string"
          },
          "seats": {
            "items": {
              "additionalProperties": true,
              "description": "One seat's verdict, in the review brief's shape.",
              "properties": {
                "best": {
                  "items": {
                    "type": "string"
                  },
                  "type": "array"
                },
                "critic": {
                  "enum": [
                    "player",
                    "ux",
                    "mobile",
                    "skeptic"
                  ],
                  "type": "string"
                },
                "fixFirst": {
                  "items": {
                    "type": "string"
                  },
                  "type": "array"
                },
                "quote": {
                  "type": "string"
                },
                "read": {
                  "type": "number"
                },
                "scores": {
                  "additionalProperties": {
                    "type": "number"
                  },
                  "description": "lookAndFeel, readability, intuitiveness, juice, fun, mobile, hud, overall; 1-10.",
                  "type": "object"
                },
                "why": {
                  "additionalProperties": {
                    "type": "string"
                  },
                  "type": "object"
                },
                "worst": {
                  "items": {
                    "type": "string"
                  },
                  "type": "array"
                }
              },
              "required": [
                "critic",
                "scores"
              ],
              "type": "object"
            },
            "type": "array"
          },
          "versus": {
            "description": "The head to head against a genre hit runs locally only.",
            "type": "null"
          },
          "versus_note": {
            "type": "string"
          }
        },
        "required": [
          "seats",
          "errors",
          "mean",
          "frames",
          "model",
          "versus",
          "versus_note"
        ],
        "type": "object"
      },
      "RoomTicket": {
        "additionalProperties": true,
        "description": "A single-use relay ticket.",
        "type": "object"
      },
      "SceneRead": {
        "properties": {
          "entered": {
            "type": "boolean"
          },
          "front_door": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/FrontDoor"
              },
              {
                "type": "null"
              }
            ]
          },
          "game_id": {
            "$ref": "#/components/schemas/GameId"
          },
          "preview_url": {
            "type": "string"
          },
          "scene": {
            "description": "The scene reading's answer.",
            "properties": {
              "draw_calls": {
                "properties": {
                  "basis": {
                    "type": "string"
                  },
                  "estimate": {
                    "type": "integer"
                  }
                },
                "type": "object"
              },
              "engine": {
                "enum": [
                  "three",
                  "pixi",
                  "phaser",
                  "none"
                ],
                "type": "string"
              },
              "handle": {
                "type": "string"
              },
              "hidden": {
                "properties": {
                  "names": {
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  },
                  "total": {
                    "type": "integer"
                  }
                },
                "type": "object"
              },
              "hint": {
                "type": "string"
              },
              "kinds": {
                "additionalProperties": {
                  "type": "integer"
                },
                "type": "object"
              },
              "max_depth": {
                "type": "integer"
              },
              "nodes": {
                "type": "integer"
              },
              "offscreen": {
                "properties": {
                  "names": {
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  },
                  "total": {
                    "type": "integer"
                  }
                },
                "type": "object"
              },
              "renderer": {
                "type": [
                  "object",
                  "null"
                ]
              },
              "textures": {
                "type": "object"
              },
              "truncated": {
                "type": "boolean"
              },
              "visible": {
                "type": "integer"
              }
            },
            "type": "object"
          },
          "view": {
            "$ref": "#/components/schemas/DrivenView"
          }
        },
        "required": [
          "game_id",
          "preview_url",
          "scene"
        ],
        "type": "object"
      },
      "Scope": {
        "description": "A key's scopes. A key minted without naming any gets every scope but the two\ncommunity ones; `community:read` and `community:write` are on a\nkey only when its minting named them.\n",
        "enum": [
          "tools:run",
          "jobs:read",
          "usage:read",
          "games:publish",
          "rooms:join",
          "feedback:write",
          "community:read",
          "community:write"
        ],
        "type": "string"
      },
      "ScreenAudit": {
        "properties": {
          "failures": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "game_id": {
            "$ref": "#/components/schemas/GameId"
          },
          "notes": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "preview_url": {
            "type": "string"
          },
          "safe": {
            "description": "The insets kept clear (top, right, bottom, left).",
            "type": "object"
          },
          "verdict": {
            "$ref": "#/components/schemas/Verdict"
          },
          "viewport": {
            "type": "string"
          },
          "views": {
            "items": {
              "properties": {
                "error": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "failed": {
                  "items": {
                    "enum": [
                      "small_targets",
                      "small_text",
                      "overlaps",
                      "clipped",
                      "unsafe"
                    ],
                    "type": "string"
                  },
                  "type": "array"
                },
                "layout": {
                  "description": "The layout's lists, each `{total, items}`; null when not measured."
                },
                "verdict": {
                  "$ref": "#/components/schemas/Verdict"
                },
                "view": {
                  "type": "string"
                }
              },
              "type": "object"
            },
            "type": "array"
          }
        },
        "required": [
          "game_id",
          "preview_url",
          "verdict",
          "views",
          "failures",
          "notes"
        ],
        "type": "object"
      },
      "ServerVerdict": {
        "properties": {
          "failures": {
            "items": {
              "properties": {
                "reason": {
                  "type": "string"
                },
                "what": {
                  "type": "string"
                }
              },
              "required": [
                "what",
                "reason"
              ],
              "type": "object"
            },
            "type": "array"
          },
          "gates": {
            "type": "integer"
          },
          "hooks_found": {
            "description": "Whether the page exposed the __FPX_* hooks; null when the probe did not reach the game.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "note": {
            "type": "string"
          },
          "ran": {
            "description": "false when the probe never reached the game.",
            "type": "boolean"
          },
          "verdict": {
            "$ref": "#/components/schemas/Verdict"
          }
        },
        "required": [
          "verdict",
          "ran",
          "note",
          "failures",
          "gates"
        ],
        "type": "object"
      },
      "Sliced": {
        "properties": {
          "cell_height": {
            "type": "integer"
          },
          "cell_width": {
            "type": "integer"
          },
          "columns": {
            "type": "integer"
          },
          "frames": {
            "items": {
              "properties": {
                "column": {
                  "type": "integer"
                },
                "height": {
                  "type": "integer"
                },
                "index": {
                  "type": "integer"
                },
                "name": {
                  "type": "string"
                },
                "png_base64": {
                  "contentEncoding": "base64",
                  "type": "string"
                },
                "row": {
                  "type": "integer"
                },
                "width": {
                  "type": "integer"
                },
                "x": {
                  "type": "integer"
                },
                "y": {
                  "type": "integer"
                }
              },
              "required": [
                "name",
                "index",
                "row",
                "column",
                "x",
                "y",
                "width",
                "height",
                "png_base64"
              ],
              "type": "object"
            },
            "type": "array"
          },
          "manifest": {
            "additionalProperties": true,
            "description": "TexturePacker JSON-hash over the untouched sheet.",
            "type": "object"
          },
          "rows": {
            "type": "integer"
          },
          "skipped_empty": {
            "type": "integer"
          }
        },
        "required": [
          "columns",
          "rows",
          "cell_width",
          "cell_height",
          "skipped_empty",
          "frames",
          "manifest"
        ],
        "type": "object"
      },
      "StoreShots": {
        "properties": {
          "files": {
            "items": {
              "properties": {
                "bytes": {
                  "type": "integer"
                },
                "height": {
                  "type": "integer"
                },
                "index": {
                  "type": "integer"
                },
                "key": {
                  "type": "string"
                },
                "size": {
                  "enum": [
                    "iphone_6_9",
                    "iphone_6_5",
                    "ipad_13"
                  ],
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "width": {
                  "type": "integer"
                }
              },
              "required": [
                "size",
                "width",
                "height",
                "index",
                "key",
                "url",
                "bytes"
              ],
              "type": "object"
            },
            "type": "array"
          },
          "game_id": {
            "$ref": "#/components/schemas/GameId"
          },
          "notes": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "orientation": {
            "enum": [
              "portrait",
              "landscape"
            ],
            "type": "string"
          },
          "run_id": {
            "type": "string"
          },
          "shots": {
            "items": {
              "properties": {
                "banner": {
                  "type": "string"
                },
                "index": {
                  "type": "integer"
                },
                "variant": {
                  "type": "string"
                },
                "view": {
                  "type": "string"
                }
              },
              "required": [
                "index",
                "view",
                "variant",
                "banner"
              ],
              "type": "object"
            },
            "type": "array"
          },
          "url_expires_in_secs": {
            "type": "integer"
          }
        },
        "required": [
          "game_id",
          "run_id",
          "orientation",
          "shots",
          "files",
          "url_expires_in_secs",
          "notes"
        ],
        "type": "object"
      },
      "TextureStats": {
        "properties": {
          "findings": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "images": {
            "items": {
              "properties": {
                "file_bytes": {
                  "type": "integer"
                },
                "format": {
                  "enum": [
                    "png",
                    "jpeg",
                    "webp",
                    "ktx2",
                    "other",
                    "external"
                  ],
                  "type": "string"
                },
                "gpu_bytes": {
                  "type": "integer"
                },
                "height": {
                  "type": [
                    "integer",
                    "null"
                  ]
                },
                "index": {
                  "type": "integer"
                },
                "name": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                },
                "npot": {
                  "type": "boolean"
                },
                "oversized": {
                  "type": "boolean"
                },
                "used_by": {
                  "items": {
                    "type": "string"
                  },
                  "type": "array"
                },
                "width": {
                  "type": [
                    "integer",
                    "null"
                  ]
                }
              },
              "type": "object"
            },
            "type": "array"
          },
          "max_side": {
            "type": "integer"
          },
          "totals": {
            "properties": {
              "file_bytes": {
                "type": "integer"
              },
              "gpu_bytes": {
                "type": "integer"
              },
              "images": {
                "type": "integer"
              },
              "materials": {
                "type": "integer"
              },
              "not_measured": {
                "type": "integer"
              },
              "npot": {
                "type": "integer"
              },
              "oversized": {
                "type": "integer"
              },
              "textures": {
                "type": "integer"
              }
            },
            "type": "object"
          }
        },
        "required": [
          "max_side",
          "images",
          "totals",
          "findings"
        ],
        "type": "object"
      },
      "ToolInput": {
        "additionalProperties": true,
        "description": "The tool's input; unknown fields are a 400.",
        "properties": {
          "confirm_cost": {
            "type": "boolean"
          },
          "webhook_url": {
            "description": "Submit only. A public https URL; private, loopback and link-local hosts are a 400.",
            "maxLength": 2048,
            "pattern": "^https://",
            "type": "string"
          }
        },
        "type": "object"
      },
      "ToolPrice": {
        "properties": {
          "available": {
            "type": "boolean"
          },
          "prices": {
            "items": {
              "properties": {
                "credits": {
                  "type": "integer"
                },
                "variant": {
                  "type": "string"
                }
              },
              "required": [
                "variant",
                "credits"
              ],
              "type": "object"
            },
            "type": "array"
          },
          "tool": {
            "type": "string"
          }
        },
        "required": [
          "tool",
          "available",
          "prices"
        ],
        "type": "object"
      },
      "Upload": {
        "properties": {
          "dependencies": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "properties": {
                  "advisories_checked": {
                    "type": "boolean"
                  },
                  "packages": {
                    "type": "integer"
                  },
                  "source": {
                    "type": "string"
                  }
                },
                "type": "object"
              }
            ]
          },
          "files": {
            "type": "integer"
          },
          "game_id": {
            "$ref": "#/components/schemas/GameId"
          },
          "live_unchanged": {
            "description": "The game is published and still serves its published version; publish to ship this build.",
            "type": "boolean"
          },
          "play_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "prebuilt": {
            "type": "boolean"
          },
          "preview_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "project_id": {
            "format": "uuid",
            "type": "string"
          },
          "remixable": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "replaced": {
            "type": "boolean"
          },
          "skipped_empty": {
            "type": "integer"
          },
          "status": {
            "enum": [
              "draft",
              "published"
            ],
            "type": "string"
          },
          "verification": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/Verification"
              }
            ]
          }
        },
        "required": [
          "game_id",
          "project_id",
          "files",
          "status",
          "replaced",
          "skipped_empty",
          "prebuilt",
          "preview_url",
          "play_url",
          "verification"
        ],
        "type": "object"
      },
      "Usage": {
        "properties": {
          "days": {
            "items": {
              "properties": {
                "credits": {
                  "type": "integer"
                },
                "day": {
                  "format": "date",
                  "type": "string"
                },
                "jobs": {
                  "type": "integer"
                },
                "succeeded": {
                  "type": "integer"
                },
                "tool": {
                  "type": "string"
                },
                "waived_credits": {
                  "type": "integer"
                }
              },
              "required": [
                "day",
                "tool",
                "jobs",
                "succeeded",
                "credits",
                "waived_credits"
              ],
              "type": "object"
            },
            "type": "array"
          },
          "from": {
            "format": "date",
            "type": "string"
          },
          "to": {
            "format": "date",
            "type": "string"
          },
          "total_credits": {
            "type": "integer"
          },
          "total_waived_credits": {
            "type": "integer"
          }
        },
        "required": [
          "from",
          "to",
          "total_credits",
          "total_waived_credits",
          "days"
        ],
        "type": "object"
      },
      "Verdict": {
        "enum": [
          "pass",
          "fail",
          "not_observed"
        ],
        "type": "string"
      },
      "Verification": {
        "properties": {
          "agree": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "client": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "additionalProperties": true,
                "properties": {
                  "fingerprint": {
                    "type": "string"
                  },
                  "verdict": {
                    "$ref": "#/components/schemas/Verdict"
                  }
                },
                "type": "object"
              }
            ]
          },
          "server": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ServerVerdict"
              }
            ]
          }
        },
        "required": [
          "client",
          "server",
          "agree"
        ],
        "type": "object"
      },
      "generate_image_input": {
        "additionalProperties": false,
        "properties": {
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "kind": {
            "default": "image",
            "description": "texture: a seamless tile that wraps both ways; strip: a scrolling layer that wraps left to right (either refused, uncharged, if it shows a seam). platform: a side-view ground or platform piece (a flat walkable top, repeats left to right). key_art: the title moment with its hero. screen: a target frame of one game screen, the hero, the play and the HUD or words in place (opaque). reference: one design's sheet, front, side and back on a plain field (opaque). image: anything else; opaque, it is drawn as scenery only (no figure, no HUD, no text).",
            "enum": [
              "image",
              "texture",
              "strip",
              "platform",
              "key_art",
              "screen",
              "reference"
            ],
            "type": "string"
          },
          "model": {
            "type": "string",
            "description": "Optional: a model this tool offers, by its id from `GET /v1/tools/models`; omit it for our pick."
          },
          "prompt": {
            "description": "What to make. Art direction welcome.",
            "maxLength": 4000,
            "minLength": 1,
            "type": "string"
          },
          "quality": {
            "default": "medium",
            "description": "low for drafts, medium for game art, high for key art.",
            "enum": [
              "low",
              "medium",
              "high"
            ],
            "type": "string"
          },
          "references": {
            "description": "Pictures of yours (an asset_id a job printed, or import_asset) sent to the model as references: a character sheet to draw on-model, the game's approved art to match. Say in the prompt what each is for ('the knight from the reference, mid-jump'). The first is in the base price; each one after it adds a little.",
            "items": {
              "format": "uuid",
              "type": "string"
            },
            "maxItems": 16,
            "type": "array",
            "uniqueItems": true
          },
          "size": {
            "default": "1024x1024",
            "description": "WxH. The aspect ratio is kept: both sides scale together to fit 256-1024, then map to the nearest ratio the model draws (1:1, 3:2, 2:3, 4:3, 3:4, 16:9, 9:16, 21:9). E.g. 1536x1024 -> 3:2, 1920x1080 -> 16:9.",
            "pattern": "^[0-9]+x[0-9]+$",
            "type": "string"
          },
          "target_size": {
            "description": "The longest side of the delivered file, in pixels: the size the game shows it at (or twice that for sharp screens). The model still draws at `size`; the file is scaled down after, never up. Omit to keep the drawn size.",
            "maximum": 2048,
            "minimum": 16,
            "type": "integer"
          },
          "transparent": {
            "default": false,
            "type": "boolean"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "prompt"
        ],
        "type": "object"
      },
      "generate_sprite_input": {
        "additionalProperties": false,
        "properties": {
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "model": {
            "type": "string",
            "description": "Optional: a model this tool offers, by its id from `GET /v1/tools/models`; omit it for our pick."
          },
          "prompt": {
            "description": "What to make. Art direction welcome.",
            "maxLength": 4000,
            "minLength": 1,
            "type": "string"
          },
          "quality": {
            "default": "medium",
            "description": "low for drafts, medium for game art, high for key art.",
            "enum": [
              "low",
              "medium",
              "high"
            ],
            "type": "string"
          },
          "references": {
            "description": "Pictures of yours (an asset_id a job printed, or import_asset) sent to the model as references: a character sheet to draw on-model, the game's approved art to match. Say in the prompt what each is for ('the knight from the reference, mid-jump'). The first is in the base price; each one after it adds a little.",
            "items": {
              "format": "uuid",
              "type": "string"
            },
            "maxItems": 16,
            "type": "array",
            "uniqueItems": true
          },
          "size": {
            "default": "1024x1024",
            "description": "WxH. The aspect ratio is kept: both sides scale together to fit 256-1024, then map to the nearest ratio the model draws (1:1, 3:2, 2:3, 4:3, 3:4, 16:9, 9:16, 21:9). E.g. 1536x1024 -> 3:2, 1920x1080 -> 16:9.",
            "pattern": "^[0-9]+x[0-9]+$",
            "type": "string"
          },
          "target_size": {
            "description": "The longest side of the delivered file, in pixels: the size the game shows it at (or twice that for sharp screens). The model still draws at `size`; the file is scaled down after, never up. Omit to keep the drawn size.",
            "maximum": 2048,
            "minimum": 16,
            "type": "integer"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "prompt"
        ],
        "type": "object"
      },
      "edit_image_input": {
        "additionalProperties": false,
        "properties": {
          "asset_id": {
            "description": "A picture of yours: one a previous job made (a sprite, a backdrop), or one import_asset stored",
            "format": "uuid",
            "type": "string"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "game_id": {
            "description": "A game of yours: its style lock and anchors shape the edit (and add their own small share to the price).",
            "pattern": "^[0-9a-f]{32}$",
            "type": "string"
          },
          "mask_asset_id": {
            "description": "A mask for the edit: a PNG the picture's exact size, white where painted, black (or transparent) elsewhere, stored with import_asset. Only the painted area changes (grown 3 px and feathered); every pixel outside it is the original's, its transparency kept. Takes mode erase or edit, and no size, quality or game_id.",
            "format": "uuid",
            "type": "string"
          },
          "mode": {
            "default": "edit",
            "description": "edit: change what the prompt says, keep the rest; restyle: redraw it in another look; pose: the same character in the pose the prompt describes; erase (with mask_asset_id only): remove what is painted and fill in the background, no prompt needed. With mask_asset_id, edit or erase.",
            "enum": [
              "edit",
              "restyle",
              "pose",
              "erase"
            ],
            "type": "string"
          },
          "prompt": {
            "description": "The one change, e.g. 'eyes closed', 'recoiling from a hit, eyes squeezed shut', 'the armour gold'. Everything else is kept. With mask_asset_id: what to draw where the mask is painted (required for mode edit, optional for erase).",
            "maxLength": 4000,
            "minLength": 1,
            "type": "string"
          },
          "quality": {
            "default": "medium",
            "description": "low for drafts, medium for game art, high for key art.",
            "enum": [
              "low",
              "medium",
              "high"
            ],
            "type": "string"
          },
          "size": {
            "description": "Omit to keep the picture's own size. Otherwise as generate_image's size: WxH, the ratio kept, mapped to the nearest ratio the model draws.",
            "pattern": "^[0-9]+x[0-9]+$",
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "asset_id"
        ],
        "type": "object"
      },
      "generate_spritesheet_input": {
        "additionalProperties": false,
        "properties": {
          "animations": {
            "description": "Each cycle and its frame count, each name once; at least 2 and at most 32 frames in all. Hero: idle 2, walk 6, attack 4, hit 2. Enemy: walk 4, hit 2, death 4.",
            "items": {
              "additionalProperties": false,
              "properties": {
                "fps": {
                  "description": "Default: idle 6, walk 10, run 12, jump 10, attack 12, act 12, hit 10, death 8, blink 10.",
                  "maximum": 30,
                  "minimum": 1,
                  "type": "integer"
                },
                "frames": {
                  "maximum": 12,
                  "minimum": 1,
                  "type": "integer"
                },
                "loop": {
                  "description": "Default: idle, walk and run loop; the rest play once.",
                  "type": "boolean"
                },
                "name": {
                  "enum": [
                    "idle",
                    "walk",
                    "run",
                    "jump",
                    "attack",
                    "act",
                    "hit",
                    "death",
                    "blink"
                  ],
                  "type": "string"
                }
              },
              "required": [
                "name",
                "frames"
              ],
              "type": "object"
            },
            "maxItems": 8,
            "minItems": 1,
            "type": "array"
          },
          "asset_id": {
            "description": "A sprite of yours on a transparent background to animate (else the base is drawn from the prompt)",
            "format": "uuid",
            "type": "string"
          },
          "body": {
            "default": "biped",
            "description": "Whose poses: biped, quadruped (four legs) or flyer (wings; its walk and run are flying). blink 1 frame is the eyes-shut swap.",
            "enum": [
              "biped",
              "quadruped",
              "flyer"
            ],
            "type": "string"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "frame_size": {
            "default": 256,
            "description": "Each frame's square cell, pixels.",
            "maximum": 512,
            "minimum": 64,
            "type": "integer"
          },
          "game_id": {
            "description": "A game of yours: its style lock and anchors shape every frame.",
            "pattern": "^[0-9a-f]{32}$",
            "type": "string"
          },
          "prompt": {
            "description": "The character, as for generate_sprite. With asset_id it only reminds each frame who this is.",
            "maxLength": 4000,
            "minLength": 1,
            "type": "string"
          },
          "quality": {
            "default": "medium",
            "description": "low for drafts, medium for game art, high for key art.",
            "enum": [
              "low",
              "medium",
              "high"
            ],
            "type": "string"
          },
          "view": {
            "default": "side",
            "description": "side faces right (flip the sprite for left).",
            "enum": [
              "side",
              "front"
            ],
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "animations"
        ],
        "type": "object"
      },
      "generate_sound_input": {
        "additionalProperties": false,
        "properties": {
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "duration_seconds": {
            "maximum": 30,
            "minimum": 0.5,
            "type": "number"
          },
          "loop": {
            "default": false,
            "type": "boolean"
          },
          "model": {
            "type": "string",
            "description": "Optional: a model this tool offers, by its id from `GET /v1/tools/models`; omit it for our pick."
          },
          "prompt": {
            "description": "What to make. Art direction welcome.",
            "maxLength": 4000,
            "minLength": 1,
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "prompt"
        ],
        "type": "object"
      },
      "generate_music_input": {
        "additionalProperties": false,
        "properties": {
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "instrumental": {
            "default": false,
            "type": "boolean"
          },
          "length": {
            "default": "clip",
            "enum": [
              "clip",
              "full"
            ],
            "type": "string"
          },
          "model": {
            "type": "string",
            "description": "Optional: a model this tool offers, by its id from `GET /v1/tools/models`; omit it for our pick."
          },
          "prompt": {
            "description": "What to make. Art direction welcome.",
            "maxLength": 4000,
            "minLength": 1,
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "prompt"
        ],
        "type": "object"
      },
      "cast_voice_input": {
        "additionalProperties": false,
        "properties": {
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "description": {
            "description": "Who this is, for you and your team. Kept in the record; never spoken.",
            "maxLength": 500,
            "minLength": 1,
            "type": "string"
          },
          "model": {
            "type": "string",
            "description": "Optional: a model this tool offers, by its id from `GET /v1/tools/models`; omit it for our pick."
          },
          "name": {
            "description": "The cast member, e.g. 'Old Bram'. Kept in the record; never spoken.",
            "pattern": "^[A-Za-z0-9][A-Za-z0-9 _.'-]{0,39}$",
            "type": "string"
          },
          "preset": {
            "description": "The base voice: Zephyr bright, Puck upbeat, Charon informative, Kore firm, Fenrir excitable, Leda youthful, Orus firm, Aoede breezy, Callirrhoe easy-going, Autonoe bright, Enceladus breathy, Iapetus clear, Umbriel easy-going, Algieba smooth, Despina smooth, Erinome clear, Algenib gravelly, Rasalgethi informative, Laomedeia upbeat, Achernar soft, Alnilam firm, Schedar even, Gacrux mature, Pulcherrima forward, Achird friendly, Zubenelgenubi casual, Vindemiatrix gentle, Sadachbia lively, Sadaltager knowledgeable, Sulafat warm.",
            "enum": [
              "Zephyr",
              "Puck",
              "Charon",
              "Kore",
              "Fenrir",
              "Leda",
              "Orus",
              "Aoede",
              "Callirrhoe",
              "Autonoe",
              "Enceladus",
              "Iapetus",
              "Umbriel",
              "Algieba",
              "Despina",
              "Erinome",
              "Algenib",
              "Rasalgethi",
              "Laomedeia",
              "Achernar",
              "Alnilam",
              "Schedar",
              "Gacrux",
              "Pulcherrima",
              "Achird",
              "Zubenelgenubi",
              "Vindemiatrix",
              "Sadachbia",
              "Sadaltager",
              "Sulafat"
            ],
            "type": "string"
          },
          "sample": {
            "description": "What the sample says (default: a short hello). Charged like a line.",
            "maxLength": 500,
            "minLength": 1,
            "type": "string"
          },
          "tags": {
            "description": "How this character always speaks, as delivery words: gruff, weary, slowly, whispering, cheerful. Every line gets them.",
            "items": {
              "pattern": "^[a-z][a-z -]{0,23}$",
              "type": "string"
            },
            "maxItems": 4,
            "type": "array"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "name",
          "preset"
        ],
        "type": "object"
      },
      "voice_line_input": {
        "additionalProperties": false,
        "properties": {
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "emotion": {
            "description": "This line only: angry, scared, laughing, whispering.",
            "items": {
              "pattern": "^[a-z][a-z -]{0,23}$",
              "type": "string"
            },
            "maxItems": 3,
            "type": "array"
          },
          "model": {
            "type": "string",
            "description": "Optional: a model this tool offers, by its id from `GET /v1/tools/models`; omit it for our pick."
          },
          "preset": {
            "description": "The base voice: Zephyr bright, Puck upbeat, Charon informative, Kore firm, Fenrir excitable, Leda youthful, Orus firm, Aoede breezy, Callirrhoe easy-going, Autonoe bright, Enceladus breathy, Iapetus clear, Umbriel easy-going, Algieba smooth, Despina smooth, Erinome clear, Algenib gravelly, Rasalgethi informative, Laomedeia upbeat, Achernar soft, Alnilam firm, Schedar even, Gacrux mature, Pulcherrima forward, Achird friendly, Zubenelgenubi casual, Vindemiatrix gentle, Sadachbia lively, Sadaltager knowledgeable, Sulafat warm.",
            "enum": [
              "Zephyr",
              "Puck",
              "Charon",
              "Kore",
              "Fenrir",
              "Leda",
              "Orus",
              "Aoede",
              "Callirrhoe",
              "Autonoe",
              "Enceladus",
              "Iapetus",
              "Umbriel",
              "Algieba",
              "Despina",
              "Erinome",
              "Algenib",
              "Rasalgethi",
              "Laomedeia",
              "Achernar",
              "Alnilam",
              "Schedar",
              "Gacrux",
              "Pulcherrima",
              "Achird",
              "Zubenelgenubi",
              "Vindemiatrix",
              "Sadachbia",
              "Sadaltager",
              "Sulafat"
            ],
            "type": "string"
          },
          "tags": {
            "description": "With preset: the delivery words (as cast_voice's).",
            "items": {
              "pattern": "^[a-z][a-z -]{0,23}$",
              "type": "string"
            },
            "maxItems": 4,
            "type": "array"
          },
          "text": {
            "description": "The line, as the character says it. Bracketed audio tags inside it steer the delivery and are not spoken: [sighs], [laughs], [pause].",
            "maxLength": 500,
            "minLength": 1,
            "type": "string"
          },
          "voice_asset_id": {
            "description": "voice.json from cast_voice: the character's voice, the same on every line",
            "format": "uuid",
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "text"
        ],
        "type": "object"
      },
      "dialogue_input": {
        "additionalProperties": false,
        "properties": {
          "cast": {
            "additionalProperties": {
              "description": "A speaker's voice: voice.json's asset id from cast_voice (the same voice on every line), or a preset: Zephyr, Puck, Charon, Kore, Fenrir, Leda, Orus, Aoede, Callirrhoe, Autonoe, Enceladus, Iapetus, Umbriel, Algieba, Despina, Erinome, Algenib, Rasalgethi, Laomedeia, Achernar, Alnilam, Schedar, Gacrux, Pulcherrima, Achird, Zubenelgenubi, Vindemiatrix, Sadachbia, Sadaltager, Sulafat.",
              "pattern": "^([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}|[A-Za-z]{2,24})$",
              "type": "string"
            },
            "description": "Speaker → voice, for every line that names none.",
            "propertyNames": {
              "pattern": "^[A-Za-z0-9][A-Za-z0-9 _.'-]{0,39}$"
            },
            "type": "object"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "gap_ms": {
            "default": 250,
            "description": "Silence between lines, ms.",
            "maximum": 10000,
            "minimum": 0,
            "type": "integer"
          },
          "lines": {
            "description": "The script, in order: at most 60 lines and 4000 characters of text in all (split a longer scene). Each line starts where the one before ended, plus that one's pause.",
            "items": {
              "additionalProperties": false,
              "properties": {
                "pause_after_ms": {
                  "description": "Silence after this line, ms (default gap_ms).",
                  "maximum": 10000,
                  "minimum": 0,
                  "type": "integer"
                },
                "speaker": {
                  "description": "Who says it, e.g. 'Old Bram'. Never spoken.",
                  "pattern": "^[A-Za-z0-9][A-Za-z0-9 _.'-]{0,39}$",
                  "type": "string"
                },
                "tags": {
                  "description": "This line only: delivery words (angry, scared, whispering).",
                  "items": {
                    "pattern": "^[a-z][a-z -]{0,23}$",
                    "type": "string"
                  },
                  "maxItems": 4,
                  "type": "array"
                },
                "text": {
                  "description": "The line, as the character says it. [sighs], [laughs], [pause] steer the delivery and are not spoken.",
                  "maxLength": 500,
                  "minLength": 1,
                  "type": "string"
                },
                "track": {
                  "description": "The timeline track it sits on (default: one per speaker).",
                  "pattern": "^[A-Za-z0-9][A-Za-z0-9 _.'-]{0,39}$",
                  "type": "string"
                },
                "voice": {
                  "description": "This line's voice, over the cast's: voice.json's asset id from cast_voice (the same voice on every line), or a preset: Zephyr, Puck, Charon, Kore, Fenrir, Leda, Orus, Aoede, Callirrhoe, Autonoe, Enceladus, Iapetus, Umbriel, Algieba, Despina, Erinome, Algenib, Rasalgethi, Laomedeia, Achernar, Alnilam, Schedar, Gacrux, Pulcherrima, Achird, Zubenelgenubi, Vindemiatrix, Sadachbia, Sadaltager, Sulafat.",
                  "pattern": "^([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}|[A-Za-z]{2,24})$",
                  "type": "string"
                }
              },
              "required": [
                "speaker",
                "text"
              ],
              "type": "object"
            },
            "maxItems": 60,
            "minItems": 1,
            "type": "array"
          },
          "model": {
            "type": "string",
            "description": "Optional: a model this tool offers, by its id from `GET /v1/tools/models`; omit it for our pick."
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "lines"
        ],
        "type": "object"
      },
      "generate_3d_model_input": {
        "additionalProperties": false,
        "properties": {
          "animations": {
            "description": "Clip names from the motion library, each shipped as model.<name>.glb under that name. walk and run come free with the rig; each other clip is paid. A *_in_place motion plays on the spot (the game moves the body); the rest carry root motion. Any clip rigs the model, textured whatever the style. The rig takes humanoid bipeds only, decided from the prompt's words: a prompt naming another body (an animal, a vehicle) comes back static, priced and charged as static, and the job's result says so; an image with no prompt is rigged.",
            "items": {
              "enum": [
                "idle",
                "walk",
                "run",
                "jump",
                "attack",
                "block",
                "hit",
                "death",
                "wave",
                "dance",
                "cheer",
                "walk_in_place",
                "walk_back",
                "walk_back_in_place",
                "run_in_place",
                "sprint",
                "sprint_in_place",
                "crouch_walk",
                "crouch_walk_in_place",
                "crouch_walk_back",
                "crouch_walk_back_in_place",
                "sneak",
                "sneak_in_place",
                "injured_walk",
                "injured_walk_in_place",
                "carry_walk",
                "carry_walk_in_place",
                "swim",
                "swim_idle",
                "climb_ladder",
                "climb_wall",
                "climb_stairs",
                "push",
                "jump_run",
                "jump_over",
                "fall",
                "vault",
                "dodge",
                "roll",
                "slash",
                "combo",
                "thrust",
                "heavy_attack",
                "spin_attack",
                "jab",
                "uppercut",
                "punch_combo",
                "kick",
                "roundhouse_kick",
                "sweep_kick",
                "parry",
                "ground_slam",
                "shoot_bow",
                "draw_shoot_bow",
                "walk_aim_bow",
                "walk_aim_bow_in_place",
                "shoot",
                "walk_shoot",
                "walk_shoot_in_place",
                "run_shoot",
                "cast",
                "cast_quick",
                "hit_face",
                "knockback",
                "knockdown",
                "death_back",
                "death_forward",
                "pick_up",
                "sit_down",
                "sit_idle",
                "stand_up",
                "talk",
                "fist_pump",
                "bow",
                "shrug",
                "agree",
                "disagree",
                "angry",
                "confused",
                "die",
                "dead",
                "gethit",
                "get_hit",
                "victory"
              ],
              "type": "string"
            },
            "maxItems": 8,
            "type": "array"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "engine": {
            "type": "string",
            "description": "Optional: a model this tool offers, by its id from `GET /v1/tools/models`; omit it for our pick."
          },
          "image_asset_id": {
            "description": "An image a previous job of yours made",
            "format": "uuid",
            "type": "string"
          },
          "image_url": {
            "pattern": "^https://",
            "type": "string"
          },
          "model": {
            "type": "string",
            "description": "Optional: a model this tool offers, by its id from `GET /v1/tools/models`; omit it for our pick."
          },
          "prompt": {
            "description": "What to make. Art direction welcome.",
            "maxLength": 4000,
            "minLength": 1,
            "type": "string"
          },
          "raw": {
            "default": false,
            "description": "model.glb (and each clip) is the engine's GLB byte for byte: every triangle, the maps at full size and format, no compression. For close-ups (a first-person viewmodel, a hero character) and for cutting your own levels; heavy for a phone as it is. Same price. No model.source.glb beside it.",
            "type": "boolean"
          },
          "style": {
            "default": "standard",
            "description": "standard: textured (PBR), about 30K to 50K triangles, by engine. hero: textured at a high triangle count, static only: 300K to 500K triangles, by engine. lowpoly: the cheap draft, an UNTEXTURED white mesh with no material (colour it in code), at the engine's own triangle count, NOT reduced (about 48K triangles unless an engine is named); for a textured model a phone can draw, use standard and cut it with optimize_model or lod_model. hero with animations ships the standard mesh, rigged.",
            "enum": [
              "standard",
              "hero",
              "lowpoly"
            ],
            "type": "string"
          },
          "view_asset_ids": {
            "additionalProperties": false,
            "description": "Extra views of the SAME subject (images previous jobs of yours made), beside the front picture: the model is built from every view, so its back is drawn, not invented. Needs image_url or image_asset_id (the front).",
            "properties": {
              "back": {
                "description": "The subject from behind",
                "format": "uuid",
                "type": "string"
              },
              "left": {
                "description": "The subject's left side",
                "format": "uuid",
                "type": "string"
              },
              "right": {
                "description": "The subject's right side",
                "format": "uuid",
                "type": "string"
              }
            },
            "type": "object"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [],
        "type": "object"
      },
      "generate_skybox_input": {
        "additionalProperties": false,
        "properties": {
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "negative_prompt": {
            "description": "What the sky must not show.",
            "maxLength": 4000,
            "minLength": 1,
            "type": "string"
          },
          "prompt": {
            "description": "What to make. Art direction welcome.",
            "maxLength": 4000,
            "minLength": 1,
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "prompt"
        ],
        "type": "object"
      },
      "find_material_input": {
        "additionalProperties": false,
        "properties": {
          "kind": {
            "description": "Only this kind; omit for all three.",
            "enum": [
              "hdri",
              "texture",
              "model"
            ],
            "type": "string"
          },
          "limit": {
            "default": 8,
            "maximum": 20,
            "minimum": 1,
            "type": "integer"
          },
          "query": {
            "description": "Keywords, e.g. \"mossy rock\" or \"sunset sky\".",
            "pattern": "^[A-Za-z0-9 _-]{1,80}$",
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "query"
        ],
        "type": "object"
      },
      "get_material_input": {
        "additionalProperties": false,
        "properties": {
          "id": {
            "description": "An id find_material returned.",
            "pattern": "^[a-z0-9_-]{1,100}$",
            "type": "string"
          },
          "kind": {
            "enum": [
              "hdri",
              "texture",
              "model"
            ],
            "type": "string"
          },
          "query": {
            "description": "Keywords instead of an id: the best match is fetched.",
            "pattern": "^[A-Za-z0-9 _-]{1,80}$",
            "type": "string"
          },
          "resolution": {
            "default": "1k",
            "enum": [
              "1k",
              "2k"
            ],
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "kind"
        ],
        "type": "object"
      },
      "inspect_model_input": {
        "additionalProperties": false,
        "properties": {
          "asset_id": {
            "description": "A .glb (or a self-contained .gltf) a previous job of yours made",
            "format": "uuid",
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "asset_id"
        ],
        "type": "object"
      },
      "optimize_model_input": {
        "additionalProperties": false,
        "properties": {
          "asset_id": {
            "description": "A .glb (or a self-contained .gltf) a previous job of yours made",
            "format": "uuid",
            "type": "string"
          },
          "budget": {
            "description": "The shape class whose triangle budget to decimate to.",
            "enum": [
              "food",
              "prop",
              "thin_walled",
              "set_piece",
              "character"
            ],
            "type": "string"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "device": {
            "default": "phone",
            "enum": [
              "phone",
              "desktop"
            ],
            "type": "string"
          },
          "height_m": {
            "description": "Scale so the model stands this tall, in metres.",
            "maximum": 1000,
            "minimum": 0.01,
            "type": "number"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "asset_id",
          "budget"
        ],
        "type": "object"
      },
      "fracture_model_input": {
        "additionalProperties": false,
        "properties": {
          "asset_id": {
            "description": "A .glb (or a self-contained .gltf) a previous job of yours made",
            "format": "uuid",
            "type": "string"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "pieces": {
            "default": 8,
            "maximum": 32,
            "minimum": 2,
            "type": "integer"
          },
          "seed": {
            "description": "Same seed, same shards.",
            "minimum": 0,
            "type": "integer"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "asset_id"
        ],
        "type": "object"
      },
      "lod_model_input": {
        "additionalProperties": false,
        "properties": {
          "asset_id": {
            "description": "A .glb (or a self-contained .gltf) a previous job of yours made",
            "format": "uuid",
            "type": "string"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "levels": {
            "default": 3,
            "description": "Levels after your model (LOD0), finest first.",
            "maximum": 4,
            "minimum": 1,
            "type": "integer"
          },
          "min_triangles": {
            "default": 100,
            "description": "No level is cut below this; the chain stops instead.",
            "maximum": 200000,
            "minimum": 100,
            "type": "integer"
          },
          "ratio": {
            "default": 0.5,
            "description": "Share of the triangles each level keeps of the one before.",
            "maximum": 0.95,
            "minimum": 0.05,
            "type": "number"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "asset_id"
        ],
        "type": "object"
      },
      "rig_model_input": {
        "additionalProperties": false,
        "properties": {
          "asset_id": {
            "description": "A .glb (or a self-contained .gltf) a previous job of yours made",
            "format": "uuid",
            "type": "string"
          },
          "clips": {
            "description": "Clips to author onto a bare biped rig (default all four). Not with a donor.",
            "items": {
              "enum": [
                "idle",
                "walk",
                "attack",
                "death"
              ],
              "type": "string"
            },
            "maxItems": 4,
            "type": "array",
            "uniqueItems": true
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "donor_asset_id": {
            "description": "A rigged, animated biped of yours: its rig and clips are fitted onto asset_id, which must have no rig",
            "format": "uuid",
            "type": "string"
          },
          "fbx": {
            "default": false,
            "description": "With motions: FBX copies too (model.fbx, model.<name>.fbx), for Unity and other tools that import FBX.",
            "type": "boolean"
          },
          "motions": {
            "description": "Library motions for an UNRIGGED humanoid mesh (an import, a static or hero model): our 3D provider rigs it and makes each, shipped as model.<name>.glb beside the rigged model.glb. walk and run come with the rig; each other motion is paid. A *_in_place motion plays on the spot. Not with donor_asset_id or clips; a model that already has a rig is refused, uncharged.",
            "items": {
              "enum": [
                "idle",
                "walk",
                "run",
                "jump",
                "attack",
                "block",
                "hit",
                "death",
                "wave",
                "dance",
                "cheer",
                "walk_in_place",
                "walk_back",
                "walk_back_in_place",
                "run_in_place",
                "sprint",
                "sprint_in_place",
                "crouch_walk",
                "crouch_walk_in_place",
                "crouch_walk_back",
                "crouch_walk_back_in_place",
                "sneak",
                "sneak_in_place",
                "injured_walk",
                "injured_walk_in_place",
                "carry_walk",
                "carry_walk_in_place",
                "swim",
                "swim_idle",
                "climb_ladder",
                "climb_wall",
                "climb_stairs",
                "push",
                "jump_run",
                "jump_over",
                "fall",
                "vault",
                "dodge",
                "roll",
                "slash",
                "combo",
                "thrust",
                "heavy_attack",
                "spin_attack",
                "jab",
                "uppercut",
                "punch_combo",
                "kick",
                "roundhouse_kick",
                "sweep_kick",
                "parry",
                "ground_slam",
                "shoot_bow",
                "draw_shoot_bow",
                "walk_aim_bow",
                "walk_aim_bow_in_place",
                "shoot",
                "walk_shoot",
                "walk_shoot_in_place",
                "run_shoot",
                "cast",
                "cast_quick",
                "hit_face",
                "knockback",
                "knockdown",
                "death_back",
                "death_forward",
                "pick_up",
                "sit_down",
                "sit_idle",
                "stand_up",
                "talk",
                "fist_pump",
                "bow",
                "shrug",
                "agree",
                "disagree",
                "angry",
                "confused",
                "die",
                "dead",
                "gethit",
                "get_hit",
                "victory"
              ],
              "type": "string"
            },
            "maxItems": 8,
            "minItems": 1,
            "type": "array",
            "uniqueItems": true
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "asset_id"
        ],
        "type": "object"
      },
      "render_model_input": {
        "additionalProperties": false,
        "properties": {
          "asset_id": {
            "description": "A .glb (or a self-contained .gltf) a previous job of yours made",
            "format": "uuid",
            "type": "string"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "frames": {
            "default": 8,
            "description": "Views evenly round the model.",
            "maximum": 12,
            "minimum": 1,
            "type": "integer"
          },
          "size": {
            "default": 512,
            "description": "Square edge of each view, in pixels.",
            "maximum": 1024,
            "minimum": 64,
            "type": "integer"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "asset_id"
        ],
        "type": "object"
      },
      "finalize_model_input": {
        "additionalProperties": false,
        "properties": {
          "asset_id": {
            "description": "A .glb (or a self-contained .gltf) a previous job of yours made",
            "format": "uuid",
            "type": "string"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "keep_clips": {
            "description": "Clip names to KEEP, e.g. [\"Idle\", \"Walk\"]; the rest are dropped. Omit to keep every clip.",
            "items": {
              "pattern": "^[A-Za-z0-9_.|: -]{1,64}$",
              "type": "string"
            },
            "maxItems": 32,
            "type": "array"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "asset_id"
        ],
        "type": "object"
      },
      "build_level_input": {
        "additionalProperties": false,
        "properties": {
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "size": {
            "default": 768,
            "description": "Edge of the two proof pictures, in pixels.",
            "maximum": 1024,
            "minimum": 256,
            "type": "integer"
          },
          "spec": {
            "additionalProperties": false,
            "properties": {
              "areas": {
                "items": {
                  "additionalProperties": false,
                  "properties": {
                    "ceiling": {
                      "default": false,
                      "type": "boolean"
                    },
                    "d": {
                      "description": "Size along Z.",
                      "maximum": 100,
                      "minimum": 0.5,
                      "multipleOf": 0.25,
                      "type": "number"
                    },
                    "floor_y": {
                      "description": "The walking surface's height.",
                      "maximum": 100,
                      "minimum": -50,
                      "type": "number"
                    },
                    "height": {
                      "default": 3,
                      "maximum": 20,
                      "minimum": 1,
                      "type": "number"
                    },
                    "kind": {
                      "default": "room",
                      "enum": [
                        "room",
                        "yard",
                        "path",
                        "water"
                      ],
                      "type": "string"
                    },
                    "name": {
                      "description": "Becomes part of a node name: a-z, 0-9, _; unique in the level.",
                      "pattern": "^[a-z][a-z0-9_]{0,31}$",
                      "type": "string"
                    },
                    "openings": {
                      "items": {
                        "additionalProperties": false,
                        "properties": {
                          "at": {
                            "description": "Metres along the wall from its start to the opening's near edge.",
                            "maximum": 200,
                            "minimum": -200,
                            "multipleOf": 0.25,
                            "type": "number"
                          },
                          "height": {
                            "default": 2.2,
                            "maximum": 20,
                            "minimum": 0.5,
                            "type": "number"
                          },
                          "side": {
                            "description": "n = -Z, s = +Z, e = +X, w = -X.",
                            "enum": [
                              "n",
                              "s",
                              "e",
                              "w"
                            ],
                            "type": "string"
                          },
                          "sill": {
                            "default": 0,
                            "description": "0 = a door; above 0 = a window.",
                            "maximum": 10,
                            "minimum": 0,
                            "type": "number"
                          },
                          "width": {
                            "description": "Metres.",
                            "maximum": 100,
                            "minimum": 0.5,
                            "multipleOf": 0.25,
                            "type": "number"
                          }
                        },
                        "required": [
                          "side",
                          "at",
                          "width"
                        ],
                        "type": "object"
                      },
                      "maxItems": 16,
                      "type": "array"
                    },
                    "w": {
                      "description": "Size along X.",
                      "maximum": 100,
                      "minimum": 0.5,
                      "multipleOf": 0.25,
                      "type": "number"
                    },
                    "walls": {
                      "default": true,
                      "type": "boolean"
                    },
                    "x": {
                      "description": "Smallest x corner.",
                      "maximum": 200,
                      "minimum": -200,
                      "multipleOf": 0.25,
                      "type": "number"
                    },
                    "z": {
                      "description": "Smallest z corner.",
                      "maximum": 200,
                      "minimum": -200,
                      "multipleOf": 0.25,
                      "type": "number"
                    }
                  },
                  "required": [
                    "name",
                    "x",
                    "z",
                    "w",
                    "d"
                  ],
                  "type": "object"
                },
                "maxItems": 64,
                "type": "array"
              },
              "markers": {
                "items": {
                  "additionalProperties": false,
                  "properties": {
                    "at": {
                      "description": "[x, y, z] metres, +Y up.",
                      "items": {
                        "type": "number"
                      },
                      "maxItems": 3,
                      "minItems": 3,
                      "type": "array"
                    },
                    "kind": {
                      "enum": [
                        "spawn",
                        "exit",
                        "pickup",
                        "enemy",
                        "checkpoint",
                        "light",
                        "camera",
                        "trigger"
                      ],
                      "type": "string"
                    },
                    "name": {
                      "description": "Becomes part of a node name: a-z, 0-9, _; unique in the level.",
                      "pattern": "^[a-z][a-z0-9_]{0,31}$",
                      "type": "string"
                    },
                    "rot": {
                      "default": 0,
                      "description": "Degrees, counter-clockwise seen from above. The marker faces its local +Z: 0 south (+Z), 90 east (+X), 180 north (-Z), -90 west.",
                      "maximum": 360,
                      "minimum": -360,
                      "type": "number"
                    }
                  },
                  "required": [
                    "name",
                    "kind",
                    "at"
                  ],
                  "type": "object"
                },
                "maxItems": 256,
                "minItems": 1,
                "type": "array"
              },
              "name": {
                "description": "Becomes part of a node name: a-z, 0-9, _; unique in the level.",
                "pattern": "^[a-z][a-z0-9_]{0,31}$",
                "type": "string"
              },
              "platforms": {
                "items": {
                  "additionalProperties": false,
                  "properties": {
                    "d": {
                      "description": "Size along Z.",
                      "maximum": 100,
                      "minimum": 0.5,
                      "multipleOf": 0.25,
                      "type": "number"
                    },
                    "name": {
                      "description": "Becomes part of a node name: a-z, 0-9, _; unique in the level.",
                      "pattern": "^[a-z][a-z0-9_]{0,31}$",
                      "type": "string"
                    },
                    "role": {
                      "default": "floor",
                      "enum": [
                        "floor",
                        "ground",
                        "path",
                        "trim",
                        "accent"
                      ],
                      "type": "string"
                    },
                    "thickness": {
                      "default": 0.3,
                      "maximum": 5,
                      "minimum": 0.05,
                      "type": "number"
                    },
                    "w": {
                      "description": "Size along X.",
                      "maximum": 100,
                      "minimum": 0.5,
                      "multipleOf": 0.25,
                      "type": "number"
                    },
                    "x": {
                      "description": "Smallest x corner.",
                      "maximum": 200,
                      "minimum": -200,
                      "multipleOf": 0.25,
                      "type": "number"
                    },
                    "y": {
                      "description": "The top surface's height.",
                      "maximum": 100,
                      "minimum": -50,
                      "type": "number"
                    },
                    "z": {
                      "description": "Smallest z corner.",
                      "maximum": 200,
                      "minimum": -200,
                      "multipleOf": 0.25,
                      "type": "number"
                    }
                  },
                  "required": [
                    "name",
                    "x",
                    "z",
                    "w",
                    "d",
                    "y"
                  ],
                  "type": "object"
                },
                "maxItems": 128,
                "type": "array"
              },
              "props": {
                "items": {
                  "additionalProperties": false,
                  "properties": {
                    "at": {
                      "description": "[x, y, z] metres, +Y up.",
                      "items": {
                        "type": "number"
                      },
                      "maxItems": 3,
                      "minItems": 3,
                      "type": "array"
                    },
                    "collide": {
                      "default": true,
                      "type": "boolean"
                    },
                    "kind": {
                      "enum": [
                        "crate",
                        "barrel",
                        "table",
                        "chair",
                        "bench",
                        "bed",
                        "shelf",
                        "counter",
                        "pillar",
                        "lamp",
                        "tree",
                        "bush",
                        "rock",
                        "planter",
                        "fence",
                        "sign",
                        "chest",
                        "pot"
                      ],
                      "type": "string"
                    },
                    "name": {
                      "description": "Becomes part of a node name: a-z, 0-9, _; unique in the level.",
                      "pattern": "^[a-z][a-z0-9_]{0,31}$",
                      "type": "string"
                    },
                    "rot": {
                      "default": 0,
                      "maximum": 360,
                      "minimum": -360,
                      "type": "number"
                    },
                    "scale": {
                      "default": 1,
                      "maximum": 4,
                      "minimum": 0.25,
                      "type": "number"
                    }
                  },
                  "required": [
                    "name",
                    "kind",
                    "at"
                  ],
                  "type": "object"
                },
                "maxItems": 512,
                "type": "array"
              },
              "ramps": {
                "items": {
                  "additionalProperties": false,
                  "properties": {
                    "d": {
                      "description": "Size along Z.",
                      "maximum": 100,
                      "minimum": 0.5,
                      "multipleOf": 0.25,
                      "type": "number"
                    },
                    "dir": {
                      "description": "n = -Z, s = +Z, e = +X, w = -X.",
                      "enum": [
                        "n",
                        "s",
                        "e",
                        "w"
                      ],
                      "type": "string"
                    },
                    "from_y": {
                      "description": "Height at the low end.",
                      "maximum": 100,
                      "minimum": -50,
                      "type": "number"
                    },
                    "name": {
                      "description": "Becomes part of a node name: a-z, 0-9, _; unique in the level.",
                      "pattern": "^[a-z][a-z0-9_]{0,31}$",
                      "type": "string"
                    },
                    "steps": {
                      "default": 0,
                      "description": "0 = a ramp (at most 40°); 2–64 = stairs (at most 50°).",
                      "maximum": 64,
                      "minimum": 0,
                      "type": "integer"
                    },
                    "to_y": {
                      "description": "Height at the `dir` end.",
                      "maximum": 100,
                      "minimum": -50,
                      "type": "number"
                    },
                    "w": {
                      "description": "Size along X.",
                      "maximum": 100,
                      "minimum": 0.5,
                      "multipleOf": 0.25,
                      "type": "number"
                    },
                    "x": {
                      "description": "Smallest x corner.",
                      "maximum": 200,
                      "minimum": -200,
                      "multipleOf": 0.25,
                      "type": "number"
                    },
                    "z": {
                      "description": "Smallest z corner.",
                      "maximum": 200,
                      "minimum": -200,
                      "multipleOf": 0.25,
                      "type": "number"
                    }
                  },
                  "required": [
                    "name",
                    "x",
                    "z",
                    "w",
                    "d",
                    "dir",
                    "from_y",
                    "to_y"
                  ],
                  "type": "object"
                },
                "maxItems": 64,
                "type": "array"
              },
              "style": {
                "additionalProperties": false,
                "properties": {
                  "outline": {
                    "default": true,
                    "type": "boolean"
                  },
                  "outline_width": {
                    "default": 0.03,
                    "maximum": 0.1,
                    "minimum": 0.005,
                    "type": "number"
                  },
                  "palette": {
                    "additionalProperties": false,
                    "properties": {
                      "accent": {
                        "pattern": "^#[0-9a-fA-F]{6}$",
                        "type": "string"
                      },
                      "floor": {
                        "pattern": "^#[0-9a-fA-F]{6}$",
                        "type": "string"
                      },
                      "foliage": {
                        "pattern": "^#[0-9a-fA-F]{6}$",
                        "type": "string"
                      },
                      "ground": {
                        "pattern": "^#[0-9a-fA-F]{6}$",
                        "type": "string"
                      },
                      "ink": {
                        "pattern": "^#[0-9a-fA-F]{6}$",
                        "type": "string"
                      },
                      "path": {
                        "pattern": "^#[0-9a-fA-F]{6}$",
                        "type": "string"
                      },
                      "prop": {
                        "pattern": "^#[0-9a-fA-F]{6}$",
                        "type": "string"
                      },
                      "trim": {
                        "pattern": "^#[0-9a-fA-F]{6}$",
                        "type": "string"
                      },
                      "wall": {
                        "pattern": "^#[0-9a-fA-F]{6}$",
                        "type": "string"
                      },
                      "water": {
                        "pattern": "^#[0-9a-fA-F]{6}$",
                        "type": "string"
                      }
                    },
                    "type": "object"
                  },
                  "shading": {
                    "default": "toon",
                    "enum": [
                      "toon",
                      "flat",
                      "lit"
                    ],
                    "type": "string"
                  }
                },
                "required": [],
                "type": "object"
              },
              "walls": {
                "items": {
                  "additionalProperties": false,
                  "properties": {
                    "from": {
                      "items": {
                        "description": "x or z",
                        "maximum": 200,
                        "minimum": -200,
                        "multipleOf": 0.25,
                        "type": "number"
                      },
                      "maxItems": 2,
                      "minItems": 2,
                      "type": "array"
                    },
                    "height": {
                      "default": 3,
                      "maximum": 20,
                      "minimum": 0.25,
                      "type": "number"
                    },
                    "name": {
                      "description": "Becomes part of a node name: a-z, 0-9, _; unique in the level.",
                      "pattern": "^[a-z][a-z0-9_]{0,31}$",
                      "type": "string"
                    },
                    "openings": {
                      "items": {
                        "additionalProperties": false,
                        "properties": {
                          "at": {
                            "description": "Metres along the wall from its start to the opening's near edge.",
                            "maximum": 200,
                            "minimum": -200,
                            "multipleOf": 0.25,
                            "type": "number"
                          },
                          "height": {
                            "default": 2.2,
                            "maximum": 20,
                            "minimum": 0.5,
                            "type": "number"
                          },
                          "sill": {
                            "default": 0,
                            "description": "0 = a door; above 0 = a window.",
                            "maximum": 10,
                            "minimum": 0,
                            "type": "number"
                          },
                          "width": {
                            "description": "Metres.",
                            "maximum": 100,
                            "minimum": 0.5,
                            "multipleOf": 0.25,
                            "type": "number"
                          }
                        },
                        "required": [
                          "at",
                          "width"
                        ],
                        "type": "object"
                      },
                      "maxItems": 16,
                      "type": "array"
                    },
                    "role": {
                      "default": "wall",
                      "enum": [
                        "wall",
                        "trim",
                        "foliage"
                      ],
                      "type": "string"
                    },
                    "thickness": {
                      "default": 0.2,
                      "maximum": 2,
                      "minimum": 0.05,
                      "type": "number"
                    },
                    "to": {
                      "description": "Along X or along Z only.",
                      "items": {
                        "description": "x or z",
                        "maximum": 200,
                        "minimum": -200,
                        "multipleOf": 0.25,
                        "type": "number"
                      },
                      "maxItems": 2,
                      "minItems": 2,
                      "type": "array"
                    },
                    "y": {
                      "description": "The base's height.",
                      "maximum": 100,
                      "minimum": -50,
                      "type": "number"
                    }
                  },
                  "required": [
                    "name",
                    "from",
                    "to"
                  ],
                  "type": "object"
                },
                "maxItems": 128,
                "type": "array"
              }
            },
            "required": [
              "name",
              "markers"
            ],
            "type": "object"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "spec"
        ],
        "type": "object"
      },
      "author_skin_input": {
        "additionalProperties": false,
        "properties": {
          "asset_id": {
            "description": "A .glb character (or a self-contained .gltf) a previous job of yours made",
            "format": "uuid",
            "type": "string"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "tone": {
            "description": "The skin tone, #rrggbb. Use one tone per character and reuse it across the cast. Omit to keep the model's own skin colour, evened out.",
            "pattern": "^#[0-9a-fA-F]{6}$",
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "asset_id"
        ],
        "type": "object"
      },
      "retexture_model_input": {
        "additionalProperties": false,
        "properties": {
          "asset_id": {
            "description": "A .glb (or a self-contained .gltf) a previous job of yours made",
            "format": "uuid",
            "type": "string"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "game_id": {
            "description": "A game of yours: its style lock (style, palette, anchors) shapes the repaint.",
            "pattern": "^[0-9a-f]{32}$",
            "type": "string"
          },
          "normal": {
            "default": false,
            "description": "Also derive a normal map.",
            "type": "boolean"
          },
          "palette": {
            "description": "Colours to paint with, #rrggbb.",
            "items": {
              "pattern": "^#[0-9a-fA-F]{6}$",
              "type": "string"
            },
            "maxItems": 8,
            "type": "array"
          },
          "prompt": {
            "description": "The new look: materials, colours, wear. The shape stays.",
            "maxLength": 4000,
            "minLength": 1,
            "type": "string"
          },
          "quality": {
            "default": "medium",
            "description": "low for drafts, medium for game art, high for key art.",
            "enum": [
              "low",
              "medium",
              "high"
            ],
            "type": "string"
          },
          "roughness": {
            "default": false,
            "description": "Also derive a roughness map.",
            "type": "boolean"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "asset_id",
          "prompt"
        ],
        "type": "object"
      },
      "generate_video_input": {
        "additionalProperties": false,
        "properties": {
          "aspect_ratio": {
            "description": "16:9 by default. Animating a still (image_url or image_asset_id), the clip keeps the still's shape; aspect_ratio with image_url is refused.",
            "enum": [
              "16:9",
              "9:16",
              "1:1"
            ],
            "type": "string"
          },
          "audio": {
            "default": false,
            "description": "Generated sound in the clip.",
            "type": "boolean"
          },
          "camera": {
            "additionalProperties": false,
            "description": "Camera words, mapped per model to its own camera control or to a fixed phrase after the prompt (caps.camera in _meta.models says which). A word the model does not take is refused, uncharged, naming the ones it does.",
            "properties": {
              "aperture": {
                "enum": [
                  "deep",
                  "shallow"
                ],
                "type": "string"
              },
              "lens": {
                "enum": [
                  "wide",
                  "normal",
                  "tele",
                  "macro"
                ],
                "type": "string"
              },
              "move": {
                "enum": [
                  "static",
                  "pan_left",
                  "pan_right",
                  "tilt_up",
                  "tilt_down",
                  "dolly_in",
                  "dolly_out",
                  "orbit_left",
                  "orbit_right",
                  "crane_up",
                  "handheld"
                ],
                "type": "string"
              },
              "speed": {
                "description": "How fast the move runs; needs a move other than static.",
                "enum": [
                  "slow",
                  "normal",
                  "fast"
                ],
                "type": "string"
              }
            },
            "type": "object"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "duration_seconds": {
            "default": 5,
            "description": "Seconds, priced per second; a length outside what the server renders is clamped.",
            "maximum": 30,
            "minimum": 2,
            "type": "integer"
          },
          "end_image_asset_id": {
            "description": "An image of yours: the clip's last frame, cropped to aspect_ratio; needs a first one",
            "format": "uuid",
            "type": "string"
          },
          "end_image_url": {
            "description": "The clip's last frame; needs a first one.",
            "pattern": "^https://",
            "type": "string"
          },
          "image_asset_id": {
            "description": "An image a previous job of yours made: the still to animate, in its own shape",
            "format": "uuid",
            "type": "string"
          },
          "image_url": {
            "description": "A still to animate, the first frame (key art, a target frame).",
            "pattern": "^https://",
            "type": "string"
          },
          "model": {
            "type": "string",
            "description": "Optional: a model this tool offers, by its id from `GET /v1/tools/models`; omit it for our pick."
          },
          "prompt": {
            "description": "What happens in the clip: subject, motion, camera. With references, name them \"Image 1\", \"Image 2\"…",
            "maxLength": 4000,
            "minLength": 1,
            "type": "string"
          },
          "references": {
            "description": "Pictures whose subjects the clip keeps (a character, a prop), each an image asset id of yours or an https URL, in order: Image 1, Image 2… Not with a still to animate.",
            "items": {
              "pattern": "^(https://.+|[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12})$",
              "type": "string"
            },
            "maxItems": 4,
            "type": "array"
          },
          "resolution": {
            "default": "720p",
            "description": "Priced per second by resolution. The engine priced per clip (the 5 s and 10 s rows) draws at its own resolution and takes no `audio` or `seed`.",
            "enum": [
              "480p",
              "720p",
              "1080p"
            ],
            "type": "string"
          },
          "seed": {
            "maximum": 2147483647,
            "minimum": 0,
            "type": "integer"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "prompt"
        ],
        "type": "object"
      },
      "edit_video_input": {
        "additionalProperties": false,
        "properties": {
          "aspect_ratio": {
            "description": "Omit to keep the clip's shape.",
            "enum": [
              "16:9",
              "9:16",
              "1:1"
            ],
            "type": "string"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "duration_seconds": {
            "description": "Keep this many seconds from the start (a value outside 2–10 is clamped); omit for the whole clip (quoted at 10 s, charged the seconds made).",
            "maximum": 10,
            "minimum": 2,
            "type": "integer"
          },
          "keep_audio": {
            "default": false,
            "description": "Keep the clip's own sound; otherwise the engine decides whether to make new sound.",
            "type": "boolean"
          },
          "model": {
            "type": "string",
            "description": "Optional: a model this tool offers, by its id from `GET /v1/tools/models`; omit it for our pick."
          },
          "prompt": {
            "description": "The edit, as an instruction: \"make it night and snowing\", \"replace the car with a dragon\", \"watercolour style\".",
            "maxLength": 4000,
            "minLength": 1,
            "type": "string"
          },
          "reference_image_asset_id": {
            "description": "An image of yours the edit follows (a character, a look)",
            "format": "uuid",
            "type": "string"
          },
          "reference_image_url": {
            "description": "Or that picture at an https URL.",
            "pattern": "^https://",
            "type": "string"
          },
          "resolution": {
            "default": "720p",
            "description": "Priced per second of the edited clip by resolution.",
            "enum": [
              "720p",
              "1080p"
            ],
            "type": "string"
          },
          "seed": {
            "maximum": 2147483647,
            "minimum": 0,
            "type": "integer"
          },
          "video_asset_id": {
            "description": "A clip a previous job of yours made (MP4 or MOV, 2–10 s)",
            "format": "uuid",
            "type": "string"
          },
          "video_url": {
            "description": "Or a clip at an https URL: the engine takes MP4 or MOV, 2–10 s, up to 100 MB, and a URL is only read when the job runs.",
            "pattern": "^https://",
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "prompt"
        ],
        "type": "object"
      },
      "lip_sync_input": {
        "additionalProperties": false,
        "properties": {
          "audio_asset_id": {
            "description": "The speech: a file of yours — voice_line's line.mp3 or dialogue's dialogue.mp3 (MP3 or WAV, at most 60 s)",
            "format": "uuid",
            "type": "string"
          },
          "audio_url": {
            "description": "Or the speech at an https URL: the engine takes mp3, wav, m4a, aac or ogg, under 10 MB, at most 60 s, and a URL is only read when the job runs. Quoted at the 60 s most, charged the seconds made.",
            "pattern": "^https://",
            "type": "string"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "duration_seconds": {
            "description": "The speech's length, whole seconds rounded up (voice_line's result says it): the quote. Omit to be quoted at 60 s; charged the seconds made. Only with audio_asset_id: a longer file is refused, uncharged.",
            "maximum": 60,
            "minimum": 1,
            "type": "integer"
          },
          "image_asset_id": {
            "description": "The portrait: an image of yours (an earlier job's, or import_asset) — one clear face toward the camera",
            "format": "uuid",
            "type": "string"
          },
          "image_url": {
            "description": "Or the portrait at an https URL.",
            "pattern": "^https://",
            "type": "string"
          },
          "model": {
            "type": "string",
            "description": "Optional: a model this tool offers, by its id from `GET /v1/tools/models`; omit it for our pick."
          },
          "resolution": {
            "default": "720p",
            "description": "Priced per second of the clip by resolution.",
            "enum": [
              "480p",
              "720p"
            ],
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [],
        "type": "object"
      },
      "cutout_input": {
        "additionalProperties": false,
        "properties": {
          "asset_id": {
            "description": "A picture of yours (a job's image, or import_asset): PNG, JPEG, WebP or GIF, at most 4096 px a side",
            "format": "uuid",
            "type": "string"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "mask": {
            "default": false,
            "description": "Also return mask.png, the subject's mask (white on black).",
            "type": "boolean"
          },
          "subject": {
            "default": "general",
            "description": "general: objects, characters, props. portrait: a person. matting: hair, fur, smoke — soft edges kept as partial transparency.",
            "enum": [
              "general",
              "portrait",
              "matting"
            ],
            "type": "string"
          },
          "trim": {
            "default": false,
            "description": "Crop cutout.png to the subject, 2 px of margin.",
            "type": "boolean"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "asset_id"
        ],
        "type": "object"
      },
      "upscale_input": {
        "additionalProperties": false,
        "properties": {
          "asset_id": {
            "description": "A picture of yours (a job's image, or import_asset), at most 1024 px a side",
            "format": "uuid",
            "type": "string"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "creativity": {
            "default": 0.35,
            "description": "How much new detail it may invent: 0 stays closest to the source.",
            "maximum": 1,
            "minimum": 0,
            "type": "number"
          },
          "factor": {
            "default": 2,
            "description": "Two or four times the source's size: 1024 px becomes 2048 or 4096.",
            "enum": [
              2,
              4
            ],
            "type": "integer"
          },
          "prompt": {
            "description": "Optional: what the picture is (\"pixel-art knight, crisp edges\"), to steer the detail added.",
            "maxLength": 4000,
            "minLength": 1,
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "asset_id"
        ],
        "type": "object"
      },
      "transcribe_words_input": {
        "additionalProperties": false,
        "properties": {
          "asset_id": {
            "description": "Audio or video of yours (MP3, WAV, M4A, MP4, MOV, WebM; a job's output or an upload), at most 30 minutes",
            "format": "uuid",
            "type": "string"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "language": {
            "description": "The language spoken, as a code (en, es, pt-BR). Omit to detect it.",
            "pattern": "^[a-z]{2,3}(-[A-Za-z]{2,4})?$",
            "type": "string"
          },
          "speakers": {
            "default": false,
            "description": "Tell speakers apart: each word carries its speaker.",
            "type": "boolean"
          },
          "translate_to": {
            "description": "Also translate every sentence into this language, times kept: translated.<code>.srt and .vtt.",
            "pattern": "^[a-z]{2,3}(-[A-Za-z]{2,4})?$",
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "asset_id"
        ],
        "type": "object"
      },
      "caption_video_input": {
        "additionalProperties": false,
        "properties": {
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "format": {
            "default": "srt",
            "description": "srt or vtt: caption files (both come back, the one asked first). burned: captioned.mp4 with the captions drawn in, plus the files.",
            "enum": [
              "srt",
              "vtt",
              "burned"
            ],
            "type": "string"
          },
          "language": {
            "description": "The language spoken, as a code. Omit to detect it.",
            "pattern": "^[a-z]{2,3}(-[A-Za-z]{2,4})?$",
            "type": "string"
          },
          "safe_area": {
            "default": "none",
            "description": "With burned: social keeps captions clear of a vertical app's buttons and caption text (9:16 feeds); none puts them low in the frame.",
            "enum": [
              "none",
              "social"
            ],
            "type": "string"
          },
          "style": {
            "default": "block",
            "description": "block: up to 7 words on a dark band. word-pop: up to 3 words, the one being said lit in colour.",
            "enum": [
              "block",
              "word-pop"
            ],
            "type": "string"
          },
          "transcript_asset_id": {
            "description": "Optional: a transcript.json from transcribe_words (yours, edited or not): captions from it, nothing transcribed or charged for the words",
            "format": "uuid",
            "type": "string"
          },
          "video_asset_id": {
            "description": "A clip of yours (MP4, MOV or WebM), at most 10 minutes",
            "format": "uuid",
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "video_asset_id"
        ],
        "type": "object"
      },
      "split_stems_input": {
        "additionalProperties": false,
        "properties": {
          "asset_id": {
            "description": "A recording of yours, or a video whose sound to split (MP3, WAV, M4A, OGG, FLAC, MP4, MOV, WebM; a job's output, import_asset or upload_asset), at most 10 minutes",
            "format": "uuid",
            "type": "string"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "duration_seconds": {
            "description": "The recording's length in whole seconds, rounded up: the quote. Omit to be quoted at 10 minutes; a longer file than said is refused, uncharged.",
            "maximum": 600,
            "minimum": 1,
            "type": "integer"
          },
          "format": {
            "default": "mp3",
            "description": "mp3, or wav to edit without another lossy pass. Stems are never mastered: they sum back to the mix.",
            "enum": [
              "mp3",
              "wav"
            ],
            "type": "string"
          },
          "stems": {
            "description": "The stems to make; omit for all four. other is everything that is not vocals, drums or bass.",
            "items": {
              "enum": [
                "vocals",
                "drums",
                "bass",
                "other"
              ],
              "type": "string"
            },
            "maxItems": 4,
            "minItems": 1,
            "type": "array",
            "uniqueItems": true
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "asset_id"
        ],
        "type": "object"
      },
      "isolate_voice_input": {
        "additionalProperties": false,
        "properties": {
          "asset_id": {
            "description": "A recording of yours, or a video whose sound to clean (MP3, WAV, M4A, OGG, FLAC, MP4, MOV, WebM; a job's output, import_asset or upload_asset), at most an hour",
            "format": "uuid",
            "type": "string"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "duration_seconds": {
            "description": "The recording's length in whole seconds, rounded up: the quote. Omit to be quoted at an hour; a longer file than said is refused, uncharged.",
            "maximum": 3600,
            "minimum": 1,
            "type": "integer"
          },
          "format": {
            "default": "mp3",
            "description": "mp3, or wav (decoded from the mp3) to edit without another lossy pass. Not mastered: the voice keeps the recording's own level.",
            "enum": [
              "mp3",
              "wav"
            ],
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "asset_id"
        ],
        "type": "object"
      },
      "beat_grid_input": {
        "additionalProperties": false,
        "properties": {
          "asset_id": {
            "description": "The music: a recording of yours, or a video whose sound to read. A cut list without it reads the video's own sound",
            "format": "uuid",
            "type": "string"
          },
          "beats_per_bar": {
            "default": 4,
            "description": "4 for most music, 3 for a waltz.",
            "maximum": 7,
            "minimum": 2,
            "type": "integer"
          },
          "beats_per_cut": {
            "description": "cut_list: beats a shot lasts; omit for the power of two nearest 1.8 s.",
            "maximum": 16,
            "minimum": 1,
            "type": "integer"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "mode": {
            "default": "grid",
            "description": "grid: the tempo, every beat and downbeat, the bars. cut_list: a video of yours cut to target_seconds with every cut on a beat.",
            "enum": [
              "grid",
              "cut_list"
            ],
            "type": "string"
          },
          "render": {
            "default": false,
            "description": "cut_list: also render cut.mp4, the cut with the music under it.",
            "type": "boolean"
          },
          "target_seconds": {
            "description": "cut_list: how long the cut runs at most; it ends on a beat.",
            "maximum": 120,
            "minimum": 1,
            "type": "number"
          },
          "video_asset_id": {
            "description": "cut_list: the video to cut (MP4, MOV or WebM)",
            "format": "uuid",
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [],
        "type": "object"
      },
      "mask_subject_input": {
        "additionalProperties": false,
        "properties": {
          "box": {
            "additionalProperties": false,
            "description": "A box around the subject on the first frame, in pixels.",
            "properties": {
              "x_max": {
                "minimum": 1,
                "type": "integer"
              },
              "x_min": {
                "minimum": 0,
                "type": "integer"
              },
              "y_max": {
                "minimum": 1,
                "type": "integer"
              },
              "y_min": {
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "x_min",
              "y_min",
              "x_max",
              "y_max"
            ],
            "type": "object"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "duration_seconds": {
            "description": "The clip's length in whole seconds, rounded up: the quote. Omit to be quoted at 30 s; a longer clip than said is refused, uncharged.",
            "maximum": 30,
            "minimum": 1,
            "type": "integer"
          },
          "format": {
            "default": "webm",
            "description": "webm: subject.webm, the subject on a transparent background. png: mask_frames.zip, a grayscale PNG a frame. mask: only mask.mp4. mask.mp4 (white subject on black) always comes back.",
            "enum": [
              "webm",
              "png",
              "mask"
            ],
            "type": "string"
          },
          "label": {
            "description": "What the subject is, in a few words (dog, red car). With no points, box or label: the main subject, in the middle of the first frame.",
            "pattern": "^[A-Za-z][A-Za-z0-9 '-]{0,39}$",
            "type": "string"
          },
          "points": {
            "description": "Pixels of the first frame, in the clip's own size: label 1 on the subject, 0 on what is not it.",
            "items": {
              "additionalProperties": false,
              "properties": {
                "label": {
                  "default": 1,
                  "enum": [
                    0,
                    1
                  ],
                  "type": "integer"
                },
                "x": {
                  "minimum": 0,
                  "type": "integer"
                },
                "y": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "required": [
                "x",
                "y"
              ],
              "type": "object"
            },
            "maxItems": 8,
            "type": "array"
          },
          "video_asset_id": {
            "description": "A clip of yours (MP4, MOV or WebM; a job's output, import_asset or upload_asset), at most 30 seconds",
            "format": "uuid",
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "video_asset_id"
        ],
        "type": "object"
      },
      "make_shorts_input": {
        "additionalProperties": false,
        "properties": {
          "aspect": {
            "default": "9:16",
            "description": "9:16 (1080×1920) for vertical feeds, 1:1 (1080×1080) for square ones. The frame is cropped to it in the middle.",
            "enum": [
              "9:16",
              "1:1"
            ],
            "type": "string"
          },
          "captions": {
            "default": "none",
            "description": "Burn the words in: block (a few words on a band) or word-pop (the word being said lit). none: no captions.",
            "enum": [
              "none",
              "block",
              "word-pop"
            ],
            "type": "string"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "count": {
            "default": 3,
            "description": "How many shorts to make, best first.",
            "maximum": 10,
            "minimum": 1,
            "type": "integer"
          },
          "duration_seconds": {
            "description": "The video's length in whole seconds, rounded up: the quote. Omit to be quoted at an hour; a longer video than said is refused, uncharged.",
            "maximum": 3600,
            "minimum": 1,
            "type": "integer"
          },
          "language": {
            "description": "The language spoken, as a code (en, es, pt-BR). Omit to detect it.",
            "pattern": "^[a-z]{2,3}(-[A-Za-z]{2,4})?$",
            "type": "string"
          },
          "max_seconds": {
            "default": 60,
            "description": "The longest a short may run.",
            "maximum": 60,
            "minimum": 15,
            "type": "integer"
          },
          "min_seconds": {
            "default": 15,
            "description": "The shortest a short may run.",
            "maximum": 60,
            "minimum": 15,
            "type": "integer"
          },
          "safe_area": {
            "default": "social",
            "description": "With captions: social keeps them clear of a feed's buttons and caption text; none puts them low in the frame.",
            "enum": [
              "social",
              "none"
            ],
            "type": "string"
          },
          "transcript_asset_id": {
            "description": "Optional: a transcript.json of this video (transcribe_words, or an earlier make_shorts): the moments picked from it, nothing transcribed or charged for the words",
            "format": "uuid",
            "type": "string"
          },
          "video_asset_id": {
            "description": "A long video of yours (MP4, MOV or WebM; a job's output, import_asset or upload_asset, at most 200 MB), at most an hour",
            "format": "uuid",
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "video_asset_id"
        ],
        "type": "object"
      },
      "search_footage_input": {
        "additionalProperties": false,
        "properties": {
          "by": {
            "default": "both",
            "description": "said: search the speech. seen: search frames (one every 2 s, at most 120). both: either, a moment found both ways ranked higher.",
            "enum": [
              "both",
              "said",
              "seen"
            ],
            "type": "string"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "cut": {
            "default": false,
            "description": "Also cut each moment out as its own clip (match_01.mp4…).",
            "type": "boolean"
          },
          "duration_seconds": {
            "description": "The video's length in whole seconds, rounded up: the quote. Omit to be quoted at an hour; a longer video than said is refused, uncharged.",
            "maximum": 3600,
            "minimum": 1,
            "type": "integer"
          },
          "language": {
            "description": "The language spoken, as a code. Omit to detect it.",
            "pattern": "^[a-z]{2,3}(-[A-Za-z]{2,4})?$",
            "type": "string"
          },
          "max_results": {
            "default": 5,
            "description": "At most this many moments, best first.",
            "maximum": 20,
            "minimum": 1,
            "type": "integer"
          },
          "query": {
            "description": "What to find, in words: \"the part about pricing\", \"a red car at night\".",
            "maxLength": 200,
            "minLength": 1,
            "pattern": "^[^\\u0000-\\u001F<>{}\\[\\]\\\\`]{1,200}$",
            "type": "string"
          },
          "transcript_asset_id": {
            "description": "Optional: a transcript.json of this video: what is said searched in it, nothing transcribed or charged for the words",
            "format": "uuid",
            "type": "string"
          },
          "video_asset_id": {
            "description": "A video of yours (MP4, MOV or WebM; a job's output, import_asset or upload_asset, at most 200 MB), at most an hour",
            "format": "uuid",
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "video_asset_id",
          "query"
        ],
        "type": "object"
      },
      "detect_chords_input": {
        "additionalProperties": false,
        "properties": {
          "asset_id": {
            "description": "A recording of yours, or a video whose sound to read (MP3, WAV, M4A, OGG, FLAC, MP4, MOV, WebM), its first 10 minutes read",
            "format": "uuid",
            "type": "string"
          },
          "beats_per_bar": {
            "default": 4,
            "description": "4 for most music, 3 for a waltz: how the chart's bars are counted.",
            "maximum": 7,
            "minimum": 2,
            "type": "integer"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "asset_id"
        ],
        "type": "object"
      },
      "backing_track_input": {
        "additionalProperties": false,
        "properties": {
          "beats_per_bar": {
            "description": "The metre's beats; default 4.",
            "maximum": 7,
            "minimum": 2,
            "type": "integer"
          },
          "bpm": {
            "description": "The tempo; default 100 (or the chords.json's).",
            "maximum": 240,
            "minimum": 40,
            "type": "integer"
          },
          "chart": {
            "description": "The chords, a bar between bar lines: \"| C | G | Am F | % |\" (% repeats a bar, N.C. is no chord), or a chord a bar: \"C G Am F\". Up to 64 bars. Or give chords_asset_id.",
            "maxLength": 2000,
            "minLength": 1,
            "pattern": "^[A-GNa-dgijmsu0-9#/|%. \\n]{1,2000}$",
            "type": "string"
          },
          "chords_asset_id": {
            "description": "Instead of chart: a chords.json of yours from detect_chords; its chart, key and tempo are used unless you give them",
            "format": "uuid",
            "type": "string"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "key": {
            "description": "The key: \"C major\", \"F# minor\".",
            "pattern": "^[A-G][#b]? (major|minor)$",
            "type": "string"
          },
          "length": {
            "default": "clip",
            "description": "clip: about 30 s, to loop. full: a whole track, priced as one.",
            "enum": [
              "clip",
              "full"
            ],
            "type": "string"
          },
          "style": {
            "description": "The band and the feel: \"warm indie pop, brushed drums, Rhodes, upright bass\".",
            "maxLength": 300,
            "minLength": 1,
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "style"
        ],
        "type": "object"
      },
      "brand_kit_input": {
        "additionalProperties": false,
        "properties": {
          "asset_id": {
            "description": "A logo or brand picture of yours (PNG, JPEG, WebP or GIF, at most 4096 px a side; a transparent background is ignored)",
            "format": "uuid",
            "type": "string"
          },
          "colors": {
            "default": 5,
            "description": "How many colours to read from it before the roles are given.",
            "maximum": 8,
            "minimum": 3,
            "type": "integer"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "name": {
            "description": "The brand's name, drawn on the swatch card.",
            "pattern": "^[A-Za-z0-9 &'.,!-]{1,40}$",
            "type": "string"
          },
          "personality": {
            "description": "The type pairing's character; omit to read it from the palette.",
            "enum": [
              "playful",
              "friendly",
              "bold",
              "technical",
              "elegant",
              "classic"
            ],
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "asset_id"
        ],
        "type": "object"
      },
      "resize_design_input": {
        "additionalProperties": false,
        "properties": {
          "asset_id": {
            "description": "A picture of yours (PNG, JPEG, WebP or GIF, at most 6000 px a side)",
            "format": "uuid",
            "type": "string"
          },
          "background": {
            "description": "With pad: the colour, #RRGGBB (default: the picture's own border).",
            "pattern": "^#[0-9A-Fa-f]{6}$",
            "type": "string"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "fit": {
            "default": "auto",
            "description": "crop: where the picture's detail is. extend: the whole picture over a blurred copy of itself. pad: the whole picture on a flat colour. auto: crop when it keeps most of the detail, else extend.",
            "enum": [
              "auto",
              "crop",
              "extend",
              "pad"
            ],
            "type": "string"
          },
          "format": {
            "default": "png",
            "enum": [
              "png",
              "jpeg"
            ],
            "type": "string"
          },
          "sizes": {
            "description": "Named sizes (square 1080×1080, portrait 1080×1350, story 1080×1920, landscape 1920×1080, thumbnail 1280×720, link_card 1200×630, banner 1500×500, wide 1600×900) or {width, height} of your own. Omit for square, portrait, story, landscape and link_card.",
            "items": {
              "oneOf": [
                {
                  "enum": [
                    "square",
                    "portrait",
                    "story",
                    "landscape",
                    "thumbnail",
                    "link_card",
                    "banner",
                    "wide"
                  ],
                  "type": "string"
                },
                {
                  "additionalProperties": false,
                  "properties": {
                    "height": {
                      "maximum": 4096,
                      "minimum": 16,
                      "type": "integer"
                    },
                    "name": {
                      "pattern": "^[a-z0-9_-]{1,32}$",
                      "type": "string"
                    },
                    "width": {
                      "maximum": 4096,
                      "minimum": 16,
                      "type": "integer"
                    }
                  },
                  "required": [
                    "width",
                    "height"
                  ],
                  "type": "object"
                }
              ]
            },
            "maxItems": 12,
            "minItems": 1,
            "type": "array"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "asset_id"
        ],
        "type": "object"
      },
      "make_deck_input": {
        "additionalProperties": false,
        "properties": {
          "aspect": {
            "default": "16:9",
            "description": "1920×1080 or 1440×1080 pages.",
            "enum": [
              "16:9",
              "4:3"
            ],
            "type": "string"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "kit_asset_id": {
            "description": "Optional: a kit.json from brand_kit: the deck takes its paper, ink and primary colours",
            "format": "uuid",
            "type": "string"
          },
          "markdown": {
            "description": "The outline. Slides split at --- lines, or at each # or ## heading (the slide's title); - bullets (two spaces in for a second level), > quotes, ``` code, **bold**, \"Note:\" lines for speaker notes. A picture is ![alt](asset:<asset_id>), one of yours, at most 20; no URLs. At most 60 slides.",
            "maxLength": 40000,
            "minLength": 1,
            "type": "string"
          },
          "theme": {
            "default": "light",
            "enum": [
              "light",
              "dark"
            ],
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "markdown"
        ],
        "type": "object"
      },
      "list_characters_input": {
        "additionalProperties": false,
        "properties": {
          "body": {
            "enum": [
              "biped",
              "quadruped",
              "flyer"
            ],
            "type": "string"
          },
          "medium": {
            "description": "Only 2D sprite sheets or only rigged 3D models; omit for both.",
            "enum": [
              "2d",
              "3d"
            ],
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [],
        "type": "object"
      },
      "get_character_input": {
        "additionalProperties": false,
        "properties": {
          "files": {
            "description": "Only these files (e.g. [\"sheet.png\", \"sheet.json\"]); omit for all.",
            "items": {
              "pattern": "^[A-Za-z0-9._-]{1,64}$",
              "type": "string"
            },
            "maxItems": 16,
            "type": "array"
          },
          "id": {
            "description": "A character id list_characters returned, e.g. \"fox-2d\".",
            "pattern": "^[a-z0-9-]{1,40}$",
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "id"
        ],
        "type": "object"
      },
      "restyle_character_input": {
        "additionalProperties": false,
        "properties": {
          "animations": {
            "description": "2D only: redraw just these cycles (fewer frames, less cost); omit for all. A cycle the character has not got is refused (a flyer has no jump).",
            "items": {
              "enum": [
                "idle",
                "walk",
                "run",
                "jump",
                "attack",
                "hit",
                "death",
                "blink"
              ],
              "type": "string"
            },
            "type": "array"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "game_id": {
            "description": "A game of yours: its style lock and anchors shape the look.",
            "pattern": "^[0-9a-f]{32}$",
            "type": "string"
          },
          "id": {
            "description": "A character id list_characters returned.",
            "pattern": "^[a-z0-9-]{1,40}$",
            "type": "string"
          },
          "palette": {
            "description": "3D only: colours the repaint keeps to.",
            "items": {
              "pattern": "^#[0-9a-fA-F]{6}$",
              "type": "string"
            },
            "maxItems": 8,
            "type": "array"
          },
          "prompt": {
            "description": "The new look: who it is now, materials, colours. The motions stay.",
            "maxLength": 4000,
            "minLength": 1,
            "type": "string"
          },
          "quality": {
            "default": "medium",
            "description": "low for drafts, medium for game art, high for key art.",
            "enum": [
              "low",
              "medium",
              "high"
            ],
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "id",
          "prompt"
        ],
        "type": "object"
      },
      "author_motion_input": {
        "additionalProperties": false,
        "properties": {
          "asset_id": {
            "description": "A rigged humanoid .glb of yours (get_character, rig_model, generate_3d_model with animations)",
            "format": "uuid",
            "type": "string"
          },
          "base_clip": {
            "description": "The stance to build on: this clip's first frame (default idle).",
            "pattern": "^[A-Za-z0-9_.|: -]{1,64}$",
            "type": "string"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "motions": {
            "description": "Each clip as data: a kind and its dials, each inside the range the kind was tuned in (a value outside is refused, naming it). wave: seconds 0.8-3, lift_deg 60-160, swings 1-5, swing_deg 10-40, side. nod: seconds 0.4-2, times 1-3, depth_deg 5-30. hop: seconds 0.4-1.2, height 0.03-0.25, crouch 0-0.12. strike: seconds 0.3-1.5, windup_share 0.2-0.5, reach_deg 40-110, lean_deg 0-25, side. flinch: seconds 0.2-0.8, lean_deg 5-30. celebrate: seconds 0.8-3, lift_deg 100-170, bounces 1-4.",
            "items": {
              "additionalProperties": false,
              "properties": {
                "bounces": {
                  "type": "number"
                },
                "crouch": {
                  "type": "number"
                },
                "depth_deg": {
                  "type": "number"
                },
                "height": {
                  "type": "number"
                },
                "kind": {
                  "enum": [
                    "celebrate",
                    "flinch",
                    "hop",
                    "nod",
                    "strike",
                    "wave"
                  ],
                  "type": "string"
                },
                "lean_deg": {
                  "type": "number"
                },
                "lift_deg": {
                  "type": "number"
                },
                "name": {
                  "description": "The clip's name; the kind's when omitted. Must not be a clip the model has.",
                  "pattern": "^[a-z][a-z0-9_]{0,31}$",
                  "type": "string"
                },
                "reach_deg": {
                  "type": "number"
                },
                "seconds": {
                  "type": "number"
                },
                "side": {
                  "description": "wave and strike: which arm.",
                  "enum": [
                    "left",
                    "right"
                  ],
                  "type": "string"
                },
                "swing_deg": {
                  "type": "number"
                },
                "swings": {
                  "type": "number"
                },
                "times": {
                  "type": "number"
                },
                "windup_share": {
                  "type": "number"
                }
              },
              "required": [
                "kind"
              ],
              "type": "object"
            },
            "maxItems": 12,
            "minItems": 1,
            "type": "array"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "asset_id",
          "motions"
        ],
        "type": "object"
      },
      "retarget_clips_input": {
        "additionalProperties": false,
        "properties": {
          "asset_id": {
            "description": "The rigged model of yours that receives the clips",
            "format": "uuid",
            "type": "string"
          },
          "clips": {
            "description": "Only these (each starts with a letter); omit for all. A name the model already has is refused.",
            "items": {
              "pattern": "^[A-Za-z][A-Za-z0-9_]{0,31}$",
              "type": "string"
            },
            "maxItems": 32,
            "type": "array"
          },
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "donor_asset_id": {
            "description": "A rigged model of yours carrying the clips",
            "format": "uuid",
            "type": "string"
          },
          "donor_character": {
            "description": "Or a 3D library character's clips, e.g. \"robot-3d\".",
            "pattern": "^[a-z0-9-]{1,40}$",
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "asset_id"
        ],
        "type": "object"
      },
      "play_input": {
        "additionalProperties": false,
        "properties": {
          "confirm_cost": {
            "description": "Set true to run a call that costs more than the confirm threshold.",
            "type": "boolean"
          },
          "criteria": {
            "description": "What to judge from the screen, e.g. \"a hit flashes the enemy\".",
            "items": {
              "maxLength": 300,
              "minLength": 1,
              "type": "string"
            },
            "maxItems": 12,
            "type": "array"
          },
          "game_id": {
            "description": "A game of yours (funpixel.json game_id).",
            "pattern": "^[0-9a-f]{32}$",
            "type": "string"
          },
          "max_acts": {
            "default": 16,
            "maximum": 30,
            "minimum": 1,
            "type": "integer"
          },
          "orientation": {
            "description": "Turn the phone from the game's own orientation.",
            "enum": [
              "portrait",
              "landscape"
            ],
            "type": "string"
          },
          "premise": {
            "description": "The store description (four to six sentences), when a new player would have read one.",
            "maxLength": 1500,
            "minLength": 40,
            "type": "string"
          },
          "viewport": {
            "default": "phone",
            "enum": [
              "phone",
              "desktop"
            ],
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "pattern": "^https://",
            "description": "Where to POST the finished job once: https, a public host. The submit answer carries the signing secret."
          }
        },
        "required": [
          "game_id"
        ],
        "type": "object"
      }
    },
    "securitySchemes": {
      "bearer": {
        "description": "An `fp_live_` API key, or a signed-in session's token.",
        "scheme": "bearer",
        "type": "http"
      }
    }
  },
  "info": {
    "description": "The Funpixel HTTP API: the Tools API (tools, jobs, usage, keys), the hosted\nMCP, drafts and uploads, the game tools and Community. Guides:\nhttps://docs.funpixel.ai.\n\nEvery route needs a paid plan. An `fp_live_` key reaches a route only with\nthe scope named in its `x-funpixel-scope`; `session` routes take a\nsigned-in session only. The community reads also\nanswer with no credential at all (no `viewer` state), as the apps do.\n\nRate limits (https://docs.funpixel.ai/agents/limits/): every\nanswer a limit counted carries `RateLimit-Policy` and `RateLimit`\n(draft-ietf-httpapi-ratelimit-headers-11) and `RateLimit-Limit`,\n`RateLimit-Remaining`, `RateLimit-Reset`; every 429 carries `Retry-After`.\nA submit past its window is 429 `submit_rate_limited` or\n`kind_rate_limited`; a paid submit while the limiter cannot answer is 503\n`rate_limit_unavailable`.\n\nServed as JSON at `GET /openapi.json`, with one path and one request\nschema per tool (`/v1/tools/<tool>`, from the MCP's own schemas).\n",
    "summary": "The routes an outside agent, funtools and the hosted MCP call.",
    "title": "Funpixel Agent Platform API",
    "version": "1"
  },
  "openapi": "3.1.0",
  "paths": {
    "/.well-known/oauth-protected-resource": {
      "get": {
        "operationId": "protectedResourceMetadata",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "description": "RFC 9728 metadata for the MCP."
          }
        },
        "security": [],
        "tags": [
          "mcp"
        ]
      }
    },
    "/.well-known/oauth-protected-resource/mcp": {
      "get": {
        "operationId": "protectedResourceMetadataMcp",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "description": "The same document, path-inserted."
          }
        },
        "security": [],
        "tags": [
          "mcp"
        ]
      }
    },
    "/mcp": {
      "post": {
        "description": "The hosted MCP, JSON-RPC over stateless Streamable HTTP. Setup: https://docs.funpixel.ai/agents/connect/.",
        "operationId": "mcp",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "A JSON-RPC response, or a per-call SSE stream."
          },
          "202": {
            "accepted.": null,
            "description": "A notification"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "mcp"
        ],
        "x-funpixel-scope": "per method"
      }
    },
    "/openapi.json": {
      "get": {
        "description": "This document as JSON, with a path and a request schema per tool. Anonymous;\n`Cache-Control: public, max-age=3600`. It changes only with a deploy.\n",
        "operationId": "getOpenApi",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "description": "The OpenAPI 3.1 document."
          }
        },
        "security": [],
        "tags": [
          "meta"
        ]
      }
    },
    "/v1/cli/keys": {
      "post": {
        "description": "What `funtools login` calls. The bearer is the OAuth access token of the\ndevice flow `funtools login` runs, issued for this route (`at+jwt`); any\nother token is 401. Mints one key\nnamed for the machine, with the scopes the body names, else the default set\n(every scope but `community:read` / `community:write`); 503 `unavailable` while sign-in is\noff. 429 `rate_limited` past 10 an hour per account; 409 at the key cap.\n",
        "operationId": "mintCliKey",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "hostname": {
                    "description": "The key is named \"funtools on <hostname>\".",
                    "type": "string"
                  },
                  "scopes": {
                    "description": "`funtools login --scope`. Absent = the default set; an unknown word is 400 `invalid_input`.",
                    "items": {
                      "$ref": "#/components/schemas/Scope"
                    },
                    "minItems": 1,
                    "type": "array"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": false
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "key": {
                      "$ref": "#/components/schemas/ApiKey"
                    },
                    "secret": {
                      "pattern": "^fp_live_",
                      "type": "string"
                    }
                  },
                  "required": [
                    "key",
                    "secret"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "The key and its secret, shown once."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "keys"
        ],
        "x-funpixel-scope": "cli-sign-in"
      }
    },
    "/v1/explore": {
      "get": {
        "description": "Discover. With a `community:read` key or a session, each game's `viewer`\nflags are that account's; with no credential they are all false. Only games\nshared to Community are listed to a visitor.\n",
        "operationId": "explore",
        "parameters": [
          {
            "in": "query",
            "name": "sort",
            "schema": {
              "default": "newest",
              "enum": [
                "newest",
                "stars",
                "trending",
                "most_played"
              ],
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "q",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "genre",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "default": 24,
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "schema": {
              "default": 0,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "has_more": {
                      "type": "boolean"
                    },
                    "offset": {
                      "type": "integer"
                    },
                    "projects": {
                      "items": {
                        "$ref": "#/components/schemas/CommunityGame"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "projects",
                    "has_more",
                    "offset"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "One page of games."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "security": [
          {
            "bearer": []
          },
          {}
        ],
        "tags": [
          "community"
        ],
        "x-funpixel-scope": "community:read"
      }
    },
    "/v1/explore/activity": {
      "get": {
        "operationId": "exploreActivity",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "events": {
                      "items": {
                        "type": "object"
                      },
                      "type": "array"
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "events",
                    "has_more"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "What happened in Community lately (published, remixed), newest first."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "security": [
          {
            "bearer": []
          },
          {}
        ],
        "tags": [
          "community"
        ],
        "x-funpixel-scope": "community:read"
      }
    },
    "/v1/feed": {
      "get": {
        "description": "The feed, ranked for the account asking (at most 1,200 pages an hour per client IP).",
        "operationId": "feed",
        "parameters": [
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "cursor",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "items": {
                      "items": {
                        "properties": {
                          "kind": {
                            "enum": [
                              "game",
                              "creator",
                              "collection"
                            ],
                            "type": "string"
                          }
                        },
                        "required": [
                          "kind"
                        ],
                        "type": "object"
                      },
                      "type": "array"
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "items"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "One page of feed items (`kind` game, creator or collection)."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "security": [
          {
            "bearer": []
          },
          {}
        ],
        "tags": [
          "community"
        ],
        "x-funpixel-scope": "community:read"
      }
    },
    "/v1/feedback": {
      "post": {
        "operationId": "submitFeedback",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "agent": {
                    "maxLength": 64,
                    "type": "string"
                  },
                  "entries": {
                    "items": {
                      "type": "object"
                    },
                    "maxItems": 100,
                    "type": "array"
                  },
                  "game_id": {
                    "$ref": "#/components/schemas/GameId"
                  },
                  "game_metadata": {
                    "type": "object"
                  },
                  "items": {
                    "items": {
                      "type": "object"
                    },
                    "maxItems": 20,
                    "type": "array"
                  }
                },
                "type": "object"
              }
            }
          },
          "description": "The GDK's report, unchanged. The game is optional; a report with none, or with a game id this server has never seen, is stored without a game (`attached` false).",
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "attached": {
                      "description": "false: stored without a game",
                      "type": "boolean"
                    },
                    "batch_id": {
                      "type": "string"
                    },
                    "items": {
                      "type": "integer"
                    },
                    "note": {
                      "description": "Why a named game was not attached.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "batch_id",
                    "items",
                    "attached"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Filed."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "feedback"
        ],
        "x-funpixel-scope": "feedback:write"
      }
    },
    "/v1/games/drafts": {
      "post": {
        "operationId": "createDraft",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "name": {
                    "maxLength": 120,
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Draft"
                }
              }
            },
            "description": "An empty private draft the caller owns."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "games"
        ],
        "x-funpixel-scope": "games:publish"
      }
    },
    "/v1/games/uploads": {
      "post": {
        "operationId": "uploadGame",
        "parameters": [
          {
            "in": "query",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "game_id",
            "schema": {
              "$ref": "#/components/schemas/GameId"
            }
          },
          {
            "in": "query",
            "name": "prebuilt",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "in": "query",
            "name": "remixable",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "in": "query",
            "name": "mode",
            "schema": {
              "enum": [
                "replace"
              ],
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/gzip": {
              "schema": {
                "format": "binary",
                "type": "string"
              }
            },
            "application/zip": {
              "schema": {
                "format": "binary",
                "type": "string"
              }
            }
          },
          "description": "A .tar.gz or .zip of the staged game, `verify.json` at its root.",
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Upload"
                }
              }
            },
            "description": "Stored, built and probed as a draft."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "games"
        ],
        "x-funpixel-scope": "games:publish"
      }
    },
    "/v1/games/{game_id}/audit-screens": {
      "post": {
        "description": "Layout on every declared view (at most 16), each on its own load, entered and\nheld: text under 12 px, hit areas under 44 px, HUD pieces over each other, anything cut\nby the screen edge or inside a phone's safe area fail the view; HUD in the letterbox\nand the play area it covers are notes. Default the review phone, 390x844 with touch.\n",
        "operationId": "auditScreens",
        "parameters": [
          {
            "$ref": "#/components/parameters/GameId"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "properties": {
                  "click": {
                    "$ref": "#/components/schemas/Click"
                  },
                  "height": {
                    "default": 844,
                    "maximum": 2560,
                    "minimum": 200,
                    "type": "integer"
                  },
                  "touch": {
                    "default": true,
                    "type": "boolean"
                  },
                  "views": {
                    "items": {
                      "pattern": "^[A-Za-z0-9_.-]{1,64}$",
                      "type": "string"
                    },
                    "maxItems": 16,
                    "type": "array"
                  },
                  "width": {
                    "default": 390,
                    "maximum": 2560,
                    "minimum": 200,
                    "type": "integer"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScreenAudit"
                }
              }
            },
            "description": "A three-state verdict per view and overall."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "game tools"
        ],
        "x-funpixel-scope": "games:publish"
      }
    },
    "/v1/games/{game_id}/build": {
      "post": {
        "operationId": "buildDraft",
        "parameters": [
          {
            "$ref": "#/components/parameters/GameId"
          }
        ],
        "requestBody": {
          "content": {
            "application/gzip": {
              "schema": {
                "format": "binary",
                "type": "string"
              }
            },
            "application/zip": {
              "schema": {
                "format": "binary",
                "type": "string"
              }
            }
          },
          "description": "A .tar.gz or .zip of the project. Nothing is stored.",
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DraftBuild"
                }
              }
            },
            "description": "It built; the draft's preview host serves it."
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DraftBuild"
                }
              }
            },
            "description": "`build_failed` (with `log_tail`), `package_refused`, `source_layout` (no package.json or index.html at the root) or `source_secret`."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "game tools"
        ],
        "x-funpixel-scope": "games:publish"
      }
    },
    "/v1/games/{game_id}/capture-view": {
      "post": {
        "description": "One JPEG of the draft at a named state: the `__FPX_VIEWS__` entry entered,\nthe `__FPX_VERBS__` listed pressed in order, run `hold_ms`, then held still for the\nshot, in one browser call. A view that did not enter still answers its picture with\n`entered: false` and the reason; never read that picture as the view.\n",
        "operationId": "captureView",
        "parameters": [
          {
            "$ref": "#/components/parameters/GameId"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LookInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CapturedView"
                }
              }
            },
            "description": "What the drive did, and the picture."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "game tools"
        ],
        "x-funpixel-scope": "games:publish"
      }
    },
    "/v1/games/{game_id}/inspect-scene": {
      "post": {
        "description": "The draft's scene graph read in the page (Three through `__THREEJS_SCENE__` +\n`camera`, Pixi through `__PIXI_APP__`, Phaser through `__PHASER_GAME__`), at a named\nstate as `captureView` drives it. Read-only. `scene.engine: none` answers with a `hint`.\n",
        "operationId": "inspectScene",
        "parameters": [
          {
            "$ref": "#/components/parameters/GameId"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LookInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SceneRead"
                }
              }
            },
            "description": "The graph's counts, what is off or outside the view, textures, a draw-call estimate."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "game tools"
        ],
        "x-funpixel-scope": "games:publish"
      }
    },
    "/v1/games/{game_id}/mobile-check": {
      "post": {
        "operationId": "mobileCheck",
        "parameters": [
          {
            "$ref": "#/components/parameters/GameId"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "properties": {
                  "devices": {
                    "items": {
                      "enum": [
                        "narrow_android",
                        "small_iphone",
                        "review_frame",
                        "large_iphone"
                      ],
                      "type": "string"
                    },
                    "type": "array"
                  },
                  "orientation": {
                    "default": "auto",
                    "enum": [
                      "auto",
                      "portrait",
                      "landscape",
                      "both"
                    ],
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MobileCheck"
                }
              }
            },
            "description": "The phone matrix, three-state per check and frame."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "game tools"
        ],
        "x-funpixel-scope": "games:publish"
      }
    },
    "/v1/games/{game_id}/preview": {
      "get": {
        "operationId": "getPreview",
        "parameters": [
          {
            "$ref": "#/components/parameters/GameId"
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Preview"
                }
              }
            },
            "description": "The draft's preview host, null until something built."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "game tools"
        ],
        "x-funpixel-scope": "games:publish"
      }
    },
    "/v1/games/{game_id}/probe": {
      "post": {
        "operationId": "probeDraft",
        "parameters": [
          {
            "$ref": "#/components/parameters/GameId"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "properties": {
                  "click": {
                    "$ref": "#/components/schemas/Click"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ServerVerdict"
                    },
                    {
                      "properties": {
                        "game_id": {
                          "$ref": "#/components/schemas/GameId"
                        },
                        "preview_url": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "game_id",
                        "preview_url"
                      ],
                      "type": "object"
                    }
                  ]
                }
              }
            },
            "description": "The hosted probe's three-state verdict on the preview host."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "game tools"
        ],
        "x-funpixel-scope": "games:publish"
      }
    },
    "/v1/games/{game_id}/public": {
      "get": {
        "description": "One game's page. A Link-only game opened by its id answers a visitor the reduced\npayload (`community: \"off\"`, no counts, no viewer state); 404 when there is nothing\nthis caller may see.\n",
        "operationId": "publicGame",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommunityGame"
                }
              }
            },
            "description": "The game."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "security": [
          {
            "bearer": []
          },
          {}
        ],
        "tags": [
          "community"
        ],
        "x-funpixel-scope": "community:read"
      },
      "parameters": [
        {
          "$ref": "#/components/parameters/GameId"
        }
      ]
    },
    "/v1/games/{game_id}/remix": {
      "parameters": [
        {
          "$ref": "#/components/parameters/GameId"
        }
      ],
      "post": {
        "description": "Fork a game as the key's account: one in Community with remixing on (`viewer.can_remix`),\nor the account's own. The fork is born Link only and carries the source's poster. A\nsecond press on someone else's game answers the fork already made (200,\n`already_remixed`). 403 when remixing is off, 404 when the game is not one this\naccount may remix.\n",
        "operationId": "remixGame",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "name": {
                    "description": "The fork's name; screened. Default \"Remix of <title>\".",
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": false
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "already_remixed": {
                      "type": "boolean"
                    },
                    "file_count": {
                      "type": "integer"
                    },
                    "game_id": {
                      "$ref": "#/components/schemas/GameId"
                    },
                    "name": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "game_id",
                    "name",
                    "already_remixed"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "The fork this account already made of this game."
          },
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "file_count": {
                      "type": "integer"
                    },
                    "game_id": {
                      "$ref": "#/components/schemas/GameId"
                    },
                    "name": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "game_id",
                    "name"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "The fork."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "community"
        ],
        "x-funpixel-scope": "community:write"
      }
    },
    "/v1/games/{game_id}/rooms/ticket": {
      "post": {
        "description": "A single-use ticket to the multiplayer relay for a game you own. `?dev=true` mints one\nfor the game's dev room only (what `funtools dev` plays on localhost).\n",
        "operationId": "mintRoomTicket",
        "parameters": [
          {
            "$ref": "#/components/parameters/GameId"
          },
          {
            "in": "query",
            "name": "dev",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "in": "query",
            "name": "player",
            "schema": {
              "pattern": "^[A-Za-z0-9]{1,16}$",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RoomTicket"
                }
              }
            },
            "description": "A single-use relay ticket for the caller's game."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "games"
        ],
        "x-funpixel-scope": "rooms:join"
      }
    },
    "/v1/games/{game_id}/screenshot": {
      "post": {
        "operationId": "screenshotDraft",
        "parameters": [
          {
            "$ref": "#/components/parameters/GameId"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "properties": {
                  "click": {
                    "$ref": "#/components/schemas/Click"
                  },
                  "height": {
                    "default": 720,
                    "maximum": 2560,
                    "minimum": 200,
                    "type": "integer"
                  },
                  "touch": {
                    "default": false,
                    "type": "boolean"
                  },
                  "width": {
                    "default": 1280,
                    "maximum": 2560,
                    "minimum": 200,
                    "type": "integer"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "image/jpeg": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              }
            },
            "description": "The page as a JPEG.",
            "headers": {
              "X-Funpixel-Front-Door": {
                "description": "With `click`, what the press did (a FrontDoor, as ASCII JSON).",
                "schema": {
                  "type": "string"
                }
              },
              "X-Funpixel-Preview-Url": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "game tools"
        ],
        "x-funpixel-scope": "games:publish"
      }
    },
    "/v1/games/{game_id}/star": {
      "delete": {
        "operationId": "unstarGame",
        "responses": {
          "200": {
            "description": "Not starred."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "community"
        ],
        "x-funpixel-scope": "community:write"
      },
      "parameters": [
        {
          "$ref": "#/components/parameters/GameId"
        }
      ],
      "post": {
        "description": "Star a game in Community (or your own) as the key's account. Idempotent.",
        "operationId": "starGame",
        "responses": {
          "200": {
            "description": "Starred."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "community"
        ],
        "x-funpixel-scope": "community:write"
      }
    },
    "/v1/games/{game_id}/store-shots": {
      "post": {
        "operationId": "storeShots",
        "parameters": [
          {
            "$ref": "#/components/parameters/GameId"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "properties": {
                  "banners": {
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 6,
                    "type": "array"
                  },
                  "run_id": {
                    "type": "string"
                  },
                  "sizes": {
                    "items": {
                      "enum": [
                        "iphone_6_9",
                        "iphone_6_5",
                        "ipad_13"
                      ],
                      "type": "string"
                    },
                    "type": "array"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoreShots"
                }
              }
            },
            "description": "Store screenshots from the newest capture run; 409 `no_captures` when there is none."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "game tools"
        ],
        "x-funpixel-scope": "games:publish"
      }
    },
    "/v1/games/{game_id}/verification": {
      "get": {
        "operationId": "getVerification",
        "parameters": [
          {
            "$ref": "#/components/parameters/GameId"
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Verification"
                    },
                    {
                      "properties": {
                        "game_id": {
                          "$ref": "#/components/schemas/GameId"
                        }
                      },
                      "required": [
                        "game_id"
                      ],
                      "type": "object"
                    }
                  ]
                }
              }
            },
            "description": "The client's verify claim and the server's own verdict."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "games"
        ],
        "x-funpixel-scope": "games:publish"
      }
    },
    "/v1/gdk/skills/index.json": {
      "get": {
        "description": "The GDK skills, in the shape opencode's remote skill discovery\nreads: point `skills.urls` at `https://api.funpixel.ai/v1/gdk/skills/`.\nAnonymous and read-only; the content is compiled into the server, so it\nchanges only with a deploy. `Cache-Control: public, max-age=3600` and an\n`ETag` (`If-None-Match` answers 304). `version` is a hash of the skill's\nfiles: a client re-downloads a skill when it changes.\n",
        "operationId": "gdkSkillsIndex",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "skills": {
                      "items": {
                        "properties": {
                          "description": {
                            "description": "When to load it (the frontmatter description).",
                            "type": "string"
                          },
                          "files": {
                            "description": "Paths relative to the skill, SKILL.md first.",
                            "items": {
                              "type": "string"
                            },
                            "type": "array"
                          },
                          "name": {
                            "description": "The skill's directory name.",
                            "type": "string"
                          },
                          "version": {
                            "description": "16 hex characters of a hash of its files.",
                            "type": "string"
                          }
                        },
                        "required": [
                          "name",
                          "description",
                          "version",
                          "files"
                        ],
                        "type": "object"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "skills"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Every skill with its files."
          },
          "304": {
            "description": "The ETag matched."
          }
        },
        "security": [],
        "tags": [
          "skills"
        ]
      }
    },
    "/v1/gdk/skills/{name}/{file}": {
      "get": {
        "description": "One file of one skill, as listed by the index (`file` may contain `/`, e.g.\n`references/rubric.md`). Only the listed files exist; anything else is 404.\n",
        "operationId": "gdkSkillFile",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "file",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "The file."
          },
          "304": {
            "description": "The ETag matched."
          },
          "404": {
            "description": "No such skill file."
          }
        },
        "security": [],
        "tags": [
          "skills"
        ]
      }
    },
    "/v1/jobs": {
      "get": {
        "description": "The account's jobs, newest first: every key's and the session's, each one\nreadable with `GET /v1/jobs/{job_id}`. Keyset-paginated: pass `next_cursor` back\nas `cursor` until it is null.\n",
        "operationId": "listJobs",
        "parameters": [
          {
            "description": "Only this tool's jobs (a name from the `Tool` parameter).",
            "in": "query",
            "name": "tool",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "status",
            "schema": {
              "$ref": "#/components/schemas/JobStatus"
            }
          },
          {
            "description": "The `next_cursor` of the page before; opaque.",
            "in": "query",
            "name": "cursor",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "default": 20,
              "maximum": 100,
              "minimum": 1,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobPage"
                }
              }
            },
            "description": "One page of jobs, each with fresh file URLs."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "jobs"
        ],
        "x-funpixel-scope": "jobs:read"
      }
    },
    "/v1/jobs/{job_id}": {
      "delete": {
        "operationId": "cancelJob",
        "parameters": [
          {
            "$ref": "#/components/parameters/JobId"
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "Cancelled (idempotent)."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "jobs"
        ],
        "x-funpixel-scope": "tools:run"
      },
      "get": {
        "operationId": "getJob",
        "parameters": [
          {
            "$ref": "#/components/parameters/JobId"
          },
          {
            "description": "Hold up to this many seconds (≤ 60) until the job ends.",
            "in": "query",
            "name": "wait",
            "schema": {
              "maximum": 60,
              "minimum": 0,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job, with fresh file URLs."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "jobs"
        ],
        "x-funpixel-scope": "jobs:read"
      }
    },
    "/v1/jobs/{job_id}/assets/{asset_id}": {
      "get": {
        "description": "One file of a succeeded job, its bytes (the job's own reader only).\n",
        "operationId": "getJobFile",
        "parameters": [
          {
            "$ref": "#/components/parameters/JobId"
          },
          {
            "in": "path",
            "name": "asset_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/octet-stream": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              }
            },
            "description": "The file, as its `content_type`."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "jobs"
        ],
        "x-funpixel-scope": "jobs:read"
      }
    },
    "/v1/jobs/{job_id}/deliveries": {
      "get": {
        "description": "The job's webhook delivery log: delivery 1 is the automatic one, each\nmanual retry the next. Every attempt with when it went, what answered and\nwhy it was not delivered. Never a body, a signature or the secret.\n",
        "operationId": "listDeliveries",
        "parameters": [
          {
            "$ref": "#/components/parameters/JobId"
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Deliveries"
                }
              }
            },
            "description": "The log, oldest first."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "jobs"
        ],
        "x-funpixel-scope": "jobs:read"
      }
    },
    "/v1/jobs/{job_id}/deliveries/retry": {
      "post": {
        "description": "Deliver a finished job's webhook again, as a new delivery with its own\nattempts and backoff, rendered and signed afresh. 409 `no_webhook`,\n`job_not_finished`, `delivery_in_flight` (one is waiting or being sent),\n`too_many_deliveries` (10 per job) or `webhook_refused`; 429 past 30 an\nhour per account.\n",
        "operationId": "retryDelivery",
        "parameters": [
          {
            "$ref": "#/components/parameters/JobId"
          }
        ],
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Deliveries"
                }
              }
            },
            "description": "Queued; the log with the new delivery `pending`."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "jobs"
        ],
        "x-funpixel-scope": "tools:run"
      }
    },
    "/v1/jobs/{job_id}/events": {
      "get": {
        "operationId": "jobEvents",
        "parameters": [
          {
            "$ref": "#/components/parameters/JobId"
          },
          {
            "in": "query",
            "name": "after",
            "schema": {
              "minimum": 0,
              "type": "integer"
            }
          },
          {
            "in": "header",
            "name": "Last-Event-ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Server-Sent Events: `queued`, `started`, `asset`, then `succeeded` |\n`failed` | `cancelled`; `id` is the per-job seq, data `{seq, at, data}`;\nthe terminal event's data carries `job`.\n"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "jobs"
        ],
        "x-funpixel-scope": "jobs:read"
      }
    },
    "/v1/me/api-keys": {
      "get": {
        "operationId": "listKeys",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "keys": {
                      "items": {
                        "$ref": "#/components/schemas/ApiKey"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "keys"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "The account's keys (prefix only, never the secret)."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "keys"
        ],
        "x-funpixel-scope": "session"
      },
      "post": {
        "operationId": "createKey",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "expires_at": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "monthly_credit_cap": {
                    "minimum": 1,
                    "type": "integer"
                  },
                  "name": {
                    "type": "string"
                  },
                  "scopes": {
                    "items": {
                      "$ref": "#/components/schemas/Scope"
                    },
                    "type": "array"
                  }
                },
                "required": [
                  "name"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "key": {
                      "$ref": "#/components/schemas/ApiKey"
                    },
                    "secret": {
                      "pattern": "^fp_live_",
                      "type": "string"
                    }
                  },
                  "required": [
                    "key",
                    "secret"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "The key and its secret, shown once."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "keys"
        ],
        "x-funpixel-scope": "session"
      }
    },
    "/v1/me/api-keys/{key_id}": {
      "delete": {
        "operationId": "revokeKey",
        "responses": {
          "204": {
            "description": "Revoked."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "keys"
        ],
        "x-funpixel-scope": "session"
      },
      "parameters": [
        {
          "in": "path",
          "name": "key_id",
          "required": true,
          "schema": {
            "format": "uuid",
            "type": "string"
          }
        }
      ],
      "patch": {
        "operationId": "updateKey",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "monthly_credit_cap": {
                    "minimum": 1,
                    "type": [
                      "integer",
                      "null"
                    ]
                  }
                },
                "required": [
                  "monthly_credit_cap"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "monthly_credit_cap": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "The cap as stored."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "keys"
        ],
        "x-funpixel-scope": "session"
      }
    },
    "/v1/me/credits": {
      "get": {
        "operationId": "getCredits",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Credits"
                }
              }
            },
            "description": "The account's balance and plan."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "usage"
        ],
        "x-funpixel-scope": "usage:read"
      }
    },
    "/v1/me/key": {
      "get": {
        "operationId": "whoami",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "key": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ApiKey"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "plan": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "username": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "username",
                    "key"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "`funtools whoami`: the account behind this request and, for a key, the key\n(never its secret; `null` for a session).\n"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "keys"
        ],
        "x-funpixel-scope": "usage:read"
      }
    },
    "/v1/me/recent-looks": {
      "get": {
        "description": "Your last 8 games' looks, newest first, read from each game's plan (its design document) and its\nstyle lock: the identity line, the look's first line, the palette, the display font, the\nHUD line and each screen's entrance and intent. A new game's plan is held to differ from\nthem. Your own games only. Never a price.\n",
        "operationId": "getRecentLooks",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "games": {
                      "items": {
                        "properties": {
                          "at": {
                            "format": "date-time",
                            "type": "string"
                          },
                          "font": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "game_id": {
                            "type": "string"
                          },
                          "hud": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "identity": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "name": {
                            "type": "string"
                          },
                          "palette": {
                            "items": {
                              "type": "string"
                            },
                            "type": "array"
                          },
                          "screens": {
                            "items": {
                              "properties": {
                                "entrance": {
                                  "type": [
                                    "string",
                                    "null"
                                  ]
                                },
                                "intent": {
                                  "type": [
                                    "string",
                                    "null"
                                  ]
                                },
                                "name": {
                                  "type": "string"
                                }
                              },
                              "type": "object"
                            },
                            "type": "array"
                          },
                          "style": {
                            "type": [
                              "string",
                              "null"
                            ]
                          }
                        },
                        "required": [
                          "game_id",
                          "name",
                          "at",
                          "palette",
                          "screens"
                        ],
                        "type": "object"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "games"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "The recent games' looks (an empty list for none)."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "usage"
        ],
        "x-funpixel-scope": "games:publish"
      }
    },
    "/v1/me/usage": {
      "get": {
        "operationId": "getUsage",
        "parameters": [
          {
            "in": "query",
            "name": "from",
            "schema": {
              "format": "date",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "to",
            "schema": {
              "format": "date",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "key_id",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Usage"
                }
              }
            },
            "description": "Tools API spend by day and tool (default the current UTC month, ≤ 92 days)."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "usage"
        ],
        "x-funpixel-scope": "usage:read"
      }
    },
    "/v1/motions": {
      "get": {
        "description": "The motion library: every motion `rig_model`'s `motions` and `generate_3d_model`'s\n`animations` take, by name, with its category, whether a game loops it, whether it plays\non the spot, its on-the-spot twin, whether it comes free with a rig, and its mannequin\npreview (`preview_url`, `poster_url`; null until the preview set is published; an\n`_in_place` twin shows its moving twin's). `max_per_job` is the most motions one job\nadds; `rigged_motions` what a model that already has a rig can be given. Any plan with\na session; a key needs `jobs:read`. Never a price: quotes come from `/estimate`.\n",
        "operationId": "getMotions",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "categories": {
                      "items": {
                        "type": "string"
                      },
                      "type": "array"
                    },
                    "max_per_job": {
                      "type": "integer"
                    },
                    "motions": {
                      "items": {
                        "properties": {
                          "category": {
                            "type": "string"
                          },
                          "free_with_rig": {
                            "type": "boolean"
                          },
                          "in_place": {
                            "type": "boolean"
                          },
                          "in_place_twin": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "loops": {
                            "type": "boolean"
                          },
                          "name": {
                            "type": "string"
                          },
                          "poster_url": {
                            "format": "uri",
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "preview_url": {
                            "format": "uri",
                            "type": [
                              "string",
                              "null"
                            ]
                          }
                        },
                        "required": [
                          "name",
                          "category",
                          "loops",
                          "in_place",
                          "in_place_twin",
                          "free_with_rig",
                          "preview_url",
                          "poster_url"
                        ],
                        "type": "object"
                      },
                      "type": "array"
                    },
                    "rigged_motions": {
                      "items": {
                        "type": "string"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "motions",
                    "categories",
                    "max_per_job",
                    "rigged_motions"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "The library, in the library's order."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "jobs:read"
      }
    },
    "/v1/tools/accept_asset": {
      "post": {
        "description": "Accept or reject an image for a role (character, background, …) by\nmeasurement, keying a cut-out role first. Free and synchronous. A reject is a 200\nwith `verdict: reject`.\n",
        "operationId": "acceptAsset",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JudgeInput"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Judged"
                }
              }
            },
            "description": "The verdict, the measurements and, when accepted, the PNG."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "asset tools"
        ],
        "x-funpixel-scope": "tools:run"
      }
    },
    "/v1/tools/audit_clips": {
      "post": {
        "description": "Play every animation clip of a model on our model bench and answer what\neach does: length, root motion, a planted foot that slides, a clip that holds one\npose, clips that animate no bone. With `expected`, the clip names a game's code\nplays are matched against the file's. Free and synchronous; nothing is stored. A\nfile the bench cannot read, or one with no clips, is a 200 with `measured: false`.\n429 past 60 an hour per account.\n",
        "operationId": "auditClips",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClipAuditInput"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClipAudit"
                }
              }
            },
            "description": "Every clip, measured, and the findings in words."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "asset tools"
        ],
        "x-funpixel-scope": "tools:run"
      }
    },
    "/v1/tools/generate_batch": {
      "post": {
        "description": "One job per item by `kind` (image, sprite, texture, strip, sound, music,\nsheet, model3d), pictures styled by the game's style lock. Each item counts as one job\nagainst the job limits. The quote is the sum; over the confirm threshold it needs\n`confirm_cost` (402 `confirmation_required`). Each item's\njob is keyed by the batch, its name and its content, so a resent manifest answers\nunchanged items with their jobs and starts only new or edited ones; a failed item\nruns again (at most 3 times per content).\n",
        "operationId": "generateBatch",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "properties": {
                  "batch_key": {
                    "pattern": "^[A-Za-z0-9_.:-]{1,128}$",
                    "type": "string"
                  },
                  "confirm_cost": {
                    "type": "boolean"
                  },
                  "game_id": {
                    "$ref": "#/components/schemas/GameId"
                  },
                  "items": {
                    "items": {
                      "additionalProperties": false,
                      "properties": {
                        "kind": {
                          "default": "image",
                          "enum": [
                            "image",
                            "sprite",
                            "texture",
                            "strip",
                            "sound",
                            "music",
                            "sheet",
                            "model3d"
                          ],
                          "type": "string"
                        },
                        "name": {
                          "pattern": "^[A-Za-z0-9_.-]{1,64}$",
                          "type": "string"
                        },
                        "params": {
                          "additionalProperties": true,
                          "description": "sound, music, sheet and model3d — that tool's own input fields (never prompt or game_id).",
                          "type": "object"
                        },
                        "prompt": {
                          "description": "Required except for sheet and model3d, which may start from an asset in params.",
                          "maxLength": 4000,
                          "minLength": 1,
                          "type": "string"
                        },
                        "quality": {
                          "enum": [
                            "low",
                            "medium",
                            "high"
                          ],
                          "type": "string"
                        },
                        "references": {
                          "description": "Pictures only. Asset ids of your own pictures (a job's output, or import_asset) sent as the image model's input references, e.g. a character sheet to draw on-model. At most the model's limit (16).",
                          "items": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "maxItems": 16,
                          "type": "array"
                        },
                        "size": {
                          "description": "WxH. The aspect ratio is kept (both sides scale together to 256-1024, then the nearest ratio the model draws), so 1536x1024 is 3:2.",
                          "pattern": "^[0-9]+x[0-9]+$",
                          "type": "string"
                        },
                        "transparent": {
                          "default": false,
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "name"
                      ],
                      "type": "object"
                    },
                    "maxItems": 32,
                    "minItems": 1,
                    "type": "array"
                  },
                  "lock": {
                    "additionalProperties": false,
                    "description": "Pin the game's locked art before this batch (needs game_id): its reference sheets as asset ids of your own pictures. Every picture item without references is then drawn to the sheets its name picks.",
                    "properties": {
                      "sheets": {
                        "items": {
                          "additionalProperties": false,
                          "properties": {
                            "asset_id": {
                              "format": "uuid",
                              "type": "string"
                            },
                            "name": {
                              "pattern": "^[Rr][Ee][Ff]-[A-Za-z0-9_.-]{1,60}$",
                              "type": "string"
                            }
                          },
                          "required": [
                            "name",
                            "asset_id"
                          ],
                          "type": "object"
                        },
                        "maxItems": 24,
                        "type": "array"
                      },
                      "style": {
                        "description": "The style sentence for a game with none.",
                        "maxLength": 1000,
                        "type": "string"
                      }
                    },
                    "type": "object"
                  },
                  "style": {
                    "maxLength": 1000,
                    "type": "string"
                  },
                  "webhook_url": {
                    "description": "Each item's job POSTs itself here when it ends, as a submit's does.",
                    "maxLength": 2048,
                    "pattern": "^https://",
                    "type": "string"
                  }
                },
                "required": [
                  "items"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Batch"
                }
              }
            },
            "description": "Every item's job already existed (a resend)."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Batch"
                }
              }
            },
            "description": "At least one job started."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "asset tools"
        ],
        "x-funpixel-scope": "tools:run"
      }
    },
    "/v1/tools/import_asset": {
      "post": {
        "description": "One of the caller's own files becomes an asset. A picture (an approved sprite made\nelsewhere), so `edit_image` and `generate_spritesheet` can take its `asset_id` and draw\nnew states of the same character. Or a 3D model (`media_base64`: a GLB, or a binary FBX),\nso `rig_model` (with `motions`, on a GLB), `inspect_model`, `retarget_clips` and the other\nmodel tools can. A model is read by its bytes: a .blend, an OBJ, an ASCII FBX, a .gltf\nJSON, a GLB naming a file outside itself, or one over 64 MB is a 400 `invalid_input`,\nnothing stored. Or the caller's own audio or video (`media_base64`), or a file put by a\npresigned upload (`upload_id`, from `upload_asset`). Stored like a job's file, under a\nfinished record of tool `import_asset`; the same model bytes answer the same asset. Free\nand synchronous; nothing is generated. Exactly one of `image_base64`, `media_base64`,\n`upload_id`.\n",
        "operationId": "importAsset",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "properties": {
                  "image_base64": {
                    "description": "A picture (PNG, JPEG or WebP, at most 12 MB, 4096 px a side). Or give media_base64.",
                    "type": "string"
                  },
                  "media_base64": {
                    "description": "A picture; a 3D model: a .glb (textures embedded) or a binary .fbx (7.1 to 7.7), at most 64 MB; or audio or video (MP3, WAV, M4A, OGG, FLAC, MP4, MOV, WebM), at most 12 MB. Told apart by its bytes. Instead of image_base64.",
                    "type": "string"
                  },
                  "name": {
                    "description": "Its file name, e.g. bee.png or knight.glb; stored sanitised, with the file's real extension.",
                    "maxLength": 128,
                    "type": "string"
                  },
                  "upload_id": {
                    "description": "Finish a presigned upload: the file already PUT to `upload_asset`'s URL, checked (size, kind by its bytes) and recorded. Nothing else with it; finishing twice answers the same asset.",
                    "format": "uuid",
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "asset_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "content_type": {
                      "type": "string"
                    },
                    "job_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "size_bytes": {
                      "type": "integer"
                    }
                  },
                  "required": [
                    "asset_id",
                    "job_id",
                    "name",
                    "content_type",
                    "size_bytes"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "The new asset."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "asset tools"
        ],
        "x-funpixel-scope": "tools:run"
      }
    },
    "/v1/tools/key_sprite": {
      "post": {
        "description": "Cut a sprite out of its backdrop (green/magenta key with despill, or a\nflood fill from a flat border) and trim it, then the acceptance check every\ngenerated sprite passes. Free and synchronous; nothing is stored. A reject is a\n200 with `verdict: reject`.\n",
        "operationId": "keySprite",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JudgeInput"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Judged"
                }
              }
            },
            "description": "The verdict, the measurements and, when accepted, the PNG."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "asset tools"
        ],
        "x-funpixel-scope": "tools:run"
      }
    },
    "/v1/tools/models": {
      "get": {
        "description": "Every generation model a caller may name as `model` on a generate tool, our\npick first per kind and marked `recommended`, with whether this server runs it and the\nprice rows it is quoted and charged on, in credits. Omitting `model` runs the pick;\na named model runs alone. An unknown name is 400 `unknown_model` with `models`; a\npaid-only model on a free plan is 403 `model_needs_plan` with `reason`; a local model is\n400 `model_runs_locally` with `run`; one switched off here is 503 `model_unavailable`.\n",
        "operationId": "getModels",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Models"
                }
              }
            },
            "description": "The models, in credits only."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "jobs:read"
      }
    },
    "/v1/tools/pricing": {
      "get": {
        "operationId": "getPricing",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Pricing"
                }
              }
            },
            "description": "Per-tool prices in credits."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "jobs:read"
      }
    },
    "/v1/tools/review": {
      "post": {
        "description": "`submitJob` for `review`, the one tool whose body may carry pictures: up to 12 captures\nof 700 KB each (a 12 MB body; every other tool keeps the default limit). The captures\nare stored under the account by content and the job keeps only their names and\nhashes. Without `images` the server shoots the draft itself (build it first). Quote it\nat `/v1/tools/review/estimate` without the pictures: the price is by seats.\n",
        "operationId": "submitReview",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReviewInput"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job; its `result` is a `ReviewResult` when it succeeds.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run"
      }
    },
    "/v1/tools/slice_sheet": {
      "post": {
        "description": "Cut a sheet by its grid: `columns` + `rows`, or `cell_width` +\n`cell_height`. A grid that does not divide the sheet is a 400 naming the\nremainder. Free and synchronous.\n",
        "operationId": "sliceSheet",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "properties": {
                  "asset_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "cell_height": {
                    "minimum": 1,
                    "type": "integer"
                  },
                  "cell_width": {
                    "minimum": 1,
                    "type": "integer"
                  },
                  "columns": {
                    "minimum": 1,
                    "type": "integer"
                  },
                  "image_base64": {
                    "contentEncoding": "base64",
                    "type": "string"
                  },
                  "image_name": {
                    "default": "sheet.png",
                    "type": "string"
                  },
                  "margin": {
                    "default": 0,
                    "minimum": 0,
                    "type": "integer"
                  },
                  "prefix": {
                    "default": "frame",
                    "type": "string"
                  },
                  "rows": {
                    "minimum": 1,
                    "type": "integer"
                  },
                  "skip_empty": {
                    "default": true,
                    "type": "boolean"
                  },
                  "spacing": {
                    "default": 0,
                    "minimum": 0,
                    "type": "integer"
                  },
                  "trim": {
                    "default": false,
                    "type": "boolean"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Sliced"
                }
              }
            },
            "description": "Each cell as a PNG, and a TexturePacker JSON-hash manifest over the sheet."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "asset tools"
        ],
        "x-funpixel-scope": "tools:run"
      }
    },
    "/v1/tools/texture_stats": {
      "post": {
        "description": "What a GLB's textures cost a device, read from the image headers (PNG, JPEG,\nWebP, KTX2) without decoding: format, file bytes, pixel size, a GPU-memory estimate,\nnot a power of two, over the device's side (phone 2048 px, desktop 4096) and the\nmaterial slots that use each. Free and synchronous; nothing is stored.\n",
        "operationId": "textureStats",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "properties": {
                  "asset_id": {
                    "description": "A model a job of yours made.",
                    "format": "uuid",
                    "type": "string"
                  },
                  "device": {
                    "default": "phone",
                    "enum": [
                      "phone",
                      "desktop"
                    ],
                    "type": "string"
                  },
                  "model_base64": {
                    "description": "The model (.glb, at most 12 MB). Or `asset_id`.",
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TextureStats"
                }
              }
            },
            "description": "Every image, the totals and the findings in words."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "asset tools"
        ],
        "x-funpixel-scope": "tools:run"
      }
    },
    "/v1/tools/upload_asset": {
      "post": {
        "description": "Start a presigned upload of the caller's own audio or video too big for one call (up\nto 200 MB): a PUT URL to Funpixel's storage, good for an hour, with the content type and\nlength signed into it. PUT the bytes there with exactly the `headers` answered, then\n`POST /v1/tools/import_asset` with `upload_id` for the asset. Free; counted in the asset\nhelpers' hourly allowance.\n",
        "operationId": "uploadAsset",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "properties": {
                  "content_type": {
                    "enum": [
                      "audio/mpeg",
                      "audio/wav",
                      "audio/mp4",
                      "audio/ogg",
                      "audio/flac",
                      "video/mp4",
                      "video/quicktime",
                      "video/webm"
                    ],
                    "type": "string"
                  },
                  "name": {
                    "description": "Its file name; stored sanitised, with the declared kind's extension.",
                    "maxLength": 128,
                    "type": "string"
                  },
                  "size_bytes": {
                    "description": "The file's exact size: the URL is signed for it.",
                    "maximum": 209715200,
                    "minimum": 1,
                    "type": "integer"
                  }
                },
                "required": [
                  "content_type",
                  "size_bytes"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "expires_at": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "headers": {
                      "additionalProperties": {
                        "type": "string"
                      },
                      "type": "object"
                    },
                    "max_bytes": {
                      "type": "integer"
                    },
                    "method": {
                      "enum": [
                        "PUT"
                      ],
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "upload_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "url": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "upload_id",
                    "name",
                    "method",
                    "url",
                    "headers",
                    "expires_at",
                    "max_bytes"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Where to put the file."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "asset tools"
        ],
        "x-funpixel-scope": "tools:run"
      }
    },
    "/v1/tools/{tool}": {
      "post": {
        "operationId": "submitJob",
        "parameters": [
          {
            "$ref": "#/components/parameters/Tool"
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ToolInput"
              }
            }
          },
          "description": "The tool's input; `confirm_cost` and `webhook_url` ride in it and are taken\nout. A `webhook_url` gets the finished job POSTed to it once (see\n`webhooks.jobFinished`), signed with `webhook_secret`, which only this\nresponse carries. `find_material` and `get_material` (a free CC0 library) are\nfree and answer 429 `rate_limited` past the account's hourly allowance.\n",
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run"
      }
    },
    "/v1/tools/{tool}/estimate": {
      "post": {
        "operationId": "estimateJob",
        "parameters": [
          {
            "$ref": "#/components/parameters/Tool"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ToolInput"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Estimate"
                }
              }
            },
            "description": "The quote."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run"
      }
    },
    "/v1/users/{username}": {
      "get": {
        "operationId": "profile",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "description": "A creator's public profile, with whether the caller follows them."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "security": [
          {
            "bearer": []
          },
          {}
        ],
        "tags": [
          "community"
        ],
        "x-funpixel-scope": "community:read"
      },
      "parameters": [
        {
          "in": "path",
          "name": "username",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ]
    },
    "/v1/users/{username}/follow": {
      "delete": {
        "operationId": "unfollowUser",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FollowAnswer"
                }
              }
            },
            "description": "Not following."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "community"
        ],
        "x-funpixel-scope": "community:write"
      },
      "parameters": [
        {
          "in": "path",
          "name": "username",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "description": "Follow a creator as the key's account. Idempotent; 400 for yourself, 403 across a block.",
        "operationId": "followUser",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FollowAnswer"
                }
              }
            },
            "description": "Following."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "tags": [
          "community"
        ],
        "x-funpixel-scope": "community:write"
      }
    },
    "/v1/users/{username}/projects": {
      "get": {
        "description": "A creator's games in Community (all of them, to the creator).",
        "operationId": "profileGames",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "projects": {
                      "items": {
                        "$ref": "#/components/schemas/CommunityGame"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "projects"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "One page of games."
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        },
        "security": [
          {
            "bearer": []
          },
          {}
        ],
        "tags": [
          "community"
        ],
        "x-funpixel-scope": "community:read"
      },
      "parameters": [
        {
          "in": "path",
          "name": "username",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ]
    },
    "/v1/tools/generate_image": {
      "post": {
        "operationId": "submit_generate_image",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Generate one image (backgrounds, key art, UI art), or with kind texture / strip a seamless tile or scrolling strip, checked for a seam.",
        "description": "Generate one image (backgrounds, key art, UI art), or with kind texture / strip a seamless tile or scrolling strip, checked for a seam.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/generate_image/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/generate_image_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/generate_sprite": {
      "post": {
        "operationId": "submit_generate_sprite",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Generate one subject on a transparent background (a character, a pickup, an icon).",
        "description": "Generate one subject on a transparent background (a character, a pickup, an icon). Refused, and not charged, if it comes back opaque.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/generate_sprite/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/generate_sprite_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/edit_image": {
      "post": {
        "operationId": "submit_edit_image",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Edit a picture you made, keeping everything the prompt does not change: a cut-out stays a cut-out.",
        "description": "Edit a picture you made, keeping everything the prompt does not change: a cut-out stays a cut-out. mode pose redraws the same character in a new pose: a blink, a hurt face, a happy pose, a second step. Refused, uncharged, if the result fails the asset check. With mask_asset_id (a brush's mask, white where painted): mode erase removes what is painted, mode edit redraws it as the prompt says, and nothing outside the mask changes; a mask that is not a PNG of the picture's size is refused, uncharged. A masked edit is included in your plan's credits, or on your own key for a small platform fee.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/edit_image/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/edit_image_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/generate_spritesheet": {
      "post": {
        "operationId": "submit_generate_spritesheet",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Animate a character: its idle, walk, run, jump, attack, act, hit, death and blink cycles as one packed sheet (sheet.png) and a Pixi AnimatedSprite-ready sheet.json (frames, animations, fps, loop, the feet as anchor).",
        "description": "Animate a character: its idle, walk, run, jump, attack, act, hit, death and blink cycles as one packed sheet (sheet.png) and a Pixi AnimatedSprite-ready sheet.json (frames, animations, fps, loop, the feet as anchor). Every frame is an edit of one base sprite (yours or drawn from the prompt), so it stays the same character; a frame that drifts is redrawn once, then refused uncharged. Priced per frame. Takes minutes.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/generate_spritesheet/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/generate_spritesheet_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/generate_sound": {
      "post": {
        "operationId": "submit_generate_sound",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Generate one sound effect as an mp3 (0.5 to 30 seconds; a length outside is clamped).",
        "description": "Generate one sound effect as an mp3 (0.5 to 30 seconds; a length outside is clamped). Quoted at a flat rate and charged by its length, so a long effect can cost more than its quote.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/generate_sound/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/generate_sound_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/generate_music": {
      "post": {
        "operationId": "submit_generate_music",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Generate background music as an mp3: a ~30 s clip or a full track.",
        "description": "Generate background music as an mp3: a ~30 s clip or a full track. `instrumental` asks the prompt for no vocals.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/generate_music/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/generate_music_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/cast_voice": {
      "post": {
        "operationId": "submit_cast_voice",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Give a character a voice: one of 30 preset voices plus delivery words (gruff, weary, whispering), saved as voice.json with a spoken sample.mp3.",
        "description": "Give a character a voice: one of 30 preset voices plus delivery words (gruff, weary, whispering), saved as voice.json with a spoken sample.mp3. Pass voice.json's asset_id to voice_line so every line is the same voice. No cloning.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/cast_voice/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/cast_voice_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/voice_line": {
      "post": {
        "operationId": "submit_voice_line",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Speak one line of dialogue in a character's voice (voice_asset_id from cast_voice, or a preset): line.mp3, trimmed and mastered for speech.",
        "description": "Speak one line of dialogue in a character's voice (voice_asset_id from cast_voice, or a preset): line.mp3, trimmed and mastered for speech. Priced by its length.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/voice_line/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/voice_line_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/dialogue": {
      "post": {
        "operationId": "submit_dialogue",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Speak a whole scene: a script of lines, each a speaker in a voice (cast_voice's voice.json asset id, or a preset), every line voice_line's call, laid on a timeline (a track per speaker) and mixed into one dialogue.mp3, with dialogue.json (the timeline: tracks, clips, starts, durations) and each line-NN.mp3.",
        "description": "Speak a whole scene: a script of lines, each a speaker in a voice (cast_voice's voice.json asset id, or a preset), every line voice_line's call, laid on a timeline (a track per speaker) and mixed into one dialogue.mp3, with dialogue.json (the timeline: tracks, clips, starts, durations) and each line-NN.mp3. Priced by the script's length and charged once for the scene; its time limit grows with the lines. A line the voice service fails stops the scene: the lines before it are kept and charged, the rest not.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/dialogue/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/dialogue_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/generate_3d_model": {
      "post": {
        "operationId": "submit_generate_3d_model",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Generate a 3D model (.glb) from a prompt or a reference image.",
        "description": "Generate a 3D model (.glb) from a prompt or a reference image. Asking for animations rigs it and adds one .glb per clip. Takes minutes.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/generate_3d_model/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/generate_3d_model_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/generate_skybox": {
      "post": {
        "operationId": "submit_generate_skybox",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Generate a 360° sky as one equirectangular image (2:1) from a prompt: a 3D scene's background and its lighting (scene.environment).",
        "description": "Generate a 360° sky as one equirectangular image (2:1) from a prompt: a 3D scene's background and its lighting (scene.environment).\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/generate_skybox/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/generate_skybox_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/find_material": {
      "post": {
        "operationId": "submit_find_material",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Search a free CC0 library: HDRI skies, PBR texture sets and models.",
        "description": "Search a free CC0 library: HDRI skies, PBR texture sets and models. Returns ids to fetch with get_material.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/find_material/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/find_material_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/get_material": {
      "post": {
        "operationId": "submit_get_material",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Copy one free CC0 asset into your files: an HDRI (.hdr), a PBR texture set (colour, normal, roughness, AO) or a model (.gltf with its .bin and textures).",
        "description": "Copy one free CC0 asset into your files: an HDRI (.hdr), a PBR texture set (colour, normal, roughness, AO) or a model (.gltf with its .bin and textures). Source, authors and licence ride on every file.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/get_material/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/get_material_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/inspect_model": {
      "post": {
        "operationId": "submit_inspect_model",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Measure a 3D model you made on our model bench: materials, rig, clips, weights, with a findings-first summary.",
        "description": "Measure a 3D model you made on our model bench: materials, rig, clips, weights, with a findings-first summary.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/inspect_model/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inspect_model_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/optimize_model": {
      "post": {
        "operationId": "submit_optimize_model",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Make a 3D model you made game-ready on our model bench: transforms applied, pivot at the base, exported +Y up in metres (a model built on its side stays on its side), then decimated to a phone or desktop triangle budget without welding UV seams or breaking skin weights.",
        "description": "Make a 3D model you made game-ready on our model bench: transforms applied, pivot at the base, exported +Y up in metres (a model built on its side stays on its side), then decimated to a phone or desktop triangle budget without welding UV seams or breaking skin weights.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/optimize_model/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/optimize_model_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/fracture_model": {
      "post": {
        "operationId": "submit_fracture_model",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Pre-fracture a 3D model you made into Voronoi pieces for destruction, UVs kept; a closed mesh's breaks are capped.",
        "description": "Pre-fracture a 3D model you made into Voronoi pieces for destruction, UVs kept; a closed mesh's breaks are capped. Up to 20,000 triangles and unrigged: run optimize_model or lod_model first on a bigger one. One .glb with the pieces, sometimes fewer than `pieces`.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/fracture_model/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/fracture_model_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/lod_model": {
      "post": {
        "operationId": "submit_lod_model",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Make levels of detail of a 3D model you made on our model bench: model.lod1.glb onwards, each a decimate of the one before, UV seams and skin weights kept.",
        "description": "Make levels of detail of a 3D model you made on our model bench: model.lod1.glb onwards, each a decimate of the one before, UV seams and skin weights kept. Your model is LOD0.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/lod_model/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/lod_model_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/rig_model": {
      "post": {
        "operationId": "submit_rig_model",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Rig a 3D model you made: give an unrigged humanoid mesh library `motions` (rigged by our 3D provider: the rigged model plus one .glb per motion, FBX on request), author idle, walk, attack and death onto a biped rig that has no clips on our model bench, or fit a donor biped's rig and clips onto an unrigged mesh.",
        "description": "Rig a 3D model you made: give an unrigged humanoid mesh library `motions` (rigged by our 3D provider: the rigged model plus one .glb per motion, FBX on request), author idle, walk, attack and death onto a biped rig that has no clips on our model bench, or fit a donor biped's rig and clips onto an unrigged mesh. A free rig check runs first and refuses (uncharged, with the reason) a model that is not a biped, is already animated or rigged, or has nothing to borrow, among the other checks it names.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/rig_model/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/rig_model_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/render_model": {
      "post": {
        "operationId": "submit_render_model",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Photograph a 3D model you made on our model bench: views evenly round it, a straight-on front view and one contact sheet of the turn, as PNGs.",
        "description": "Photograph a 3D model you made on our model bench: views evenly round it, a straight-on front view and one contact sheet of the turn, as PNGs. See whether it is the right way up, the right colour, and visible at all.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/render_model/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/render_model_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/finalize_model": {
      "post": {
        "operationId": "submit_finalize_model",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Finish a 3D model you made on our model bench and prove it: materials that would draw nothing or a silhouette repaired (correct ones untouched), clips not in keep_clips dropped, then a front view and contact sheet rendered.",
        "description": "Finish a 3D model you made on our model bench and prove it: materials that would draw nothing or a silhouette repaired (correct ones untouched), clips not in keep_clips dropped, then a front view and contact sheet rendered. model.glb plus the pictures.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/finalize_model/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/finalize_model_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/build_level": {
      "post": {
        "operationId": "submit_build_level",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Build a low-poly 3D level on our model bench from a spec: rooms and yards on a 0.25 m grid, walls with doors and windows, ramps, stairs, platforms, props from a fixed kit, one palette and an ink outline.",
        "description": "Build a low-poly 3D level on our model bench from a spec: rooms and yards on a 0.25 m grid, walls with doors and windows, ramps, stairs, platforms, props from a fixed kit, one palette and an ink outline. level.glb has named art nodes, convex colliders under `colliders` and marker empties (spawn, exit, pickup…) under `markers`; plan.png and view.png show it. A spawn, exit or checkpoint with no floor under it is refused at submit, uncharged; props blocking doors are reported.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/build_level/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/build_level_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/author_skin": {
      "post": {
        "operationId": "submit_author_skin",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Make a character's face, hands and body read as skin, the same way across a cast: the bench renders exact views, a vision pass marks exposed skin, and the bench paints it to one tone with its shading kept (eyes, lips and clothing untouched).",
        "description": "Make a character's face, hands and body read as skin, the same way across a cast: the bench renders exact views, a vision pass marks exposed skin, and the bench paints it to one tone with its shading kept (eyes, lips and clothing untouched). model.glb and a proof sheet. Takes minutes.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/author_skin/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/author_skin_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/retexture_model": {
      "post": {
        "operationId": "submit_retexture_model",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Give a 3D model you made a new look on the same mesh (a variant, a season, a cast member): its four sides are repainted by the image model, under your game's style lock when you name the game, and projected back onto its own materials.",
        "description": "Give a 3D model you made a new look on the same mesh (a variant, a season, a cast member): its four sides are repainted by the image model, under your game's style lock when you name the game, and projected back onto its own materials. model.glb, a proof sheet and the painted views. Priced by quality. Takes minutes.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/retexture_model/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/retexture_model_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/generate_video": {
      "post": {
        "operationId": "submit_generate_video",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Generate a short video clip (2–30 s at 480p, 720p or 1080p; 16:9, 9:16 or 1:1, or a still's own shape when it animates one) as an MP4: from a prompt, by animating a still of yours (optionally to an end frame), or keeping the subjects of up to four reference pictures.",
        "description": "Generate a short video clip (2–30 s at 480p, 720p or 1080p; 16:9, 9:16 or 1:1, or a still's own shape when it animates one) as an MP4: from a prompt, by animating a still of yours (optionally to an end frame), or keeping the subjects of up to four reference pictures. Generated, not gameplay: use it for title, intro or outro cards, never as footage of the game. Takes minutes.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/generate_video/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/generate_video_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/edit_video": {
      "post": {
        "operationId": "submit_edit_video",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Edit a short clip (2–10 s, MP4 or MOV) by an instruction: restyle it, replace or add a subject, change the time of day, optionally following a reference picture; at 720p or 1080p, its sound kept or made anew.",
        "description": "Edit a short clip (2–10 s, MP4 or MOV) by an instruction: restyle it, replace or add a subject, change the time of day, optionally following a reference picture; at 720p or 1080p, its sound kept or made anew. An MP4. The result is generated, not gameplay: never present it as footage of the game. Takes minutes.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/edit_video/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/edit_video_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/lip_sync": {
      "post": {
        "operationId": "submit_lip_sync",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Make a portrait speak: a picture of a face and a line of speech (voice_line's line.mp3, dialogue's dialogue.mp3, or your own recording) become a talking clip as an MP4, lips, head and shoulders moving with the words, at 480p or 720p, up to 60 s, in the portrait's shape.",
        "description": "Make a portrait speak: a picture of a face and a line of speech (voice_line's line.mp3, dialogue's dialogue.mp3, or your own recording) become a talking clip as an MP4, lips, head and shoulders moving with the words, at 480p or 720p, up to 60 s, in the portrait's shape. The portrait: one clear face toward the camera, head and shoulders in frame: a person, a drawn character or an animal. The portrait must be your own face or a character you made or generated: never a photo of a real person who has not agreed, and never a public figure. For story scenes and trailers with a speaking character; generated, not gameplay: never present it as footage of the game. Priced per second of speech. Takes minutes.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/lip_sync/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/lip_sync_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/cutout": {
      "post": {
        "operationId": "submit_cutout",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Cut the subject out of a picture of yours, whatever the background (a photo, a painted scene): cutout.png on a transparent background, optionally its mask and trimmed to the subject.",
        "description": "Cut the subject out of a picture of yours, whatever the background (a photo, a painted scene): cutout.png on a transparent background, optionally its mask and trimmed to the subject. A flat green or magenta backdrop keys for free with key_sprite. Included in your plan's credits, or on your own key for a small platform fee.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/cutout/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/cutout_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/upscale": {
      "post": {
        "operationId": "submit_upscale",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Make a picture of yours two or four times bigger with detail added (up to 1024 px in, 4096 px out); a transparent picture stays transparent.",
        "description": "Make a picture of yours two or four times bigger with detail added (up to 1024 px in, 4096 px out); a transparent picture stays transparent. Priced by the size it makes. Included in your plan's credits, or on your own key for a small platform fee.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/upscale/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/upscale_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/transcribe_words": {
      "post": {
        "operationId": "submit_transcribe_words",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Transcribe audio or video of yours word by word: transcript.json with every word's start, end and confidence, the fillers and repeats to cut (um, uh, like, you know, \"the the\") and the sentences, each as a word range; plus SRT and VTT.",
        "description": "Transcribe audio or video of yours word by word: transcript.json with every word's start, end and confidence, the fillers and repeats to cut (um, uh, like, you know, \"the the\") and the sentences, each as a word range; plus SRT and VTT. Optionally translated, times kept. Edit by cutting word ranges; pass transcript.json to caption_video. Priced by the minute of speech. Included in your plan's credits, or on your own key for a small platform fee.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/transcribe_words/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/transcribe_words_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/caption_video": {
      "post": {
        "operationId": "submit_caption_video",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Caption a clip of yours from its words: SRT, VTT and every word's times as JSON, or burned into the video (block or word-pop style; a social safe area keeps captions clear of a vertical app's buttons).",
        "description": "Caption a clip of yours from its words: SRT, VTT and every word's times as JSON, or burned into the video (block or word-pop style; a social safe area keeps captions clear of a vertical app's buttons). From a transcript.json you already have, the words cost nothing. Priced by the minute of speech. Included in your plan's credits, or on your own key for a small platform fee.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/caption_video/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/caption_video_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/split_stems": {
      "post": {
        "operationId": "submit_split_stems",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Split a recording of yours (or a video's sound, up to 10 minutes) into stems: vocals, drums, bass and the rest, one MP3 or WAV each, unmastered so they sum back to the mix, plus stems.json (each file and its peak; a stem with nothing in it is marked silent).",
        "description": "Split a recording of yours (or a video's sound, up to 10 minutes) into stems: vocals, drums, bass and the rest, one MP3 or WAV each, unmastered so they sum back to the mix, plus stems.json (each file and its peak; a stem with nothing in it is marked silent). For a remix, a karaoke bed, or music under a voice. Priced by the minute. Included in your plan's credits, or on your own key for a small platform fee.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/split_stems/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/split_stems_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/isolate_voice": {
      "post": {
        "operationId": "submit_isolate_voice",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Lift the voice out of a noisy recording of yours (or a video's sound, up to an hour): voice.mp3 or voice.wav with the room, the hum, the traffic and the music under it taken away, at the recording's own level.",
        "description": "Lift the voice out of a noisy recording of yours (or a video's sound, up to an hour): voice.mp3 or voice.wav with the room, the hum, the traffic and the music under it taken away, at the recording's own level. For narration recorded somewhere loud, or a character's lines recorded at a desk. Priced by the minute. Included in your plan's credits, or on your own key for a small platform fee.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/isolate_voice/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/isolate_voice_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/beat_grid": {
      "post": {
        "operationId": "submit_beat_grid",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Read a piece of music of yours for its beat: tempo, every beat and downbeat, the bars and a confidence (beats.json).",
        "description": "Read a piece of music of yours for its beat: tempo, every beat and downbeat, the bars and a confidence (beats.json). Or, as a cut_list, cut a video of yours to a length with every cut on a beat: cut_list.json (the segments funtools trailer applies), optionally rendered as cut.mp4 with the music under it. Runs on our machine; a flat price, a render a little more.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/beat_grid/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/beat_grid_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/mask_subject": {
      "post": {
        "operationId": "submit_mask_subject",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Mask the subject of a clip of yours (up to 30 s) on every frame: subject.webm, the subject on a transparent background, or a PNG frame sequence, and always mask.mp4.",
        "description": "Mask the subject of a clip of yours (up to 30 s) on every frame: subject.webm, the subject on a transparent background, or a PNG frame sequence, and always mask.mp4. Pick it on the first frame with points, a box or a few words, or leave it to the main subject; it is tracked from there. Priced by the second. Included in your plan's credits, or on your own key for a platform fee.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/mask_subject/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/mask_subject_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/make_shorts": {
      "post": {
        "operationId": "submit_make_shorts",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Cut a long video of yours (up to an hour) into short clips for vertical feeds: 9:16 or 1:1, 15 to 60 s each, picked from what is said for a hook, a payoff and standing alone, ranked best first; captions burned in if you like, clear of a feed's buttons.",
        "description": "Cut a long video of yours (up to an hour) into short clips for vertical feeds: 9:16 or 1:1, 15 to 60 s each, picked from what is said for a hook, a payoff and standing alone, ranked best first; captions burned in if you like, clear of a feed's buttons. shorts.json lists each short's start and end in the source, a title, why it was picked and its score; transcript.json comes back to reuse. Priced by the minute of speech, plus the ranking. Included in your plan's credits, or on your own key for a platform fee.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/make_shorts/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/make_shorts_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/search_footage": {
      "post": {
        "operationId": "submit_search_footage",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Find the moments in a video of yours (up to an hour) that match what you describe, by what is said and by what is seen: ranked matches with their start, end, score, why and a thumbnail; with cut, each as its own clip.",
        "description": "Find the moments in a video of yours (up to an hour) that match what you describe, by what is said and by what is seen: ranked matches with their start, end, score, why and a thumbnail; with cut, each as its own clip. frames.json captions every frame read, transcript.json the words, to search again. Priced by the minute: the speech and the frames read. Included in your plan's credits, or on your own key for a small platform fee.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/search_footage/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/search_footage_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/detect_chords": {
      "post": {
        "operationId": "submit_detect_chords",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Read a recording of yours for its chords over time, its key and its tempo: chords.json (every chord's start and end, the bars) and chart.txt, a lead sheet backing_track takes back.",
        "description": "Read a recording of yours for its chords over time, its key and its tempo: chords.json (every chord's start and end, the bars) and chart.txt, a lead sheet backing_track takes back. Triads (major, minor); a seventh reads as its triad. Runs on our machine; a flat price.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/detect_chords/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/detect_chords_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/backing_track": {
      "post": {
        "operationId": "submit_backing_track",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Make an instrumental backing track from a chord chart (yours, or detect_chords' chords.json), a key, a tempo and a style: rhythm section and pads, no lead and no vocals, to play or sing over.",
        "description": "Make an instrumental backing track from a chord chart (yours, or detect_chords' chords.json), a key, a tempo and a style: rhythm section and pads, no lead and no vocals, to play or sing over. backing.mp3 and chart.json, with the tempo it was measured at so you know it held. Priced as a music clip or a full track. Included in your plan's credits, or on your own key for a small platform fee.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/backing_track/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/backing_track_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/brand_kit": {
      "post": {
        "operationId": "submit_brand_kit",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Read a logo or brand picture of yours into a kit: a palette with roles (primary, secondary, accent, ink, paper), the text colour that reads on each and its contrast, a type pairing of open-licence fonts to match, as kit.json, palette.css and a swatches.png card.",
        "description": "Read a logo or brand picture of yours into a kit: a palette with roles (primary, secondary, accent, ink, paper), the text colour that reads on each and its contrast, a type pairing of open-licence fonts to match, as kit.json, palette.css and a swatches.png card. Runs on our machine; a flat price.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/brand_kit/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/brand_kit_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/resize_design": {
      "post": {
        "operationId": "submit_resize_design",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Make one picture of yours into several platform sizes at once (square, portrait, story, landscape, link card, banner, or your own): each cropped where the picture's detail is, or the whole picture extended over a blurred copy of itself when a crop would lose it.",
        "description": "Make one picture of yours into several platform sizes at once (square, portrait, story, landscape, link card, banner, or your own): each cropped where the picture's detail is, or the whole picture extended over a blurred copy of itself when a crop would lose it. sizes.json says which. Runs on our machine; a flat price.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/resize_design/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/resize_design_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/make_deck": {
      "post": {
        "operationId": "submit_make_deck",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Set an outline in Markdown as a slide deck: deck.pdf and one PNG a slide (16:9 or 4:3, light or dark, or your brand_kit's colours), titles, bullets, quotes, code and your own pictures laid out, speaker notes kept in deck.json, a slide that does not fit marked.",
        "description": "Set an outline in Markdown as a slide deck: deck.pdf and one PNG a slide (16:9 or 4:3, light or dark, or your brand_kit's colours), titles, bullets, quotes, code and your own pictures laid out, speaker notes kept in deck.json, a slide that does not fit marked. Runs on our machine; a flat price.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/make_deck/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/make_deck_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/list_characters": {
      "post": {
        "operationId": "submit_list_characters",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "The character library: animated characters ready to use, 2D (a sprite sheet with idle, walk, run, jump, attack, hit, death and blink under the same names for every character; a flyer has no jump) and 3D (a rigged GLB, every clip on one humanoid rig).",
        "description": "The character library: animated characters ready to use, 2D (a sprite sheet with idle, walk, run, jump, attack, hit, death and blink under the same names for every character; a flyer has no jump) and 3D (a rigged GLB, every clip on one humanoid rig). Fastest way to a living character when one fits; your own art stays free to make.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/list_characters/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/list_characters_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/get_character": {
      "post": {
        "operationId": "submit_get_character",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Copy one library character into your files: sheet.png + sheet.json (Pixi-ready, feet as the anchor) and base.png, or model.glb with its clips by name, its turntable and its concept picture.",
        "description": "Copy one library character into your files: sheet.png + sheet.json (Pixi-ready, feet as the anchor) and base.png, or model.glb with its clips by name, its turntable and its concept picture. The answer says how to play it.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/get_character/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/get_character_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/restyle_character": {
      "post": {
        "operationId": "submit_restyle_character",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Give a library character your game's look and keep every motion: 2D redraws the base and each frame in the new look (priced per frame; name fewer animations to pay less; the result lists them under `animations`), 3D repaints the model and keeps its rig and clips (the result lists them under `clips`).",
        "description": "Give a library character your game's look and keep every motion: 2D redraws the base and each frame in the new look (priced per frame; name fewer animations to pay less; the result lists them under `animations`), 3D repaints the model and keeps its rig and clips (the result lists them under `clips`). Takes minutes.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/restyle_character/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/restyle_character_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/author_motion": {
      "post": {
        "operationId": "submit_author_motion",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "New clips on a rigged humanoid from data, not code: wave, nod, hop, strike, flinch, celebrate, each with a few dials in tuned ranges, built on the model's own stance.",
        "description": "New clips on a rigged humanoid from data, not code: wave, nod, hop, strike, flinch, celebrate, each with a few dials in tuned ranges, built on the model's own stance. The model's clips are kept.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/author_motion/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/author_motion_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/retarget_clips": {
      "post": {
        "operationId": "submit_retarget_clips",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "Carry clips onto your rigged humanoid from another model or a 3D library character: bones matched by name (a prefixed name matches: rig:LeftArm = LeftArm), the motion kept, the hips' travel scaled to your rig.",
        "description": "Carry clips onto your rigged humanoid from another model or a 3D library character: bones matched by name (a prefixed name matches: rig:LeftArm = LeftArm), the motion kept, the hips' travel scaled to your rig. Feet are not locked: check with audit_clips.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/retarget_clips/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/retarget_clips_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/v1/tools/play": {
      "post": {
        "operationId": "submit_play",
        "tags": [
          "tools"
        ],
        "x-funpixel-scope": "tools:run",
        "summary": "A blind first-time player on your game's draft: a vision model that never sees the code plays it through the screen alone (touch on a phone, mouse and keys on a desktop), one act at a time with the game held still between acts, and files a report: could it start, read the goal, act, reach an ending; each of your criteria judged from the screen; the three worst defects, each with the step and the frame that shows it.",
        "description": "A blind first-time player on your game's draft: a vision model that never sees the code plays it through the screen alone (touch on a phone, mouse and keys on a desktop), one act at a time with the game held still between acts, and files a report: could it start, read the goal, act, reach an ending; each of your criteria judged from the screen; the three worst defects, each with the step and the frame that shows it. Build the draft first. Priced per act. Takes minutes.\n\nA job: `submitJob` for this tool. Every input field, its credits and its limits: https://docs.funpixel.ai/tools/play/",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/play_input"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "The job an earlier request with this Idempotency-Key made."
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "A new job.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    }
  },
  "security": [
    {
      "bearer": []
    }
  ],
  "servers": [
    {
      "url": "https://api.funpixel.ai"
    }
  ],
  "webhooks": {
    "jobFinished": {
      "post": {
        "description": "Sent when the job ends (succeeded, failed or cancelled), at least once:\nretried on a network error, 408, 429 or 5xx after 10 s, 60 s and 300 s, then\ngiven up. A 2xx ends it; another 4xx ends it at once. Redirects are not\nfollowed. Each attempt is recorded, survives a restart, and is readable at\n`GET /v1/jobs/{job_id}/deliveries`; dedup on `Funpixel-Job-Id`.\nVerify `Funpixel-Signature: t=<unix>,v1=<hex>`: HMAC-SHA256 keyed with the\njob's `webhook_secret` over `<t>.<raw body>`; reject an old `t`. The job\nitself (`GET /v1/jobs/{job_id}`) stays the truth.\n",
        "operationId": "jobFinished",
        "parameters": [
          {
            "in": "header",
            "name": "Funpixel-Signature",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Funpixel-Job-Id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Job"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges it."
          }
        },
        "summary": "The finished job, POSTed to the submit's `webhook_url`."
      }
    }
  }
}
