Overview
The Custom Timeline Events API lets your own integration mark a named moment on a replay's timeline, for example a BedWars plugin marking the Final Death of a match. The marker is stored cloud-side and rendered by the in-browser viewer as a labelled dot on the timeline scrub bar, alongside the recorder-derived markers (kills, explosions, bookmarks).
Custom markers do not touch the recorded .replaycore archive: the recorder event format is frozen, so a marker is a cloud-side annotation on the replay, never a new recorder event kind. You can add a marker during an active recording (by server and current tick) or after the fact (by replay id).
This is part of the developer API and is authenticated with a customer API key. The viewer fetches a replay's custom markers when it loads, so markers appear in the panel viewer but not on the unauthenticated public share page.
Authentication
The write endpoint is authenticated with a customer API key (an rc_live_ bearer credential minted in the panel under Settings, then Developer API). The key must carry the replays:write scope. Present it as a bearer token; the key resolves to its tenant, and every marker is scoped to that tenant, so a key can never write to another tenant's replays. See the API keys article for minting and scopes.
Authorization: Bearer rc_live_<your-key>POST /v1/api/timeline-events
Marks one custom event on a replay's timeline. Supply exactly one of replayId or serverId. The other fields are: tick (required, the timeline position in recorder ticks starting at 0, must be 0 or greater), label (required, the text shown on the marker, 1 to 120 characters), category (optional grouping label, at most 60 characters), colour (optional #rrggbb hex tint for the dot), icon (optional built-in token: swords, skull, shield, pickaxe, blast, flask, user-plus, bookmark, flag, sparkles, hammer, star, trophy, bed or diamond), and actor (optional free-form attribution such as a player name, at most 80 characters). Icon values are closed tokens, never URLs or CSS names.
By replay id (after the fact): the replay must exist for the tenant, or the request returns 404 REPLAY_NOT_FOUND. By server id (during an active recording): the cloud resolves that server's in-progress recording and pins the marker to it; an unknown server returns 404 REPLAY_NOT_FOUND, and a known server with nothing recording returns 404 NO_ACTIVE_RECORDING. A successful call returns 201 Created with the stored marker.
{
"id": "9f1c0e2a-2b6d-4f1a-9c3e-7a5b1d2e4f60",
"replayId": "3b8f6d10-1c4e-4a2b-8f7d-2e9a0c5b4a31",
"tick": 6042,
"label": "Final Death",
"category": "elimination",
"colour": "#ff0044",
"icon": "trophy",
"actor": "RedTeam",
"createdAt": "2026-06-13T14:32:10Z"
}Example: a BedWars Final Death (during the match)
A BedWars plugin runs on the server ReplayCore is recording. When a team's bed is gone and its last player dies, that elimination is the dramatic moment a caster wants to jump straight to. While the match is recording, the plugin knows its own ReplayCore server id (the UUID returned by server registration) and the current recording tick, so it marks the moment by serverId and tick and lets the cloud resolve the in-progress recording.
Always fire this asynchronously on your plugin's HTTP executor; never block the server thread.
curl -X POST https://api.replaycore.com/v1/api/timeline-events \
-H 'Authorization: Bearer rc_live_<key>' \
-H 'Content-Type: application/json' \
-d '{
"serverId": "7a5b1d2e-4f60-4c3e-9c3e-2b6d4f1a9f1c",
"tick": 6042,
"label": "Final Death: Red eliminated",
"category": "elimination",
"colour": "#ff0044",
"icon": "trophy",
"actor": "RedTeam"
}'Example: marking after the fact (by replay id)
If your integration only learns the replay id later (for example from listing replays via GET /v1/api/replays), it can mark the same moment after the fact by replayId and tick. Either way, when a caster opens that replay in the viewer they see a red Final Death: Red eliminated marker on the timeline and can jump straight to it.
curl -X POST https://api.replaycore.com/v1/api/timeline-events \
-H 'Authorization: Bearer rc_live_<key>' \
-H 'Content-Type: application/json' \
-d '{
"replayId": "3b8f6d10-1c4e-4a2b-8f7d-2e9a0c5b4a31",
"tick": 6042,
"label": "Final Death: Red eliminated",
"category": "elimination",
"colour": "#ff0044",
"icon": "trophy",
"actor": "RedTeam"
}'Errors and limits
Validation errors return 400 with a machine-readable code: INVALID_TARGET (not exactly one of replayId or serverId), INVALID_REPLAY_ID or INVALID_SERVER_ID (not a UUID), INVALID_TICK (negative), INVALID_LABEL (empty or over 120 characters), INVALID_CATEGORY (over 60 characters), INVALID_ACTOR (over 80 characters), INVALID_COLOUR (not a #rrggbb hex value), and INVALID_ICON (not a supported icon token). Auth failures return 401 UNAUTHENTICATED or 401 INVALID_API_KEY, and a key without replays:write returns 403 INSUFFICIENT_SCOPE.
A replay holds at most 500 custom markers; beyond that the call returns 409 TOO_MANY_MARKERS. Markers are removed automatically when their replay is deleted. The endpoint shares the per-tenant developer-API rate limit.