{
  "openapi": "3.0.3",
  "info": {
    "title": "EEGLAB plugin version update API",
    "version": "1.0.0",
    "description": "Public submissions for existing plugins only. Administrator approval is required. API, browser and CLI submissions share one upload every 60 seconds across all IP addresses. An additional 10-attempt hourly per-IP limit applies. No API key is required.",
    "contact": {
      "url": "https://sccn.ucsd.edu/eeglab/plugin_uploader/api/index.html"
    }
  },
  "servers": [
    {
      "url": "https://sccn.ucsd.edu/eeglab/plugin_uploader/api/v1"
    }
  ],
  "paths": {
    "/submit-version.php": {
      "post": {
        "operationId": "submitPluginVersion",
        "summary": "Upload an existing plugin release for review",
        "description": "Cookies are not used. X-EEGLAB-API is a required non-secret header. Cross-origin browser requests are not supported. Unknown plugins, extra fields and duplicate pending or published versions are rejected. No automatic retry after a timeout or server error.",
        "parameters": [
          {
            "in": "header",
            "name": "X-EEGLAB-API",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "plugin",
                  "curversion",
                  "archive"
                ],
                "properties": {
                  "plugin": {
                    "type": "string",
                    "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,29}$",
                    "maxLength": 30,
                    "description": "An existing catalog name."
                  },
                  "curversion": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,19}$",
                    "maxLength": 20
                  },
                  "archive": {
                    "type": "string",
                    "format": "binary",
                    "description": "ZIP archive at most 104857600 bytes. Archive safety checks apply."
                  },
                  "critical": {
                    "type": "string",
                    "enum": [
                      "0",
                      "1"
                    ],
                    "description": "Omit to preserve the existing flag. 0 clears it, 1 marks the release critical."
                  },
                  "releasenotes": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "At most 255 UTF-8 bytes. Blank or omitted preserves existing notes. Four-byte characters are not supported."
                  }
                }
              },
              "encoding": {
                "archive": {
                  "contentType": "application/zip"
                }
              }
            }
          }
        },
        "responses": {
          "400": {
            "description": "Invalid input, unknown plugin, unsupported field or unsafe ZIP",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "HTTPS or API header missing, or disallowed browser origin",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "POST is required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "POST"
                  ]
                }
              }
            }
          },
          "409": {
            "description": "Version is already pending or published",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "ZIP or request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "multipart/form-data is required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Global upload interval or hourly per-IP attempt limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Minimum seconds to wait before retrying. Global limit is at most 60 seconds, per-IP limits can be longer.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            }
          },
          "503": {
            "description": "Acceptance could not be confirmed. Do not retry automatically",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "202": {
            "description": "ZIP stored privately for administrator review. This does not publish a release.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status",
                    "request_id",
                    "plugin",
                    "version",
                    "message"
                  ],
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "pending_review"
                      ]
                    },
                    "request_id": {
                      "type": "string",
                      "pattern": "^[a-f0-9]{64}$"
                    },
                    "plugin": {
                      "type": "string"
                    },
                    "version": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "retry_after": {
                "type": "integer",
                "minimum": 1
              }
            }
          }
        }
      }
    }
  }
}
