{
  "openapi": "3.1.0",
  "info": {
    "title": "Piooy Public API",
    "version": "1.0.0",
    "description": "Piooy exposes a small, stable API surface for programmatically generating images and videos with modern AI models and polling for completion. Authenticate with an API key created in the Piooy dashboard (Settings → API Keys).",
    "contact": {
      "name": "Piooy support",
      "url": "https://piooy.com/contact"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://piooy.com/terms-of-service"
    }
  },
  "servers": [
    {
      "url": "https://piooy.com",
      "description": "Production"
    }
  ],
  "components": {
    "securitySchemes": {
      "BearerApiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Piooy API Key",
        "description": "Send your Piooy API key in the `Authorization: Bearer <key>` header. Keys are managed at /settings/apikeys."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "code",
          "message"
        ],
        "properties": {
          "code": {
            "type": "integer",
            "description": "Non-zero on error"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "GenerateRequest": {
        "type": "object",
        "required": [
          "provider",
          "mediaType",
          "model",
          "scene"
        ],
        "properties": {
          "provider": {
            "type": "string",
            "description": "AI provider identifier, e.g. evolink, pearktrue."
          },
          "mediaType": {
            "type": "string",
            "enum": [
              "image",
              "video",
              "character",
              "music"
            ]
          },
          "model": {
            "type": "string",
            "description": "Model id (see /ai/models for the canonical list, e.g. nano-banana-pro, seedream-4-5, veo-3-1)."
          },
          "scene": {
            "type": "string",
            "enum": [
              "text-to-image",
              "image-to-image",
              "text-to-video",
              "image-to-video",
              "video-to-video",
              "character-creation",
              "text-to-music"
            ]
          },
          "prompt": {
            "type": "string",
            "description": "Natural-language prompt. Required unless options supplies equivalent input."
          },
          "options": {
            "type": "object",
            "additionalProperties": true,
            "description": "Model-specific options, e.g. { resolution: \"2K\", aspect_ratio: \"16:9\", duration: 5 }."
          }
        }
      },
      "GenerateResponse": {
        "type": "object",
        "properties": {
          "code": {
            "type": "integer"
          },
          "message": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "properties": {
              "taskId": {
                "type": "string",
                "description": "Piooy task id. Poll /api/v1/task/{id} until status is SUCCESS or FAILED."
              }
            }
          }
        }
      },
      "TaskResponse": {
        "type": "object",
        "properties": {
          "code": {
            "type": "integer"
          },
          "message": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "status": {
                "type": "string",
                "enum": [
                  "PENDING",
                  "PROCESSING",
                  "SUCCESS",
                  "FAILED",
                  "ERROR"
                ]
              },
              "mediaType": {
                "type": "string"
              },
              "model": {
                "type": "string"
              },
              "provider": {
                "type": "string"
              },
              "taskResult": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": true,
                "description": "Final asset URLs and metadata once status is SUCCESS."
              }
            }
          }
        }
      },
      "ContactRequest": {
        "type": "object",
        "required": [
          "email",
          "content"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          },
          "content": {
            "type": "string",
            "maxLength": 5000
          }
        }
      }
    }
  },
  "security": [
    {
      "BearerApiKey": []
    }
  ],
  "paths": {
    "/api/v1/generate": {
      "post": {
        "summary": "Start an image / video / music / character generation task",
        "description": "Accepts a provider, model, scene and prompt. Returns a taskId you can poll at /api/v1/task/{id}. Subject to per-user, per-minute, per-day, and concurrency limits.",
        "operationId": "createGenerationTask",
        "tags": [
          "generation"
        ],
        "security": [
          {
            "BearerApiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Task accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GenerateResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized (missing or invalid API key)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded"
          }
        }
      },
      "options": {
        "summary": "CORS preflight",
        "operationId": "generateOptions",
        "security": [],
        "responses": {
          "204": {
            "description": "OK"
          }
        }
      }
    },
    "/api/v1/task/{id}": {
      "get": {
        "summary": "Poll the status of a generation task",
        "operationId": "getTask",
        "tags": [
          "generation"
        ],
        "security": [
          {
            "BearerApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Task id returned by /api/v1/generate."
          },
          {
            "name": "refresh",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1",
                "assets"
              ]
            },
            "description": "Set to `1` to trigger a live refresh from the upstream provider, or `assets` to persist finished assets to Piooy storage."
          }
        ],
        "responses": {
          "200": {
            "description": "Task found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Not the task owner"
          },
          "404": {
            "description": "Task not found"
          }
        }
      }
    },
    "/api/v1/contact": {
      "post": {
        "summary": "Submit a contact-form message (no auth required)",
        "operationId": "submitContact",
        "tags": [
          "contact"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Submitted"
          },
          "400": {
            "description": "Invalid payload"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    }
  }
}