{
 "openapi": "3.1.0",
 "info": {
  "title": "Metameta Launchpad API",
  "version": "1.0.0",
  "description": "Claim a startup listing and join the waitlist. Read-only data lives at /api/*.json. Every write needs a challenge_token from /api/challenge and is rate limited per email and per hashed IP. There is no bypass for verified agents. An agent can start a claim, but only the person with access to the company mailbox can confirm it. Returns 503 not_available until the database is connected."
 },
 "servers": [
  {
   "url": "https://launchpad.metametaclub.com"
  }
 ],
 "paths": {
  "/api/challenge": {
   "get": {
    "summary": "Get a proof-of-work challenge",
    "responses": {
     "200": {
      "description": "Challenge",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Challenge"
        }
       }
      }
     },
     "503": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   },
   "post": {
    "summary": "Exchange a solved challenge or Turnstile token for a challenge_token",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "pow_challenge": {
          "type": "string"
         },
         "pow_nonce": {
          "type": "string",
          "pattern": "^\\d{1,16}$"
         },
         "turnstile_token": {
          "type": "string"
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Single-use token, valid 5 minutes",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ChallengeToken"
        }
       }
      }
     },
     "400": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "403": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "422": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "503": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/claims": {
   "get": {
    "summary": "Public claim status of a listing",
    "parameters": [
     {
      "name": "startup",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Status",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/StartupClaimStatus"
        }
       }
      }
     },
     "404": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "503": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   },
   "post": {
    "summary": "Start a claim (sends a code and link to the company email)",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "startup",
         "email",
         "consent_filming",
         "challenge_token"
        ],
        "additionalProperties": false,
        "properties": {
         "startup": {
          "type": "string",
          "description": "Listing slug from /api/startups.json"
         },
         "email": {
          "type": "string",
          "format": "email",
          "description": "Work email on the startup website's registrable domain (subdomains allowed, free mail rejected)"
         },
         "consent_filming": {
          "type": "boolean",
          "description": "Hustle Yangu filming and publicity consent, chosen explicitly by the human. Required: never assume it. false never affects the listing."
         },
         "challenge_token": {
          "type": "string"
         }
        }
       }
      }
     }
    },
    "responses": {
     "202": {
      "description": "Claim started; code emailed",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Claim"
        }
       }
      }
     },
     "400": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "403": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "422": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "502": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "503": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/claims/{id}": {
   "get": {
    "summary": "Claim status",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Claim",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Claim"
        }
       }
      }
     },
     "404": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "503": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/claims/{id}/verify": {
   "post": {
    "summary": "Confirm a claim with the emailed 6-digit code",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "code"
        ],
        "properties": {
         "code": {
          "type": "string",
          "pattern": "^\\d{6}$"
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Verified",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Claim"
        }
       }
      }
     },
     "400": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "403": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "410": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "422": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "503": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/waitlist": {
   "post": {
    "summary": "Join the waitlist",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "email",
         "role",
         "consent_privacy",
         "challenge_token"
        ],
        "properties": {
         "email": {
          "type": "string",
          "format": "email"
         },
         "role": {
          "enum": [
           "founder",
           "investor",
           "accelerator",
           "media",
           "other"
          ]
         },
         "org_name": {
          "type": "string",
          "maxLength": 120,
          "description": "Optional startup or fund name"
         },
         "consent_privacy": {
          "const": true,
          "description": "The human agrees to https://launchpad.metametaclub.com/privacy"
         },
         "challenge_token": {
          "type": "string"
         }
        }
       }
      }
     }
    },
    "responses": {
     "202": {
      "description": "Accepted. Same response whether or not the email was already listed."
     },
     "400": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "403": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "422": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "503": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  }
 },
 "components": {
  "schemas": {
   "Error": {
    "type": "object",
    "properties": {
     "error": {
      "type": "string"
     },
     "message": {
      "type": "string"
     },
     "field": {
      "type": "string"
     },
     "retry_after_seconds": {
      "type": "integer"
     }
    }
   },
   "Challenge": {
    "type": "object",
    "properties": {
     "algorithm": {
      "const": "sha256-leading-zero-bits"
     },
     "challenge": {
      "type": "string"
     },
     "difficulty": {
      "type": "integer"
     },
     "expires_at": {
      "type": "string",
      "format": "date-time"
     },
     "question": {
      "type": "string"
     },
     "instructions": {
      "type": "string"
     }
    }
   },
   "ChallengeToken": {
    "type": "object",
    "properties": {
     "challenge_token": {
      "type": "string"
     },
     "expires_at": {
      "type": "string",
      "format": "date-time"
     },
     "single_use": {
      "const": true
     }
    }
   },
   "StartupClaimStatus": {
    "type": "object",
    "properties": {
     "startup": {
      "type": "string"
     },
     "claimed": {
      "type": "boolean"
     },
     "claimed_at": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     }
    }
   },
   "Claim": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string"
     },
     "startup": {
      "type": "string"
     },
     "status": {
      "enum": [
       "pending",
       "verified",
       "claimed",
       "rejected",
       "revoked",
       "expired"
      ]
     },
     "email_domain": {
      "type": "string"
     },
     "channel": {
      "enum": [
       "web",
       "api"
      ]
     },
     "verification_method": {
      "enum": [
       "code",
       "link",
       null
      ]
     },
     "started_at": {
      "type": "string"
     },
     "email_sent_at": {
      "type": [
       "string",
       "null"
      ]
     },
     "verified_at": {
      "type": [
       "string",
       "null"
      ]
     },
     "claimed_at": {
      "type": [
       "string",
       "null"
      ]
     },
     "code_expires_at": {
      "type": [
       "string",
       "null"
      ]
     },
     "attempts_remaining": {
      "type": [
       "integer",
       "null"
      ]
     },
     "next_step": {
      "type": "string"
     },
     "links": {
      "type": "object"
     }
    }
   }
  }
 }
}