Skip to content

Race Day

Record aid station reports

Record runner In, Out, Drop and station sweep reports for an authorized event's aid station log, as an outside net-control system takes them. Up to 500 per call; each carries your own clientEntryId, so a retry records nothing twice (duplicate comes back instead). Name each station by its external code (set by the organizer in Endurance HQ), exact name or course number. recordedAt is when it happened, not when you sent it, and must be inside the event window; a batch with any out-of-range time, unknown station or bad bib is refused whole with HTTP 422 listing the bad entries, and nothing in it is saved. Requires race-day:write and timing or course access on the event. Send an Idempotency-Key header.

Method

POST

Path

/v1/events/{eventId}/station-log

Required scope

race-day:write

Request

curl -X POST "https://api.endurancehq.app/v1/events/{eventId}/station-log" \
  -H "Authorization: Bearer $EHQ_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"

Path parameters

eventIdstring, required

JSON body schema

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "entries": {
      "minItems": 1,
      "maxItems": 500,
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "clientEntryId": {
            "type": "string",
            "minLength": 8,
            "maxLength": 80,
            "description": "Your id for this report, unique within the event. Send the same id again and the report is not recorded twice."
          },
          "kind": {
            "type": "string",
            "enum": [
              "in",
              "out",
              "drop",
              "sweep"
            ]
          },
          "bib": {
            "description": "The runner's bib. Required except for a sweep.",
            "type": "string",
            "pattern": "^[A-Za-z0-9-]{1,8}$"
          },
          "recordedAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
            "description": "When the runner came in, left or dropped (or the sweep cleared), as an ISO 8601 instant with offset. Not when you sent it. Must be within the event window: not in the future, not older than 72 hours before now except during and after the race, when anything from the day before the race's first day on is accepted."
          },
          "station": {
            "type": "object",
            "properties": {
              "code": {
                "description": "The station's external code as the organizer set it in Endurance HQ (e.g. AS3). Preferred: it survives renames and tells two stations with one name apart.",
                "type": "string",
                "minLength": 1,
                "maxLength": 40
              },
              "name": {
                "description": "The station's exact name. A name two stations share needs its mile, '(mile 54.8)', or '#5' after it.",
                "type": "string",
                "minLength": 1,
                "maxLength": 120
              },
              "number": {
                "description": "1-based position in course order.",
                "type": "integer",
                "minimum": 1,
                "maximum": 500
              }
            },
            "additionalProperties": false
          },
          "note": {
            "type": "string",
            "maxLength": 300
          },
          "dropReason": {
            "description": "Drops only. A medical drop opens a medical encounter for the medical team.",
            "type": "string",
            "enum": [
              "injury",
              "exhaustion",
              "time_cutoff",
              "personal",
              "medical",
              "other"
            ]
          },
          "transportNeeded": {
            "description": "Drops only: the runner needs a ride out.",
            "type": "boolean"
          }
        },
        "required": [
          "clientEntryId",
          "kind",
          "recordedAt",
          "station"
        ],
        "additionalProperties": false
      }
    }
  },
  "required": [
    "entries"
  ],
  "additionalProperties": false
}

Response

Success status: 200

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "data": {
      "type": "object",
      "properties": {
        "accepted": {
          "type": "integer",
          "minimum": -9007199254740991,
          "maximum": 9007199254740991
        },
        "duplicate": {
          "type": "integer",
          "minimum": -9007199254740991,
          "maximum": 9007199254740991
        },
        "rejected": {
          "type": "integer",
          "minimum": -9007199254740991,
          "maximum": 9007199254740991
        },
        "entries": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "clientEntryId": {
                "type": "string"
              },
              "status": {
                "type": "string",
                "enum": [
                  "accepted",
                  "duplicate",
                  "rejected"
                ]
              },
              "entryId": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "kind": {
                "type": "string",
                "enum": [
                  "in",
                  "out",
                  "drop",
                  "sweep"
                ]
              },
              "bib": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "station": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "code": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "name": {
                        "type": "string"
                      },
                      "number": {
                        "type": "integer",
                        "minimum": -9007199254740991,
                        "maximum": 9007199254740991
                      },
                      "miles": {
                        "type": [
                          "number",
                          "null"
                        ]
                      }
                    },
                    "required": [
                      "id",
                      "code",
                      "name",
                      "number",
                      "miles"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "runner": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "registrationId": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      }
                    },
                    "required": [
                      "registrationId",
                      "name"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "message": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "clientEntryId",
              "status",
              "entryId",
              "kind",
              "bib",
              "station",
              "runner",
              "message"
            ],
            "additionalProperties": false
          }
        }
      },
      "required": [
        "accepted",
        "duplicate",
        "rejected",
        "entries"
      ],
      "additionalProperties": false
    }
  },
  "required": [
    "data"
  ],
  "additionalProperties": false
}

Other surfaces

CLI: ehq race-day station-log record --event <event_id> --input-file <entries.json>

MCP tool: ehq_station_log_record