{
  "openapi": "3.0.3",
  "info": {
    "title": "Oobler Generation API",
    "version": "2.0.0",
    "description": "Runs a photo through whichever of the 9 generation modes your API project is configured for (face swap, identity transfer, headless head-attach, apparel try-on, full random, self-prompt, headshot - remove-background-and-crop - combination: scene + garment + pose - or teleport: the subject cut out of their own photo and composited onto a scene, no generative model involved). Each project runs exactly one mode, chosen once on /api-projects, not a per-request field. Full documentation: https://oobler.oangle.com/docs/api"
  },
  "servers": [{ "url": "https://oobler.oangle.com" }],
  "paths": {
    "/api/v1/generate": {
      "post": {
        "summary": "Run a photo through this project's configured generation mode",
        "operationId": "generate",
        "security": [{ "ApiKeyAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["image"],
                "properties": {
                  "image": {
                    "type": "string",
                    "format": "binary",
                    "description": "The subject/guest photo. JPG, PNG, or WebP. Max 15MB (5MB if this project's mode is 'headshot')."
                  },
                  "reference": {
                    "type": "string",
                    "format": "binary",
                    "description": "A background or garment photo. Required only if this project's configured mode is faceswap/identity/headless/apparel/combination/teleport (the scene, for combination and teleport); ignored otherwise. There is no saved asset library on this API - always supply this inline."
                  },
                  "garment": {
                    "type": "string",
                    "format": "binary",
                    "description": "combination mode only, required there: the uniform/garment laid out with no person wearing it. Ignored for every other mode."
                  },
                  "pose": {
                    "type": "string",
                    "format": "binary",
                    "description": "combination mode only, required there: a full-body photo of someone (or a mannequin) in the pose to copy - only the body pose is taken from it. Ignored for every other mode."
                  },
                  "prompt": {
                    "type": "string",
                    "description": "Only used if this project's configured mode is 'selfprompt' - your own scene description, up to 500 characters."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Generation succeeded",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/GenerateResponse" }
              }
            }
          },
          "400": { "description": "Missing image (or reference/garment/pose, when the mode needs them), or not multipart/form-data" },
          "401": { "description": "Missing or invalid API key" },
          "402": { "description": "Insufficient credits on the project's account" },
          "413": { "description": "An uploaded file exceeds the size limit" },
          "422": { "description": "No face was detected in the photo (headshot mode only)" },
          "429": { "description": "Rate limit exceeded" },
          "502": { "description": "The processing pipeline failed" },
          "504": { "description": "The processing pipeline did not complete in time" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API project's key, created at https://oobler.oangle.com/api-projects. Send as: Authorization: Bearer <key>"
      }
    },
    "schemas": {
      "GenerateResponse": {
        "type": "object",
        "required": ["image", "contentType", "width", "height", "mode", "creditsUsed", "creditBalance"],
        "properties": {
          "image": { "type": "string", "format": "byte", "description": "Base64-encoded image bytes" },
          "contentType": { "type": "string", "example": "image/png" },
          "width": { "type": "integer" },
          "height": { "type": "integer" },
          "mode": {
            "type": "string",
            "enum": ["faceswap", "identity", "headless", "apparel", "random", "selfprompt", "headshot", "combination", "teleport"],
            "description": "The mode this project ran (fixed per project, not chosen per request)"
          },
          "creditsUsed": { "type": "number", "description": "Credits debited for this call" },
          "creditBalance": { "type": "number", "description": "The account's remaining credit balance after this call" }
        }
      }
    }
  }
}
