{
  "openapi": "3.1.1",
  "info": {
    "title": "Row Timer API",
    "version": "v1",
    "summary": "Events, entries, times and results from rowing races, and the rowing club directory.",
    "description": "The Row Timer API lets you put a race's events, crews and times into Row Timer, read\nthem back in one standard shape, read the results Row Timer works out, and read the\nclub directory. The guide, with worked examples, is at https://rowtimer.com/developers.\n\n**Keys.** Every request except the index needs a key, sent as\n`Authorization: Bearer rtk_…`. Make keys in your Row Timer account (organisers), or\nsign up for a developer account at https://rowtimer.com/developers/signup. A key\nacts as you: it sees and changes what you can on the site, within its scopes\n(`read`, or `read` and `write`). Keep keys secret; a key in a web page is public.\n\n**Shape.** JSON in and out, with snake_case names. A list comes as\n`{\"data\": [...], \"next_cursor\": \"...\"}`; pass `cursor` to get the next page, until\n`next_cursor` is null. Fields that have no value are present as null. New fields and\nnew values in an enum may appear without a new version, so ignore what you don't\nknow.\n\n**Time.** Every instant is an integer of Unix epoch milliseconds, in fields ending\n`_ms` (`1804936100530` is 13 March 2027, 11:08:20.530 UTC). Calendar days, such as an\nevent's dates, are `YYYY-MM-DD`.\n\n**Errors** are RFC 9457 `application/problem+json`, with a `type` linking to its\nexplanation, a `detail` saying what to change, a `request_id` to quote to us, and\n`errors` listing each problem at once: a query parameter by its name, anything in a\nrequest body by a JSON pointer to it. A query parameter an operation doesn't take is\nan error too, rather than ignored, so a misspelt filter never looks like a real\nanswer.\n\n**Limits.** Each key may make 600 reads and 300 writes in any 10 minutes. Every\nanswer says how many are left (`RateLimit-Remaining`) and when the count resets\n(`RateLimit-Reset`, seconds); past the limit the answer is 429 with `Retry-After`.\n\n**Caching.** Answers carry an `ETag`; send it back as `If-None-Match` and an\nunchanged answer is a 304 with no body.\n",
    "contact": {
      "name": "Row Timer",
      "email": "info@rowtimer.com",
      "url": "https://rowtimer.com/developers"
    },
    "termsOfService": "https://rowtimer.com/developers#terms"
  },
  "externalDocs": {
    "description": "The guide, with worked examples",
    "url": "https://rowtimer.com/developers"
  },
  "servers": [
    {
      "url": "https://api.rowtimer.com/v1",
      "description": "Row Timer"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "About",
      "description": "The API itself, and the key in use."
    },
    {
      "name": "Events",
      "description": "Events, each one document: the event, its races and its crews with their times.\nA key sees published events (public, confirmed by their host club) and its own:\nits club's, those it has been given, and those it uploaded. Seat races never appear.\n"
    },
    {
      "name": "Clubs",
      "description": "The rowing club directory, with each club's blade and location, and its crews'\nresults. Blade images fetched from anywhere but rowtimer.com carry the Row Timer\nmark at 160 and 450 pixels.\n"
    },
    {
      "name": "Results",
      "description": "Results across events, to compare crews from different races."
    }
  ],
  "paths": {
    "/": {
      "get": {
        "operationId": "getIndex",
        "tags": [
          "About"
        ],
        "summary": "What this is, and where its documentation is",
        "security": [],
        "responses": {
          "200": {
            "description": "The API's name, version and links.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Index"
                },
                "example": {
                  "name": "Row Timer API",
                  "version": "v1",
                  "api_revision": "2026-10-08",
                  "docs": "https://rowtimer.com/developers",
                  "reference": "https://rowtimer.com/developers/reference",
                  "openapi": "https://api.rowtimer.com/v1/openapi.json"
                }
              }
            }
          }
        }
      }
    },
    "/me": {
      "get": {
        "operationId": "getMe",
        "tags": [
          "About"
        ],
        "summary": "The key in use and the account it acts as",
        "responses": {
          "200": {
            "description": "Your account and this key.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Me"
                },
                "example": {
                  "account": {
                    "id": 245,
                    "username": "sandford",
                    "name": "Nicholas Angel",
                    "kind": "organiser",
                    "may_write": true,
                    "club": {
                      "id": 900,
                      "name": "Sandford Boat Club",
                      "code": "SFD",
                      "country": "GBR"
                    }
                  },
                  "key": {
                    "id": 12,
                    "name": "Sandford results feed",
                    "scopes": [
                      "read",
                      "write"
                    ],
                    "expires_ms": null
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/events": {
      "get": {
        "operationId": "listEvents",
        "tags": [
          "Events"
        ],
        "summary": "Events, newest first, or those changed since a time",
        "description": "Published events and this key's own. With `updated_since`, the events changed at\nor after that time, in the order they changed: keep the latest `updated_ms` you\nhave seen and pass it next time to keep a copy in step.\n",
        "parameters": [
          {
            "name": "club_id",
            "in": "query",
            "description": "Events this club took part in.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "role",
            "in": "query",
            "description": "With `club_id`, how it took part. `host` events it hosted, `entered` events it had crews at, `any` (the default) either.",
            "schema": {
              "type": "string",
              "enum": [
                "host",
                "entered",
                "any"
              ]
            }
          },
          {
            "name": "country",
            "in": "query",
            "description": "The host club's IOC country code, such as GBR.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "head",
                "regatta"
              ]
            }
          },
          {
            "name": "from",
            "in": "query",
            "description": "Events ending on or after this day.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "description": "Events starting on or before this day.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Words in the event's name.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "external_id",
            "in": "query",
            "description": "The id you gave the event when you uploaded it.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "mine",
            "in": "query",
            "description": "Only this key's own events.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "description": "Events changed at or after this time (epoch ms).",
            "schema": {
              "type": "integer"
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of events.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "next_cursor"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Event"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": 1734,
                      "external_id": "sandford-hor-2027",
                      "type": "head",
                      "name": "Sandford Head of the River 2027",
                      "short_name": "Sandford HoR",
                      "start_date": "2027-03-13",
                      "end_date": "2027-03-13",
                      "privacy": "public",
                      "official": true,
                      "host_club": {
                        "id": 900,
                        "name": "Sandford Boat Club",
                        "code": "SFD",
                        "country": "GBR"
                      },
                      "host_confirmed": true,
                      "uploaded_by": null,
                      "venue": {
                        "name": "Sandford Boathouse",
                        "lat": 51.712,
                        "lon": -1.236
                      },
                      "gmt_dataset": "rt_default",
                      "url": "https://rowtimer.com/event/1734",
                      "revision": 212,
                      "updated_ms": 1804939600000
                    }
                  ],
                  "next_cursor": "eyJxIjoiMjU5NDUwNTg2YWJlIiwiayI6WyIyMDI3LTAzLTEzIiwxNzM0XX0"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "createEvent",
        "tags": [
          "Events"
        ],
        "summary": "Put an event on Row Timer, with as much of it as you have",
        "description": "One request makes an event with its races and crews, and their times. A finished\nhead race from a spreadsheet goes up in one request. Give an `external_id` and a\nretried request can't make the event twice: the second answers 409 with its id.\n\nThe event's host club is `host_club`, or your own club if you have one. If your\naccount belongs to the host club the event is confirmed at once. Otherwise it waits\nfor the host club to confirm it, and until then it isn't published or official, and\nappears only to you and the host club. Either way you can go on changing it with\n`PATCH /events/{id}`.\n\nCrews name their race by its name. A crew's club is matched against the directory;\na club it doesn't have is kept as written, and `warnings` says so.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EventInput"
              },
              "example": {
                "name": "Sandford Head of the River 2027",
                "start_date": "2027-03-13",
                "type": "head",
                "host_club": {
                  "country": "GBR",
                  "code": "SFD"
                },
                "external_id": "sandford-hor-2027",
                "races": [
                  {
                    "name": "Division 1",
                    "distance": 4200,
                    "splits": [
                      {
                        "name": "Bridge",
                        "distance": 2100
                      }
                    ],
                    "status": "published"
                  }
                ],
                "crews": [
                  {
                    "boat_number": 1,
                    "name": "Butterman",
                    "club": {
                      "country": "GBR",
                      "code": "SFD"
                    },
                    "category": "Op 8+",
                    "race": "Division 1",
                    "elapsed": {
                      "split_a": "7:02.4",
                      "finish": "14:31.9"
                    }
                  },
                  {
                    "boat_number": 2,
                    "name": "Angel",
                    "club": "Buford Abbey Rowing Club",
                    "category": "MasC 8+",
                    "race": "Division 1",
                    "status": "dnf"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The event as made, with every race and crew, and any warnings.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string",
                  "format": "uri"
                },
                "description": "The new event's address in the API."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WriteResult"
                },
                "example": {
                  "id": 1734,
                  "external_id": "sandford-hor-2027",
                  "type": "head",
                  "name": "Sandford Head of the River 2027",
                  "short_name": null,
                  "start_date": "2027-03-13",
                  "end_date": "2027-03-13",
                  "privacy": "public",
                  "official": true,
                  "host_club": {
                    "id": 900,
                    "name": "Sandford Boat Club",
                    "code": "SFD",
                    "country": "GBR"
                  },
                  "host_confirmed": true,
                  "uploaded_by": null,
                  "venue": null,
                  "gmt_dataset": "rt_default",
                  "url": "https://rowtimer.com/event/1734",
                  "revision": 3,
                  "updated_ms": 1804939600000,
                  "races": [
                    {
                      "id": 77,
                      "external_id": null,
                      "key": null,
                      "name": "Division 1",
                      "description": null,
                      "format": "processional",
                      "status": "published",
                      "category": null,
                      "round": null,
                      "distance": 4200,
                      "splits": [
                        {
                          "key": "split_a",
                          "name": "Bridge",
                          "distance": 2100
                        }
                      ],
                      "sequence": 1,
                      "scheduled_ms": null,
                      "lanes": null
                    }
                  ],
                  "crews": [
                    {
                      "id": 812,
                      "external_id": null,
                      "boat_number": 1,
                      "name": "Butterman",
                      "club": {
                        "id": 900,
                        "name": "Sandford Boat Club",
                        "code": "SFD",
                        "country": "GBR"
                      },
                      "category": "Op 8+",
                      "status": "entered",
                      "race": "Division 1",
                      "times": {
                        "start": {
                          "clock_ms": null,
                          "elapsed_ms": 0,
                          "ntt": false
                        },
                        "split_a": {
                          "clock_ms": null,
                          "elapsed_ms": 422400,
                          "ntt": false
                        },
                        "finish": {
                          "clock_ms": null,
                          "elapsed_ms": 871900,
                          "ntt": false
                        }
                      },
                      "adjustments": []
                    },
                    {
                      "id": 813,
                      "external_id": null,
                      "boat_number": 2,
                      "name": "Angel",
                      "club": {
                        "id": null,
                        "name": "Buford Abbey Rowing Club",
                        "code": null,
                        "country": null
                      },
                      "category": "MasC 8+",
                      "status": "dnf",
                      "race": "Division 1",
                      "times": {
                        "start": null,
                        "split_a": null,
                        "finish": null
                      },
                      "adjustments": []
                    }
                  ],
                  "warnings": [
                    {
                      "pointer": "/crews/1/club",
                      "detail": "No club in the directory matches \"Buford Abbey Rowing Club\", so it's kept as written. Find the club with GET /clubs and send its id to link it."
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "422": {
            "$ref": "#/components/responses/Invalid"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/events/{id}": {
      "get": {
        "operationId": "getEvent",
        "tags": [
          "Events"
        ],
        "summary": "An event's document",
        "description": "The event, its races and its crews, each crew with its times by position. The same\nshape `POST /events` and `PATCH /events/{id}` take. A head-race crew carries its\nrace, times and adjustments; a regatta crew races more than once, so those are null,\neach side-by-side race lists its `lanes`, and results are at `/events/{id}/results`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/EventId"
          },
          {
            "name": "crews",
            "in": "query",
            "description": "false leaves the crews out (null): the event and its races alone.",
            "schema": {
              "type": "boolean",
              "default": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The event's document.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventDocument"
                },
                "example": {
                  "id": 1734,
                  "external_id": "sandford-hor-2027",
                  "type": "head",
                  "name": "Sandford Head of the River 2027",
                  "short_name": "Sandford HoR",
                  "start_date": "2027-03-13",
                  "end_date": "2027-03-13",
                  "privacy": "public",
                  "official": true,
                  "host_club": {
                    "id": 900,
                    "name": "Sandford Boat Club",
                    "code": "SFD",
                    "country": "GBR"
                  },
                  "host_confirmed": true,
                  "uploaded_by": null,
                  "venue": null,
                  "gmt_dataset": "rt_default",
                  "url": "https://rowtimer.com/event/1734",
                  "revision": 212,
                  "updated_ms": 1804939600000,
                  "races": [
                    {
                      "id": 77,
                      "external_id": null,
                      "key": null,
                      "name": "Division 1",
                      "description": null,
                      "format": "processional",
                      "status": "published",
                      "category": null,
                      "round": null,
                      "distance": 4200,
                      "splits": [
                        {
                          "key": "split_a",
                          "name": "Bridge",
                          "distance": 2100
                        }
                      ],
                      "sequence": 1,
                      "scheduled_ms": null,
                      "lanes": null
                    }
                  ],
                  "crews": [
                    {
                      "id": 812,
                      "external_id": null,
                      "boat_number": 1,
                      "name": "Butterman",
                      "club": {
                        "id": 900,
                        "name": "Sandford Boat Club",
                        "code": "SFD",
                        "country": "GBR"
                      },
                      "category": "Op 8+",
                      "status": "entered",
                      "race": "Division 1",
                      "times": {
                        "start": {
                          "clock_ms": 1804936100530,
                          "elapsed_ms": 0,
                          "ntt": false
                        },
                        "split_a": {
                          "clock_ms": 1804936522930,
                          "elapsed_ms": 422400,
                          "ntt": false
                        },
                        "finish": {
                          "clock_ms": 1804936972430,
                          "elapsed_ms": 871900,
                          "ntt": false
                        }
                      },
                      "adjustments": [
                        {
                          "position": "finish",
                          "ms": 10000,
                          "kind": "penalty",
                          "reason": "Missed marshalling"
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "410": {
            "$ref": "#/components/responses/Gone"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "operationId": "updateEvent",
        "tags": [
          "Events"
        ],
        "summary": "Change an event, its races and crews, or their times",
        "description": "Send what changes, in the same shape. A field left out stays as it is, and `null`\nclears it. Races and crews you send are merged with those the event has: a race\nis matched by `id`, then `external_id`, then `name`; a crew by `id`, then\n`external_id`, then `boat_number`. One that matches nothing is added if it says\nenough (a race: a name; a crew: a category, and a name or a club), and is otherwise\na 422: a mistyped boat number is never a new crew. Nothing is deleted by being left\nout; delete with the DELETE operations.\n\nA live feed is a PATCH with a few crews' presses:\n`{\"crews\": [{\"boat_number\": 14, \"clock\": {\"finish\": 1804937140530}}]}`. Setting a\ntime is the same however often it's sent, so a retry is safe.\n\nA crew's `adjustments`, when sent, replace those it has; sending the same list again\nchanges nothing. A published race's adjustments can't change: send its `status` as\n`provisional` in the same request to reopen it, and `published` in a later one to\npublish it again.\n\nThe answer is the event, with the races and crews this request named as they now\nstand, and any warnings. The request applies whole or not at all.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/EventId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EventInput"
              },
              "example": {
                "crews": [
                  {
                    "boat_number": 14,
                    "clock": {
                      "start": 1804936100530
                    }
                  },
                  {
                    "boat_number": 9,
                    "clock": {
                      "finish": 1804937140530
                    }
                  },
                  {
                    "id": 812,
                    "adjustments": [
                      {
                        "position": "finish",
                        "ms": 10000,
                        "kind": "penalty",
                        "reason": "Missed marshalling"
                      }
                    ]
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The event, the races and crews the request named, and any warnings.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WriteResult"
                },
                "example": {
                  "id": 1734,
                  "external_id": "sandford-hor-2027",
                  "type": "head",
                  "name": "Sandford Head of the River 2027",
                  "short_name": null,
                  "start_date": "2027-03-13",
                  "end_date": "2027-03-13",
                  "privacy": "public",
                  "official": true,
                  "host_club": {
                    "id": 900,
                    "name": "Sandford Boat Club",
                    "code": "SFD",
                    "country": "GBR"
                  },
                  "host_confirmed": true,
                  "uploaded_by": null,
                  "venue": null,
                  "gmt_dataset": "rt_default",
                  "url": "https://rowtimer.com/event/1734",
                  "revision": 214,
                  "updated_ms": 1804939700000,
                  "races": [],
                  "crews": [
                    {
                      "id": 826,
                      "external_id": null,
                      "boat_number": 9,
                      "name": "Skinner",
                      "club": {
                        "id": 900,
                        "name": "Sandford Boat Club",
                        "code": "SFD",
                        "country": "GBR"
                      },
                      "category": "Op 8+",
                      "status": "entered",
                      "race": "Division 1",
                      "times": {
                        "start": {
                          "clock_ms": 1804936100530,
                          "elapsed_ms": 0,
                          "ntt": false
                        },
                        "split_a": null,
                        "finish": {
                          "clock_ms": 1804937140530,
                          "elapsed_ms": 1040000,
                          "ntt": false
                        }
                      },
                      "adjustments": []
                    }
                  ],
                  "warnings": []
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "410": {
            "$ref": "#/components/responses/Gone"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "422": {
            "$ref": "#/components/responses/Invalid"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/events/{id}/crews/{crew_id}": {
      "delete": {
        "operationId": "deleteCrew",
        "tags": [
          "Events"
        ],
        "summary": "Delete a crew entered by mistake",
        "description": "The crew goes, with its times and adjustments. Row Timer keeps a backup of the event first. A crew that scratched is better kept, with `\"status\": \"withdrawn\"`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/EventId"
          },
          {
            "name": "crew_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/events/{id}/races/{race_id}": {
      "delete": {
        "operationId": "deleteRace",
        "tags": [
          "Events"
        ],
        "summary": "Delete a race that has no crews",
        "description": "A race with crews in it, or times recorded at it, is refused (409); move or delete its crews first.",
        "parameters": [
          {
            "$ref": "#/components/parameters/EventId"
          },
          {
            "name": "race_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/events/{id}/results": {
      "get": {
        "operationId": "getEventResults",
        "tags": [
          "Events"
        ],
        "summary": "An event's results, as Row Timer works them out",
        "description": "Every crew's result in every race with one: its time with penalties, its time with\nthe masters handicap (what places are decided by), %GMT, and its place within its\ncategory in its race and across the event. A head race's results are there while it\nis racing, each row saying whether its race is `provisional` or `published`; a\nside-by-side race's once its order is `released`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/EventId"
          },
          {
            "name": "race_id",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "The category as the event spells it.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "club_id",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The results, in race order.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "event_id",
                    "data",
                    "next_cursor"
                  ],
                  "properties": {
                    "event_id": {
                      "type": "integer"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EventResult"
                      }
                    },
                    "next_cursor": {
                      "type": "null",
                      "description": "Always null; an event's results come in one answer."
                    }
                  }
                },
                "example": {
                  "event_id": 1734,
                  "data": [
                    {
                      "crew_id": 812,
                      "race_status": "published",
                      "race_id": 77,
                      "race": "Division 1",
                      "boat_number": 1,
                      "crew": "Butterman",
                      "club": {
                        "id": 900,
                        "name": "Sandford Boat Club",
                        "code": "SFD",
                        "country": "GBR"
                      },
                      "category": "Op 8+",
                      "category_key": "M.Open.8+",
                      "band": null,
                      "handicapped": false,
                      "status": "finished",
                      "time_ms": 881900,
                      "adjusted_ms": 881900,
                      "pct_gmt": 84.31,
                      "place": 1,
                      "field": 6,
                      "event_place": 1,
                      "event_field": 6,
                      "stage": null,
                      "stage_place": null,
                      "medal": null,
                      "margin_ms": null,
                      "verdict": null
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "410": {
            "$ref": "#/components/responses/Gone"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/clubs": {
      "get": {
        "operationId": "listClubs",
        "tags": [
          "Clubs"
        ],
        "summary": "The club directory",
        "description": "Every club, in order of id; or, with `updated_since`, the clubs changed at or after\nthat time, in the order they changed.\n",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "description": "Words in the club's name, code or town.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "country",
            "in": "query",
            "description": "An IOC country code, such as GBR.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "code",
            "in": "query",
            "description": "The club's code, such as SFD.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "description": "Clubs changed at or after this time (epoch ms).",
            "schema": {
              "type": "integer"
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of clubs.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "next_cursor"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Club"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": 900,
                      "name": "Sandford Boat Club",
                      "short_name": "Sandford BC",
                      "code": "SFD",
                      "country": "GBR",
                      "region": "England, Thames",
                      "city": "Sandford",
                      "website": "https://sandfordboatclub.net",
                      "founded": 1887,
                      "wikidata": null,
                      "location": {
                        "lat": 51.712,
                        "lon": -1.236,
                        "precision": "point"
                      },
                      "url": "https://rowtimer.com/clubs/GBR/SFD",
                      "blade": {
                        "url_20": "https://rowtimer.com/images/blades/gbr/20/SFD.png",
                        "url_40": "https://rowtimer.com/images/blades/gbr/40/SFD.png",
                        "url_160": "https://rowtimer.com/images/blades/gbr/160/SFD.png",
                        "url_450": "https://rowtimer.com/images/blades/gbr/450/SFD.png"
                      },
                      "updated_ms": 1804939600000
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/clubs/{id}": {
      "get": {
        "operationId": "getClub",
        "tags": [
          "Clubs"
        ],
        "summary": "One club",
        "parameters": [
          {
            "$ref": "#/components/parameters/ClubId"
          }
        ],
        "responses": {
          "200": {
            "description": "The club.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Club"
                },
                "example": {
                  "id": 900,
                  "name": "Sandford Boat Club",
                  "short_name": "Sandford BC",
                  "code": "SFD",
                  "country": "GBR",
                  "region": "England, Thames",
                  "city": "Sandford",
                  "website": "https://sandfordboatclub.net",
                  "founded": 1887,
                  "wikidata": null,
                  "location": {
                    "lat": 51.712,
                    "lon": -1.236,
                    "precision": "point"
                  },
                  "url": "https://rowtimer.com/clubs/GBR/SFD",
                  "blade": null,
                  "updated_ms": 1804939600000
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/clubs/{id}/results": {
      "get": {
        "operationId": "getClubResults",
        "tags": [
          "Clubs"
        ],
        "summary": "A club's crews' results, latest event first",
        "description": "The finished, published events the club had crews at, each with how every one of its\ncrews did. An event still being worked out is `pending`, with what is known so far;\nask again shortly.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/ClubId"
          },
          {
            "name": "season",
            "in": "query",
            "description": "A season by the year it starts: 2026 is 1 September 2026 to 31 August 2027.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "How many events to answer at once, from 1 to 30.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 30,
              "default": 10
            }
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of events, each with the club's results.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "next_cursor"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "event",
                          "hosted",
                          "pending",
                          "results"
                        ],
                        "properties": {
                          "event": {
                            "$ref": "#/components/schemas/Event"
                          },
                          "hosted": {
                            "type": "boolean",
                            "description": "Whether the club hosted the event."
                          },
                          "pending": {
                            "type": "boolean",
                            "description": "The results are still being worked out; ask again shortly."
                          },
                          "results": {
                            "type": "array",
                            "items": {
                              "$ref": "#/components/schemas/Result"
                            }
                          }
                        }
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "event": {
                        "id": 1734,
                        "external_id": null,
                        "type": "head",
                        "name": "Sandford Head of the River 2027",
                        "short_name": "Sandford HoR",
                        "start_date": "2027-03-13",
                        "end_date": "2027-03-13",
                        "privacy": "public",
                        "official": true,
                        "host_club": {
                          "id": 900,
                          "name": "Sandford Boat Club",
                          "code": "SFD",
                          "country": "GBR"
                        },
                        "host_confirmed": true,
                        "uploaded_by": null,
                        "venue": null,
                        "gmt_dataset": "rt_default",
                        "url": "https://rowtimer.com/event/1734",
                        "revision": 212,
                        "updated_ms": 1804939600000
                      },
                      "hosted": true,
                      "pending": false,
                      "results": [
                        {
                          "race_id": null,
                          "race": "Division 2",
                          "boat_number": 12,
                          "crew": "Thatcher",
                          "club": {
                            "id": 900,
                            "name": "Sandford Boat Club",
                            "code": "SFD",
                            "country": "GBR"
                          },
                          "category": "WJ16 4x+",
                          "category_key": "W.J16.4x+",
                          "band": null,
                          "handicapped": false,
                          "status": "finished",
                          "time_ms": 1088300,
                          "adjusted_ms": 1088300,
                          "pct_gmt": 71.2,
                          "place": 2,
                          "field": 9,
                          "event_place": 2,
                          "event_field": 9,
                          "stage": null,
                          "stage_place": null,
                          "medal": null
                        }
                      ]
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/results": {
      "get": {
        "operationId": "compareResults",
        "tags": [
          "Results"
        ],
        "summary": "One category's results across events",
        "description": "Results in one category from finished, published events, latest first, to compare\ncrews that raced in different events. A row gives the club, the time and the place,\nbut not the crew's name: the event's own results say who it was. Compare\n`adjusted_ms` over the same `distance`, or `pct_gmt` across distances. `pending`\nsays how many events are still being worked out; ask again shortly for them.\n",
        "parameters": [
          {
            "name": "category",
            "in": "query",
            "required": true,
            "description": "The category in any spelling an event might use (\"WJ16 4x\", \"W J16 4x+\"), or as a `category_key` (\"W.J16.4x-\").",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "club_id",
            "in": "query",
            "description": "Only these clubs: up to 20 ids, separated by commas.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "distance",
            "in": "query",
            "description": "Only races of this length in metres.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of results.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "category_key",
                    "category",
                    "data",
                    "next_cursor",
                    "pending"
                  ],
                  "properties": {
                    "category_key": {
                      "type": "string"
                    },
                    "category": {
                      "type": "string",
                      "description": "The category's usual spelling."
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "allOf": [
                          {
                            "type": "object",
                            "required": [
                              "event",
                              "distance"
                            ],
                            "properties": {
                              "event": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "name",
                                  "date",
                                  "official",
                                  "url"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "integer"
                                  },
                                  "name": {
                                    "type": "string"
                                  },
                                  "date": {
                                    "type": "string",
                                    "format": "date",
                                    "description": "The event's last day."
                                  },
                                  "official": {
                                    "type": "boolean"
                                  },
                                  "url": {
                                    "type": "string",
                                    "format": "uri"
                                  }
                                }
                              },
                              "distance": {
                                "type": [
                                  "integer",
                                  "null"
                                ],
                                "description": "The race's length in metres."
                              }
                            }
                          },
                          {
                            "$ref": "#/components/schemas/ResultCore"
                          }
                        ]
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "pending": {
                      "type": "integer",
                      "description": "How many events' results are still being worked out."
                    }
                  }
                },
                "example": {
                  "category_key": "W.J16.4x+",
                  "category": "W J16 4x+",
                  "data": [
                    {
                      "event": {
                        "id": 1734,
                        "name": "Sandford Head of the River 2027",
                        "date": "2027-03-13",
                        "official": true,
                        "url": "https://rowtimer.com/event/1734"
                      },
                      "distance": 4200,
                      "race_id": 78,
                      "race": "Division 2",
                      "boat_number": 12,
                      "club": {
                        "id": 900,
                        "name": "Sandford Boat Club",
                        "code": "SFD",
                        "country": "GBR"
                      },
                      "category": "WJ16 4x+",
                      "category_key": "W.J16.4x+",
                      "band": null,
                      "handicapped": false,
                      "status": "finished",
                      "time_ms": 1088300,
                      "adjusted_ms": 1088300,
                      "pct_gmt": 71.2,
                      "place": 2,
                      "field": 9,
                      "event_place": 2,
                      "event_field": 9,
                      "stage": null,
                      "stage_place": null,
                      "medal": null
                    }
                  ],
                  "next_cursor": null,
                  "pending": 0
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "rtk_<selector>_<secret>",
        "description": "Your API key, as `Authorization: Bearer rtk_…`."
      }
    },
    "headers": {
      "RateLimitLimit": {
        "description": "Requests of this kind this key may make in the current 10-minute window.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimitRemaining": {
        "description": "How many of them are left.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimitReset": {
        "description": "Seconds until the window resets.",
        "schema": {
          "type": "integer"
        }
      },
      "RetryAfter": {
        "description": "Seconds to wait before trying again.",
        "schema": {
          "type": "integer"
        }
      }
    },
    "parameters": {
      "EventId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "The event's id.",
        "schema": {
          "type": "integer"
        }
      },
      "ClubId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "The club's id.",
        "schema": {
          "type": "integer"
        }
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "description": "How many to answer at once, from 1 to 200.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 200,
          "default": 50
        }
      },
      "Cursor": {
        "name": "cursor",
        "in": "query",
        "description": "The `next_cursor` from the page before, for the page after it. Keep the other parameters as they were.",
        "schema": {
          "type": "string"
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "A query parameter is wrong, or isn't one this operation takes.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "https://rowtimer.com/developers#error-bad-request",
              "title": "The request can't be read",
              "status": 400,
              "detail": "Some of the query parameters aren't right.",
              "request_id": "7d0ffc197170f93a",
              "errors": [
                {
                  "parameter": "from",
                  "detail": "from is a date, YYYY-MM-DD."
                }
              ]
            }
          }
        }
      },
      "NotFound": {
        "description": "There is nothing here, or nothing this key may see.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "https://rowtimer.com/developers#error-not-found",
              "title": "There is nothing here",
              "or nothing this key can see": null,
              "status": 404,
              "request_id": "7d0ffc197170f93a"
            }
          }
        }
      },
      "Forbidden": {
        "description": "This key may not do that. A key that only reads can't write, and a key can change only events its account runs or uploaded.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "https://rowtimer.com/developers#error-forbidden",
              "title": "This key may not do that",
              "status": 403,
              "detail": "This key can read this event but not change it. Its host club, or whoever uploaded it, can.",
              "request_id": "7d0ffc197170f93a"
            }
          }
        }
      },
      "Conflict": {
        "description": "The request clashes with the event: two crews share the boat number it gave, two\nraces would share a name, an external_id is another's, or another change to the\nevent is still being made (try again shortly). Nothing was changed.\n",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "https://rowtimer.com/developers#error-conflict",
              "title": "This clashes with what is already here",
              "status": 409,
              "detail": "The document is ambiguous against this event. Nothing was changed.",
              "request_id": "7d0ffc197170f93a",
              "errors": [
                {
                  "pointer": "/crews/0/boat_number",
                  "code": "ambiguous",
                  "detail": "2 crews in this event have boat 14. Say which by its id."
                }
              ]
            }
          }
        }
      },
      "Invalid": {
        "description": "The document has problems, each listed with a JSON pointer to it. Nothing was changed.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "https://rowtimer.com/developers#error-validation",
              "title": "The request is not valid",
              "status": 422,
              "detail": "The document has 2 problems. Nothing was changed.",
              "request_id": "7d0ffc197170f93a",
              "errors": [
                {
                  "pointer": "/crews/0",
                  "code": "not_found",
                  "detail": "No crew in this event has boat 14. A new crew needs a category, and a name or a club."
                },
                {
                  "pointer": "/crews/1/clock/finish",
                  "code": "seconds",
                  "detail": "1804937140 looks like seconds; send milliseconds (1804937140000)."
                }
              ]
            }
          }
        }
      },
      "UnsupportedMediaType": {
        "description": "Send the body as JSON, with Content-Type: application/json.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "Gone": {
        "description": "The event was deleted. Anything you kept of it is no longer on Row Timer.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "https://rowtimer.com/developers#error-gone",
              "title": "This was deleted",
              "status": 410,
              "detail": "This event was deleted.",
              "request_id": "7d0ffc197170f93a"
            }
          }
        }
      },
      "Unauthenticated": {
        "description": "No key, or a key that is wrong, revoked or expired.",
        "headers": {
          "WWW-Authenticate": {
            "schema": {
              "type": "string"
            },
            "description": "Bearer realm=\"Row Timer API\""
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "https://rowtimer.com/developers#error-unauthenticated",
              "title": "A valid API key is needed",
              "status": 401,
              "detail": "Send your key as Authorization: Bearer rtk_…",
              "request_id": "7d0ffc197170f93a"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Too many requests; wait as long as `Retry-After` says.",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "https://rowtimer.com/developers#error-rate-limited",
              "title": "Too many requests",
              "status": 429,
              "request_id": "7d0ffc197170f93a"
            }
          }
        }
      }
    },
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "An RFC 9457 problem. `type` links to its explanation on the developers page.",
        "required": [
          "type",
          "title",
          "status",
          "request_id"
        ],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "request_id": {
            "type": "string",
            "description": "Quote this to us if you ask about a failure."
          },
          "errors": {
            "type": "array",
            "description": "Each problem in the request, all at once. One in the body has a `pointer`; one in the query string has a `parameter`.",
            "items": {
              "type": "object",
              "required": [
                "detail"
              ],
              "properties": {
                "pointer": {
                  "type": "string",
                  "description": "A JSON pointer to the problem in the body, such as /crews/3/category."
                },
                "parameter": {
                  "type": "string",
                  "description": "The query parameter that is wrong, such as from."
                },
                "code": {
                  "type": "string"
                },
                "detail": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "Index": {
        "type": "object",
        "required": [
          "name",
          "version",
          "api_revision",
          "docs",
          "reference",
          "openapi"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "api_revision": {
            "type": "string",
            "description": "The date of the latest additive change to v1."
          },
          "docs": {
            "type": "string",
            "format": "uri"
          },
          "reference": {
            "type": "string",
            "format": "uri"
          },
          "openapi": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "Me": {
        "type": "object",
        "required": [
          "account",
          "key"
        ],
        "properties": {
          "account": {
            "type": "object",
            "required": [
              "id",
              "username",
              "name",
              "kind",
              "club",
              "may_write"
            ],
            "properties": {
              "id": {
                "type": "integer"
              },
              "username": {
                "type": "string"
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "kind": {
                "type": "string",
                "enum": [
                  "developer",
                  "organiser",
                  "admin"
                ]
              },
              "club": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/ClubRef"
                  }
                ]
              },
              "may_write": {
                "type": "boolean",
                "description": "Whether this account may hold write keys."
              }
            }
          },
          "key": {
            "type": "object",
            "required": [
              "id",
              "name",
              "scopes",
              "expires_ms"
            ],
            "properties": {
              "id": {
                "type": "integer"
              },
              "name": {
                "type": "string"
              },
              "scopes": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "read",
                    "write"
                  ]
                }
              },
              "expires_ms": {
                "type": [
                  "integer",
                  "null"
                ]
              }
            }
          }
        }
      },
      "ClubRef": {
        "type": "object",
        "description": "A club as an event or a crew names it. `id` is null for a club entered by name alone, which isn't in the directory.",
        "required": [
          "id",
          "name",
          "code",
          "country"
        ],
        "properties": {
          "id": {
            "type": [
              "integer",
              "null"
            ]
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "code": {
            "type": [
              "string",
              "null"
            ]
          },
          "country": {
            "type": [
              "string",
              "null"
            ],
            "description": "The IOC country code",
            "such as GBR.": null
          }
        }
      },
      "Event": {
        "type": "object",
        "required": [
          "id",
          "external_id",
          "type",
          "name",
          "short_name",
          "start_date",
          "end_date",
          "privacy",
          "official",
          "host_club",
          "host_confirmed",
          "uploaded_by",
          "venue",
          "gmt_dataset",
          "url",
          "revision",
          "updated_ms"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "external_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Your own id for the event",
            "if you gave one.": null
          },
          "type": {
            "type": "string",
            "enum": [
              "head",
              "regatta"
            ]
          },
          "name": {
            "type": "string"
          },
          "short_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "start_date": {
            "type": "string",
            "format": "date"
          },
          "end_date": {
            "type": "string",
            "format": "date",
            "description": "The last day; the same as start_date for a one-day event."
          },
          "privacy": {
            "type": "string",
            "enum": [
              "public",
              "club",
              "private"
            ]
          },
          "official": {
            "type": "boolean",
            "description": "Whether the organiser runs its official timing on Row Timer; false means the times are someone's own record."
          },
          "host_club": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ClubRef"
              }
            ]
          },
          "host_confirmed": {
            "type": "boolean",
            "description": "Whether the host club has confirmed it. An upload by someone outside the host club is unconfirmed until then, and is never published."
          },
          "uploaded_by": {
            "type": [
              "string",
              "null"
            ],
            "description": "Who put it on Row Timer, while it is unconfirmed; otherwise null."
          },
          "venue": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "type": "object",
                "required": [
                  "name",
                  "lat",
                  "lon"
                ],
                "properties": {
                  "name": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "lat": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "lon": {
                    "type": [
                      "number",
                      "null"
                    ]
                  }
                }
              }
            ]
          },
          "gmt_dataset": {
            "type": "string",
            "description": "The gold medal times %GMT is worked out against."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The event's page on Row Timer."
          },
          "revision": {
            "type": "integer",
            "description": "Goes up by one or more with every change to the event."
          },
          "updated_ms": {
            "type": [
              "integer",
              "null"
            ],
            "description": "When the event last changed."
          }
        }
      },
      "EventDocument": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Event"
          },
          {
            "type": "object",
            "required": [
              "races",
              "crews"
            ],
            "properties": {
              "races": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Race"
                }
              },
              "crews": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/Crew"
                    }
                  }
                ]
              }
            }
          }
        ]
      },
      "Race": {
        "type": "object",
        "description": "A race. A head race's divisions are races, rowed one crew after another (`processional`).",
        "required": [
          "id",
          "external_id",
          "key",
          "name",
          "description",
          "format",
          "status",
          "category",
          "round",
          "distance",
          "splits",
          "sequence",
          "scheduled_ms",
          "lanes"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "external_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "key": {
            "type": [
              "string",
              "null"
            ],
            "description": "A regatta's short name for the race, such as FA."
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "format": {
            "type": "string",
            "enum": [
              "processional",
              "side_by_side"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "provisional",
              "released",
              "published",
              "cancelled"
            ],
            "description": "provisional: racing, or finished and open to change; released: a side-by-side race's order is decided, not yet published; published: the official result."
          },
          "category": {
            "type": [
              "string",
              "null"
            ],
            "description": "A side-by-side race's category."
          },
          "round": {
            "type": [
              "string",
              "null"
            ],
            "description": "A side-by-side race's round: time_trial, heat, repechage, quarterfinal, semifinal or final."
          },
          "distance": {
            "type": [
              "integer",
              "null"
            ],
            "description": "The course's length in metres."
          },
          "splits": {
            "type": "array",
            "description": "The timing points between start and finish, in course order.",
            "items": {
              "type": "object",
              "required": [
                "key",
                "name",
                "distance"
              ],
              "properties": {
                "key": {
                  "type": "string",
                  "description": "The position's name in a crew's times",
                  "split_a to split_j.": null
                },
                "name": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "distance": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "description": "Metres from the start."
                }
              }
            }
          },
          "sequence": {
            "type": "integer",
            "description": "The running order."
          },
          "scheduled_ms": {
            "type": [
              "integer",
              "null"
            ]
          },
          "lanes": {
            "description": "A side-by-side race's draw; null for a processional race.",
            "oneOf": [
              {
                "type": "null"
              },
              {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "lane",
                    "crew_id",
                    "status"
                  ],
                  "properties": {
                    "lane": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "crew_id": {
                      "type": "integer"
                    },
                    "status": {
                      "type": "string"
                    }
                  }
                }
              }
            ]
          }
        }
      },
      "Time": {
        "type": "object",
        "description": "A time at one position. A crew timed only by elapsed times has no real start, so its clock_ms are null.",
        "required": [
          "clock_ms",
          "elapsed_ms",
          "ntt"
        ],
        "properties": {
          "clock_ms": {
            "type": [
              "integer",
              "null"
            ],
            "description": "The instant",
            "in epoch ms.": null
          },
          "elapsed_ms": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Milliseconds since the crew's start; 0 at the start."
          },
          "ntt": {
            "type": "boolean",
            "description": "Recorded as no time taken."
          }
        }
      },
      "Crew": {
        "type": "object",
        "required": [
          "id",
          "external_id",
          "boat_number",
          "name",
          "club",
          "category",
          "status",
          "race",
          "times",
          "adjustments"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "external_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "boat_number": {
            "type": [
              "integer",
              "null"
            ]
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "The crew's name as entered, such as a stroke's surname."
          },
          "club": {
            "$ref": "#/components/schemas/ClubRef"
          },
          "category": {
            "type": "string",
            "description": "The category as the event spells it."
          },
          "status": {
            "type": "string",
            "enum": [
              "entered",
              "dns",
              "dnf",
              "dsq",
              "excluded",
              "withdrawn"
            ]
          },
          "race": {
            "type": [
              "string",
              "null"
            ],
            "description": "The name of the race a head-race crew is in; null at a regatta."
          },
          "times": {
            "description": "A head-race crew's times, by position (start, split_a…, finish), each null until recorded; null at a regatta.",
            "oneOf": [
              {
                "type": "null"
              },
              {
                "type": "object",
                "additionalProperties": {
                  "oneOf": [
                    {
                      "type": "null"
                    },
                    {
                      "$ref": "#/components/schemas/Time"
                    }
                  ]
                }
              }
            ]
          },
          "adjustments": {
            "description": "Penalties and corrections; null at a regatta.",
            "oneOf": [
              {
                "type": "null"
              },
              {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "position",
                    "ms",
                    "kind",
                    "reason"
                  ],
                  "properties": {
                    "position": {
                      "type": "string"
                    },
                    "ms": {
                      "type": "integer",
                      "description": "Added to the crew's time from this position on."
                    },
                    "kind": {
                      "type": "string",
                      "enum": [
                        "penalty",
                        "correction"
                      ]
                    },
                    "reason": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            ]
          }
        }
      },
      "ResultCore": {
        "type": "object",
        "required": [
          "race_id",
          "race",
          "boat_number",
          "club",
          "category",
          "category_key",
          "band",
          "handicapped",
          "status",
          "time_ms",
          "adjusted_ms",
          "pct_gmt",
          "place",
          "field",
          "event_place",
          "event_field",
          "stage",
          "stage_place",
          "medal"
        ],
        "properties": {
          "race_id": {
            "type": [
              "integer",
              "null"
            ]
          },
          "race": {
            "type": [
              "string",
              "null"
            ]
          },
          "boat_number": {
            "type": [
              "integer",
              "null"
            ]
          },
          "club": {
            "$ref": "#/components/schemas/ClubRef"
          },
          "category": {
            "type": "string",
            "description": "The category as the event spells it."
          },
          "category_key": {
            "type": [
              "string",
              "null"
            ],
            "description": "The category as compared across events, such as W.J16.4x-; null when it can't be told."
          },
          "band": {
            "type": [
              "string",
              "null"
            ],
            "description": "A masters crew's band, A to I."
          },
          "handicapped": {
            "type": "boolean",
            "description": "Whether the masters handicap applies."
          },
          "status": {
            "type": "string",
            "enum": [
              "finished",
              "dnf",
              "dns",
              "dsq",
              "ntt",
              "none"
            ],
            "description": "none: no result yet (started, not finished); ntt: no time taken."
          },
          "time_ms": {
            "type": [
              "integer",
              "null"
            ],
            "description": "The finish less the start",
            "with penalties and corrections.": null
          },
          "adjusted_ms": {
            "type": [
              "integer",
              "null"
            ],
            "description": "time_ms with the masters handicap; what places are decided by."
          },
          "pct_gmt": {
            "type": [
              "number",
              "null"
            ],
            "description": "Speed as a percentage of the gold medal time for the category and distance."
          },
          "place": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Among its category in its race; tied times share a place."
          },
          "field": {
            "type": [
              "integer",
              "null"
            ],
            "description": "How many crews of its category were in its race."
          },
          "event_place": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Among its category over the same distance across the event."
          },
          "event_field": {
            "type": [
              "integer",
              "null"
            ]
          },
          "stage": {
            "type": [
              "string",
              "null"
            ],
            "description": "A side-by-side race's round and key, such as final FA."
          },
          "stage_place": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Its place in a side-by-side race."
          },
          "medal": {
            "type": [
              "integer",
              "null"
            ],
            "description": "1, 2 or 3 in a category's A final."
          }
        }
      },
      "Result": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ResultCore"
          },
          {
            "type": "object",
            "required": [
              "crew"
            ],
            "properties": {
              "crew": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The crew's name as entered."
              }
            }
          }
        ]
      },
      "EventResult": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Result"
          },
          {
            "type": "object",
            "required": [
              "crew_id",
              "race_status",
              "margin_ms",
              "verdict"
            ],
            "properties": {
              "crew_id": {
                "type": "integer",
                "description": "The crew's id in the event's document."
              },
              "race_status": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "provisional",
                  "released",
                  "published",
                  "cancelled",
                  null
                ]
              },
              "margin_ms": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "In a side-by-side race, how far behind the crew ahead."
              },
              "verdict": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "In a side-by-side race, the margin as rowing says it: a canvas, 2 L, easily."
              }
            }
          }
        ]
      },
      "Club": {
        "type": "object",
        "required": [
          "id",
          "name",
          "short_name",
          "code",
          "country",
          "region",
          "city",
          "website",
          "founded",
          "wikidata",
          "location",
          "url",
          "blade",
          "updated_ms"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string",
            "description": "The club's full name."
          },
          "short_name": {
            "type": "string",
            "description": "The name results show."
          },
          "code": {
            "type": [
              "string",
              "null"
            ],
            "description": "Its code, unique within its country, such as SFD."
          },
          "country": {
            "type": "string",
            "description": "The IOC country code",
            "such as GBR.": null
          },
          "region": {
            "type": [
              "string",
              "null"
            ]
          },
          "city": {
            "type": [
              "string",
              "null"
            ]
          },
          "website": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "founded": {
            "type": [
              "integer",
              "null"
            ]
          },
          "wikidata": {
            "type": [
              "string",
              "null"
            ],
            "description": "Its Wikidata item, such as Q98805134."
          },
          "location": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "type": "object",
                "required": [
                  "lat",
                  "lon",
                  "precision"
                ],
                "properties": {
                  "lat": {
                    "type": "number"
                  },
                  "lon": {
                    "type": "number"
                  },
                  "precision": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "enum": [
                      "point",
                      "address",
                      "postcode",
                      "town",
                      null
                    ]
                  }
                }
              }
            ]
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Its page on Row Timer; null for a club with no code."
          },
          "blade": {
            "description": "Its blade at 20, 40, 160 and 450 pixels high, or null when it has none. Off rowtimer.com, the 160 and 450 carry the Row Timer mark.",
            "oneOf": [
              {
                "type": "null"
              },
              {
                "type": "object",
                "required": [
                  "url_20",
                  "url_40",
                  "url_160",
                  "url_450"
                ],
                "properties": {
                  "url_20": {
                    "type": "string",
                    "format": "uri"
                  },
                  "url_40": {
                    "type": "string",
                    "format": "uri"
                  },
                  "url_160": {
                    "type": "string",
                    "format": "uri"
                  },
                  "url_450": {
                    "type": "string",
                    "format": "uri"
                  }
                }
              }
            ]
          },
          "updated_ms": {
            "type": [
              "integer",
              "null"
            ]
          }
        }
      },
      "WriteResult": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventDocument"
          },
          {
            "type": "object",
            "required": [
              "warnings"
            ],
            "properties": {
              "warnings": {
                "type": "array",
                "description": "What was done other than as sent, such as a club kept as written because the directory doesn't have it.",
                "items": {
                  "type": "object",
                  "required": [
                    "pointer",
                    "detail"
                  ],
                  "properties": {
                    "pointer": {
                      "type": "string"
                    },
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        ]
      },
      "ClubInput": {
        "description": "A club: {\"country\": \"GBR\", \"code\": \"SFD\"}, {\"id\": 245}, its name, or a ClubRef as GET answers it.",
        "oneOf": [
          {
            "type": "string"
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "country": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "code": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        ]
      },
      "TimesInput": {
        "type": "object",
        "description": "Positions (start, split_a…split_j, finish) to times. A value is a number, \"ntt\" for no time taken, or null to clear the position.",
        "propertyNames": {
          "enum": [
            "start",
            "split_a",
            "split_b",
            "split_c",
            "split_d",
            "split_e",
            "split_f",
            "split_g",
            "split_h",
            "split_i",
            "split_j",
            "finish"
          ]
        }
      },
      "EventInput": {
        "type": "object",
        "description": "An event, or the changes to one, in the shape GET answers. Read-only members (id,\nurl, revision, updated_ms, host_confirmed, uploaded_by, and a race's key, format,\ncategory, round, sequence, scheduled_ms and lanes) are passed over, so what GET\nanswered can be edited and sent back. Any other member it doesn't know is a 422.\n",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100,
            "description": "Needed for a new event."
          },
          "short_name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 15
          },
          "start_date": {
            "type": "string",
            "format": "date",
            "description": "Needed for a new event."
          },
          "end_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "type": {
            "type": "string",
            "enum": [
              "head",
              "regatta"
            ],
            "default": "head",
            "description": "A new event's type; it can't change. A regatta takes its crews (entries) alone: its races are drawn on Row Timer."
          },
          "privacy": {
            "type": "string",
            "enum": [
              "public",
              "club",
              "private"
            ],
            "default": "public"
          },
          "official": {
            "type": "boolean",
            "description": "Whether the organiser runs its official timing on Row Timer. An event its host hasn't confirmed is never official."
          },
          "host_club": {
            "$ref": "#/components/schemas/ClubInput"
          },
          "external_id": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^[A-Za-z0-9._:/-]{1,64}$",
            "description": "Your own id for the event, unique among its host club's events."
          },
          "gmt_dataset": {
            "type": "string"
          },
          "venue": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "type": "object",
                "properties": {
                  "name": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "lat": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "lon": {
                    "type": [
                      "number",
                      "null"
                    ]
                  }
                }
              }
            ]
          },
          "races": {
            "type": "array",
            "maxItems": 200,
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "integer"
                },
                "external_id": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "name": {
                  "type": "string",
                  "maxLength": 128,
                  "description": "Unique within the event: crews name their race by it."
                },
                "description": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "distance": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "description": "Metres."
                },
                "splits": {
                  "type": "array",
                  "maxItems": 10,
                  "description": "The timing points between start and finish, in course order. The list sent replaces the race's.",
                  "items": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "distance": {
                        "type": [
                          "integer",
                          "null"
                        ]
                      }
                    }
                  }
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "provisional",
                    "published"
                  ]
                }
              }
            }
          },
          "crews": {
            "type": "array",
            "maxItems": 2000,
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "integer"
                },
                "external_id": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "boat_number": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "minimum": 1
                },
                "name": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "club": {
                  "oneOf": [
                    {
                      "type": "null"
                    },
                    {
                      "$ref": "#/components/schemas/ClubInput"
                    }
                  ]
                },
                "category": {
                  "type": "string",
                  "description": "The category as the event spells it, such as \"MasC 8+\"."
                },
                "race": {
                  "type": [
                    "string",
                    "integer"
                  ],
                  "description": "The crew's race",
                  "by its name or id. A head race with one race needs none.": null
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "entered",
                    "dns",
                    "dnf",
                    "dsq",
                    "excluded",
                    "withdrawn"
                  ]
                },
                "clock": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/TimesInput"
                    }
                  ],
                  "description": "Instants, in epoch ms: {\"finish\": 1804937140530}. A number below 10¹¹ looks like seconds and is refused."
                },
                "elapsed": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/TimesInput"
                    }
                  ],
                  "description": "Time since the crew's start, in ms or as text: {\"finish\": \"14:31.9\"}. With no start, one is made up at the start of the event's day, and its clock times read as null."
                },
                "times": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/TimesInput"
                    }
                  ],
                  "description": "The read shape, {\"finish\": {\"clock_ms\": …, \"elapsed_ms\": …, \"ntt\": …}}: clock_ms is used when it's there, else elapsed_ms. Give each position once, in one of clock, elapsed and times."
                },
                "adjustments": {
                  "type": [
                    "array",
                    "null"
                  ],
                  "description": "Penalties and corrections; the list sent replaces the crew's, and the same list again changes nothing. Each needs a time at its position.",
                  "items": {
                    "type": "object",
                    "required": [
                      "position",
                      "ms",
                      "reason"
                    ],
                    "properties": {
                      "position": {
                        "type": "string",
                        "enum": [
                          "start",
                          "split_a",
                          "split_b",
                          "split_c",
                          "split_d",
                          "split_e",
                          "split_f",
                          "split_g",
                          "split_h",
                          "split_i",
                          "split_j",
                          "finish"
                        ]
                      },
                      "ms": {
                        "type": "integer",
                        "description": "Added to the crew's time from this position on; a penalty is positive."
                      },
                      "kind": {
                        "type": "string",
                        "enum": [
                          "penalty",
                          "correction"
                        ],
                        "default": "penalty"
                      },
                      "reason": {
                        "type": "string",
                        "maxLength": 255
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
