{
  "openapi": "3.1.0",
  "info": {
    "title": "Atollship.dev Public API",
    "version": "1.0.0",
    "description": "Public submission API for Atollship.dev — a directory of AI-built projects judged by a 3-judge AI panel. This API is intended for use by LLM agents (ChatGPT, Claude, Perplexity, etc.) acting on behalf of a user. Submissions are reviewed before going public.",
    "contact": {
      "url": "https://atollship.dev/docs/llm-submit"
    }
  },
  "servers": [
    {
      "url": "https://atollship.dev"
    }
  ],
  "tags": [
    {
      "name": "public",
      "description": "Endpoints callable by LLM agents."
    }
  ],
  "paths": {
    "/api/public/projects": {
      "post": {
        "tags": [
          "public"
        ],
        "operationId": "submitProject",
        "summary": "Submit a project to atollship.dev",
        "description": "Anonymous, no-auth submission endpoint for LLM agents. The agent must:\n1. Send a recognisable LLM User-Agent (e.g. `ChatGPT-User`, `Claude-User`, `PerplexityBot`). Other UAs are rejected with 403.\n2. Ask the user for an `owner_email` and pass it through — required so the user can later claim the listing.\n3. Inform the user that the submission appears in a review queue and is not published immediately.\nSubmissions are rate-limited per IP. Duplicates (same normalised URL) are rejected.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitProjectRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Minimal valid submission",
                  "value": {
                    "url": "https://example.com",
                    "owner_email": "owner@example.com"
                  }
                },
                "full": {
                  "summary": "Full submission with metadata",
                  "value": {
                    "url": "https://kriptoinof.lt",
                    "owner_email": "darjus@example.com",
                    "name": "Kriptoinof",
                    "description": "Lithuanian-language crypto news aggregator with AI-generated summaries.",
                    "tools": [
                      "Next.js",
                      "OpenAI",
                      "Vercel"
                    ],
                    "category": "Content"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Submission accepted, pending admin review.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitProjectAccepted"
                },
                "example": {
                  "id": "8f4a5b1c-8e8e-4a1b-9c2a-4f0d1e2a3b4c",
                  "slug": "kriptoinof",
                  "url": "https://atollship.dev/p/kriptoinof",
                  "status": "pending",
                  "message": "Submission received. The project will appear publicly after admin review and AI judging."
                }
              }
            }
          },
          "400": {
            "description": "Validation error (missing/invalid url or owner_email).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "User-Agent not recognised as an LLM agent. Humans should use the website form.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "A project with this URL already exists.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DuplicateError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "SubmitProjectRequest": {
        "type": "object",
        "required": [
          "url",
          "owner_email"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Publicly accessible https URL of the project's homepage.",
            "example": "https://example.com"
          },
          "owner_email": {
            "type": "string",
            "format": "email",
            "description": "Email of the project owner. Required so the owner can later claim the listing. Always ask the user for this before submitting.",
            "example": "owner@example.com"
          },
          "name": {
            "type": "string",
            "description": "Optional project name. If omitted, derived from the URL.",
            "maxLength": 100
          },
          "description": {
            "type": "string",
            "description": "Short, human-written description of what the project does.",
            "maxLength": 500
          },
          "tools": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of tools / tech stack used.",
            "maxItems": 20
          },
          "category": {
            "type": "string",
            "description": "Optional category tag (e.g. Content, Productivity, Dev Tools)."
          }
        }
      },
      "SubmitProjectAccepted": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "slug": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending"
            ]
          },
          "message": {
            "type": "string"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "field": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "DuplicateError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "project": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "slug": {
                "type": "string"
              },
              "status": {
                "type": "string"
              },
              "url": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}