{
  "openapi": "3.1.0",
  "info": {
    "title": "BetTip Fair Draw API",
    "version": "1.0.0",
    "summary": "Verifiable random draws bound to the drand beacon.",
    "description": "Pick winners from a list or a number range with a draw bound to a future round of the drand public randomness beacon. Nothing is stored: a draw description always gives the same winners. Specification: https://github.com/bettip-co-za/fair-draw/blob/main/spec/FAIR-DRAW-v1.md",
    "license": { "name": "MIT", "url": "https://opensource.org/licenses/MIT" },
    "contact": { "name": "BetTip", "url": "https://bettip.co.za/fair-draw/api/" }
  },
  "servers": [{ "url": "https://bettip.co.za/api/v1/fair-draw" }],
  "paths": {
    "/round": {
      "get": {
        "summary": "Current and next beacon round, and the round for a given time",
        "parameters": [{ "name": "at", "in": "query", "required": false, "schema": { "type": "string" }, "description": "ISO 8601 time, or unix seconds or milliseconds" }],
        "responses": { "200": { "description": "Round arithmetic", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } }, "400": { "$ref": "#/components/responses/Bad" } }
      }
    },
    "/commit": {
      "post": {
        "summary": "Describe a draw and bind it to a round",
        "requestBody": { "required": true, "content": { "application/json": { "schema": {
          "type": "object", "required": ["pick"],
          "properties": {
            "entries": { "type": "array", "items": { "type": "string", "maxLength": 200 }, "minItems": 2, "maxItems": 50000 },
            "text": { "type": "string", "description": "Entries one per line, instead of entries" },
            "range": { "type": "array", "items": { "type": "integer" }, "minItems": 2, "maxItems": 2, "description": "[from, to] inclusive, instead of entries" },
            "pick": { "type": "integer", "minimum": 1, "maximum": 10000 },
            "title": { "type": "string", "maxLength": 120 },
            "at": { "type": "string", "description": "Draw time (ISO 8601 or unix); the draw binds to the first round at or after it. Default: about 12 seconds ahead." },
            "round": { "type": "integer", "description": "A specific future beacon round, instead of at" }
          } } } } },
        "responses": { "200": { "description": "The spec, its commitment, when the round lands, and the commitment and draw links", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } }, "400": { "$ref": "#/components/responses/Bad" } }
      }
    },
    "/draw": {
      "post": {
        "summary": "Draw the winners once the round has landed",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "spec": { "$ref": "#/components/schemas/Spec" }, "draw": { "type": "string", "description": "A draw link or packed spec, instead of spec" } } } } } },
        "responses": {
          "200": { "description": "Winners, the full proof and the result link", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } },
          "425": { "description": "The round has not landed; body carries landsAt and secondsToGo, header Retry-After" },
          "400": { "$ref": "#/components/responses/Bad" }, "502": { "description": "The beacon relays could not be read; nothing was drawn" }
        }
      }
    },
    "/verify": {
      "post": {
        "summary": "Re-check a proof",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "proof": { "$ref": "#/components/schemas/Proof" }, "link": { "type": "string", "description": "A result link or packed proof, instead of proof" } } } } } },
        "responses": { "200": { "description": "ok, and every check named and explained", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } }, "400": { "$ref": "#/components/responses/Bad" } }
      }
    }
  },
  "components": {
    "responses": { "Bad": { "description": "The request could not be used; error says why in plain words" } },
    "schemas": {
      "Envelope": { "type": "object", "properties": { "api": { "type": "string" }, "version": { "type": "string" }, "docs": { "type": "string" }, "spec": { "type": "string" }, "computedAt": { "type": "string" }, "resource": { "type": "string" }, "ok": { "type": "boolean" }, "data": { "type": "object" } } },
      "Spec": {
        "type": "object", "required": ["v", "chain", "round", "pick"],
        "properties": { "v": { "const": 1 }, "chain": { "type": "string" }, "round": { "type": "integer" }, "pick": { "type": "integer" }, "title": { "type": "string" }, "entries": { "type": "array", "items": { "type": "string" } }, "range": { "type": "array", "items": { "type": "integer" } } }
      },
      "Beacon": { "type": "object", "required": ["round", "randomness", "signature"], "properties": { "round": { "type": "integer" }, "randomness": { "type": "string" }, "signature": { "type": "string" } } },
      "Winner": { "type": "object", "properties": { "position": { "type": "integer" }, "index": { "type": "integer" }, "entry": { "oneOf": [{ "type": "string" }, { "type": "integer" }] } } },
      "Proof": { "type": "object", "required": ["v", "spec", "commitment", "beacon", "winners"], "properties": { "v": { "const": 1 }, "spec": { "$ref": "#/components/schemas/Spec" }, "commitment": { "type": "string" }, "beacon": { "$ref": "#/components/schemas/Beacon" }, "winners": { "type": "array", "items": { "$ref": "#/components/schemas/Winner" } }, "meta": { "type": "object" } } }
    }
  }
}
