{
  "openapi": "3.1.0",
  "info": {
    "title": "WaitForge Public API",
    "version": "1.0.0",
    "description": "Public, unauthenticated WaitForge API. The authenticated /api/waitlists/* + /api/account/* routes power the dashboard and are not part of this spec."
  },
  "servers": [
    {
      "url": "https://waitforge.com"
    }
  ],
  "paths": {
    "/api/public/{slug}/config": {
      "get": {
        "summary": "Get waitlist config",
        "operationId": "getWaitlistConfig",
        "description": "Public configuration for a waitlist (title, theme, fields, Turnstile site key). Edge-cached 60s.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "The waitlist slug.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9][a-z0-9-]{2,39}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Public waitlist configuration.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WaitlistConfig"
                }
              }
            }
          },
          "404": {
            "description": "Unknown slug.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/public/{slug}/signup": {
      "post": {
        "summary": "Create a signup",
        "operationId": "createSignup",
        "description": "Add a signup to a waitlist. email + turnstile are required; name/company/twitter are optional and only stored when the waitlist has that field enabled. An already-registered email returns 200 with duplicate:true and the existing position.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "The waitlist slug.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9][a-z0-9-]{2,39}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SignupRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Signup created, or the email was already on the list (duplicate:true).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SignupSuccess"
                }
              }
            }
          },
          "400": {
            "description": "Invalid email, bad JSON, payload too large, or honeypot triggered.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Turnstile failed, or the waitlist is full.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown slug.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited (120 requests / IP / minute).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "WaitlistConfig": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "theme": {
            "type": "object",
            "additionalProperties": true
          },
          "fields": {
            "type": "object",
            "properties": {
              "name": {
                "type": "boolean"
              },
              "company": {
                "type": "boolean"
              },
              "twitter": {
                "type": "boolean"
              }
            }
          },
          "branding": {
            "type": "boolean"
          },
          "turnstile_site_key": {
            "type": "string"
          },
          "paid_signup": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true
          }
        }
      },
      "SignupRequest": {
        "type": "object",
        "required": [
          "email",
          "turnstile"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          },
          "name": {
            "type": "string"
          },
          "company": {
            "type": "string"
          },
          "twitter": {
            "type": "string"
          },
          "ref": {
            "type": "string",
            "description": "Optional referrer code."
          },
          "turnstile": {
            "type": "string",
            "description": "Cloudflare Turnstile token."
          }
        }
      },
      "SignupSuccess": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "duplicate": {
            "type": "boolean",
            "description": "True when the email was already on the list."
          },
          "position": {
            "type": "integer"
          },
          "ref_code": {
            "type": "string"
          },
          "share_path": {
            "type": "string"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          }
        }
      }
    }
  }
}