{
  "openapi": "3.1.0",
  "info": {
    "title": "PixelFireman API",
    "version": "1.0.0",
    "description": "Hosted image and video generation API. Claude routes each image request to the cheapest engine (vector SVG or rendered photo). Authenticate with a pf_live_ key via the Authorization bearer header or the x-api-key header. Image credits never expire.",
    "contact": {
      "name": "PixelFireman",
      "url": "https://pixelfireman.com"
    }
  },
  "servers": [
    {
      "url": "https://pixelfireman.com",
      "description": "Production"
    }
  ],
  "security": [
    { "bearerAuth": [] },
    { "apiKeyHeader": [] }
  ],
  "paths": {
    "/v1/images": {
      "post": {
        "operationId": "generateImage",
        "summary": "Generate an image",
        "description": "Generate an image from a text prompt. mode 'auto' lets the server pick the cheapest engine; 'draw' returns a vector SVG (flat 1 credit); 'generate' returns a rendered photo (credits scale with megapixels).",
        "security": [
          { "bearerAuth": [] },
          { "apiKeyHeader": [] }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/ImageRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Image generated.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ImageResponse" }
              }
            }
          },
          "400": {
            "description": "Missing prompt or image size exceeds the 2048x2048 cap.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SizeError" }
              }
            }
          },
          "402": {
            "description": "Not enough image credits.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/NoCreditsError" }
              }
            }
          },
          "429": {
            "description": "Rate limit or concurrency cap hit for this key.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "451": {
            "description": "Prompt blocked by moderation.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ModerationError" }
              }
            }
          },
          "500": {
            "description": "Server error.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          }
        }
      }
    },
    "/v1/videos": {
      "post": {
        "operationId": "generateVideo",
        "summary": "Generate a video",
        "description": "Generate a short video from a text prompt. The tier controls quality/length and how many wallet minutes it costs.",
        "security": [
          { "bearerAuth": [] },
          { "apiKeyHeader": [] }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/VideoRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Video generated.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/VideoResponse" }
              }
            }
          },
          "400": {
            "description": "Missing prompt or unknown tier.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "402": {
            "description": "Not enough video minutes.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/NoMinutesError" }
              }
            }
          },
          "429": {
            "description": "Rate limit or concurrency cap hit for this key.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "451": {
            "description": "Prompt blocked by moderation.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ModerationError" }
              }
            }
          },
          "500": {
            "description": "Server error.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          }
        }
      }
    },
    "/v1/usage": {
      "get": {
        "operationId": "getUsage",
        "summary": "Get usage and balance",
        "description": "Return usage totals for this key plus the owner wallet balance (image credits and video minutes).",
        "security": [
          { "bearerAuth": [] },
          { "apiKeyHeader": [] }
        ],
        "responses": {
          "200": {
            "description": "Usage and balance.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/UsageResponse" }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Send your key as: Authorization: Bearer pf_live_..."
      },
      "apiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Alternatively send your key as: x-api-key: pf_live_..."
      }
    },
    "schemas": {
      "ImageRequest": {
        "type": "object",
        "required": ["prompt"],
        "properties": {
          "prompt": {
            "type": "string",
            "description": "Text description of the image to create."
          },
          "mode": {
            "type": "string",
            "enum": ["auto", "draw", "generate"],
            "default": "auto",
            "description": "auto = server picks cheapest engine; draw = vector SVG; generate = rendered photo."
          },
          "size": {
            "type": "string",
            "default": "1024x1024",
            "description": "WIDTHxHEIGHT. Max 2048x2048. Ignored for draw mode.",
            "example": "1024x1024"
          }
        }
      },
      "ImageResponse": {
        "type": "object",
        "properties": {
          "engine": {
            "type": "string",
            "description": "Engine that served the request (e.g. draw, or the photo engine name)."
          },
          "cost": {
            "type": "number",
            "description": "Raw provider cost for this call, in USD."
          },
          "format": {
            "type": "string",
            "enum": ["url", "svg"],
            "description": "'url' when image is a hosted URL, 'svg' for draw mode."
          },
          "image": {
            "type": "string",
            "description": "Absolute image URL (format=url) or raw SVG markup (format=svg)."
          },
          "creditsUsed": {
            "type": "integer",
            "description": "Image credits charged for this call."
          },
          "usage": {
            "type": "object",
            "properties": {
              "images": { "type": "integer", "description": "Lifetime images on this key." },
              "cost": { "type": "number", "description": "Lifetime raw cost on this key, USD." },
              "creditsLeft": {
                "type": ["integer", "null"],
                "description": "Image credits remaining in the owner wallet, or null if the key has no owner."
              }
            }
          }
        }
      },
      "VideoRequest": {
        "type": "object",
        "required": ["prompt"],
        "properties": {
          "prompt": {
            "type": "string",
            "description": "Text description of the video to create."
          },
          "tier": {
            "type": "string",
            "enum": ["economy", "standard", "premium"],
            "default": "economy",
            "description": "Quality/length tier. Higher tiers cost more wallet minutes."
          }
        }
      },
      "VideoResponse": {
        "type": "object",
        "properties": {
          "tier": {
            "type": "string",
            "enum": ["economy", "standard", "premium"]
          },
          "format": {
            "type": "string",
            "enum": ["url"]
          },
          "video": {
            "type": "string",
            "description": "Absolute video URL."
          },
          "minutesUsed": {
            "type": "integer",
            "description": "Video minutes charged for this call."
          },
          "usage": {
            "type": "object",
            "properties": {
              "minutesLeft": {
                "type": ["integer", "null"],
                "description": "Video minutes remaining in the owner wallet, or null if the key has no owner."
              }
            }
          }
        }
      },
      "UsageResponse": {
        "type": "object",
        "properties": {
          "name": { "type": "string", "description": "Key name." },
          "images": { "type": "integer", "description": "Lifetime images on this key." },
          "cost": { "type": "number", "description": "Lifetime raw cost on this key, USD." },
          "lastUsed": {
            "type": ["string", "null"],
            "description": "Timestamp of last use, or null."
          },
          "daily": {
            "type": "object",
            "description": "Per-day usage counters for this key.",
            "additionalProperties": true
          },
          "minutes": {
            "type": ["integer", "null"],
            "description": "Video minutes remaining in the owner wallet, or null if the key has no owner."
          },
          "credits": {
            "type": ["integer", "null"],
            "description": "Image credits remaining in the owner wallet, or null if the key has no owner."
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": { "type": "string", "description": "Human-readable error message." }
        },
        "required": ["error"]
      },
      "NoCreditsError": {
        "type": "object",
        "properties": {
          "error": { "type": "string" },
          "noCredits": { "type": "boolean", "enum": [true] },
          "creditsNeeded": {
            "type": "integer",
            "description": "Credits required for the requested size (present when the size needs more than you have)."
          }
        },
        "required": ["error", "noCredits"]
      },
      "NoMinutesError": {
        "type": "object",
        "properties": {
          "error": { "type": "string" },
          "noMinutes": { "type": "boolean", "enum": [true] }
        },
        "required": ["error", "noMinutes"]
      },
      "ModerationError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Begins with 'Blocked: ' followed by the moderation reason."
          },
          "moderated": { "type": "boolean", "enum": [true] }
        },
        "required": ["error", "moderated"]
      },
      "SizeError": {
        "type": "object",
        "properties": {
          "error": { "type": "string" },
          "maxSize": {
            "type": "string",
            "example": "2048x2048",
            "description": "Present when the requested size exceeds the cap."
          }
        },
        "required": ["error"]
      }
    }
  }
}
