diff --git a/docs/v2/index.html b/docs/v2/index.html
new file mode 100644
index 00000000..9bac6f19
--- /dev/null
+++ b/docs/v2/index.html
@@ -0,0 +1,11 @@
+
+
+
+
+ Boatrace Open API for Programs
+
+
+
+
+
+
diff --git a/docs/v2/openapi.json b/docs/v2/openapi.json
new file mode 100644
index 00000000..4b3b947e
--- /dev/null
+++ b/docs/v2/openapi.json
@@ -0,0 +1,202 @@
+{
+ "openapi": "3.0.3",
+ "info": {
+ "title": "Boatrace Open API",
+ "description": "Boatrace Open API for Programs",
+ "version": "2.0.0"
+ },
+ "servers": [
+ {
+ "url": "https://boatraceopenapi.github.io",
+ "description": "Production server"
+ }
+ ],
+ "paths": {
+ "/programs/v2/today.json": {
+ "get": {
+ "summary": "GET /programs/v2/today.json",
+ "description": "GET operation for /programs/v2/today.json",
+ "parameters": [],
+ "responses": {
+ "200": {
+ "description": "Successful response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/BoatraceOpenAPI"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Bad request"
+ },
+ "404": {
+ "description": "Not found"
+ },
+ "500": {
+ "description": "Internal server error"
+ }
+ }
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "BoatraceOpenAPI": {
+ "type": "object",
+ "properties": {
+ "programs": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "race_date": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "race_stadium_number": {
+ "type": "integer"
+ },
+ "race_number": {
+ "type": "integer"
+ },
+ "race_closed_at": {
+ "type": "string"
+ },
+ "race_grade_number": {
+ "type": "integer"
+ },
+ "race_title": {
+ "type": "string"
+ },
+ "race_subtitle": {
+ "type": "string"
+ },
+ "race_distance": {
+ "type": "integer"
+ },
+ "boats": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "racer_boat_number": {
+ "type": "integer"
+ },
+ "racer_name": {
+ "type": "string"
+ },
+ "racer_number": {
+ "type": "integer"
+ },
+ "racer_class_number": {
+ "type": "integer"
+ },
+ "racer_branch_number": {
+ "type": "integer"
+ },
+ "racer_birthplace_number": {
+ "type": "integer"
+ },
+ "racer_age": {
+ "type": "integer"
+ },
+ "racer_weight": {
+ "type": "integer"
+ },
+ "racer_flying_count": {
+ "type": "integer"
+ },
+ "racer_late_count": {
+ "type": "integer"
+ },
+ "racer_average_start_timing": {
+ "type": "number"
+ },
+ "racer_national_top_1_percent": {
+ "type": "number"
+ },
+ "racer_national_top_2_percent": {
+ "type": "number"
+ },
+ "racer_national_top_3_percent": {
+ "type": "number"
+ },
+ "racer_local_top_1_percent": {
+ "type": "number"
+ },
+ "racer_local_top_2_percent": {
+ "type": "number"
+ },
+ "racer_local_top_3_percent": {
+ "type": "number"
+ },
+ "racer_assigned_motor_number": {
+ "type": "integer"
+ },
+ "racer_assigned_motor_top_2_percent": {
+ "type": "integer"
+ },
+ "racer_assigned_motor_top_3_percent": {
+ "type": "number"
+ },
+ "racer_assigned_boat_number": {
+ "type": "integer"
+ },
+ "racer_assigned_boat_top_2_percent": {
+ "type": "number"
+ },
+ "racer_assigned_boat_top_3_percent": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "racer_boat_number",
+ "racer_name",
+ "racer_number",
+ "racer_class_number",
+ "racer_branch_number",
+ "racer_birthplace_number",
+ "racer_age",
+ "racer_weight",
+ "racer_flying_count",
+ "racer_late_count",
+ "racer_average_start_timing",
+ "racer_national_top_1_percent",
+ "racer_national_top_2_percent",
+ "racer_national_top_3_percent",
+ "racer_local_top_1_percent",
+ "racer_local_top_2_percent",
+ "racer_local_top_3_percent",
+ "racer_assigned_motor_number",
+ "racer_assigned_motor_top_2_percent",
+ "racer_assigned_motor_top_3_percent",
+ "racer_assigned_boat_number",
+ "racer_assigned_boat_top_2_percent",
+ "racer_assigned_boat_top_3_percent"
+ ]
+ }
+ }
+ },
+ "required": [
+ "race_date",
+ "race_stadium_number",
+ "race_number",
+ "race_closed_at",
+ "race_grade_number",
+ "race_title",
+ "race_subtitle",
+ "race_distance",
+ "boats"
+ ]
+ }
+ }
+ },
+ "required": [
+ "programs"
+ ]
+ }
+ }
+ }
+}