API Reference
Base URL: https://live.deadlock-api.com/api
All requests must include the X-Api-Key header. Missing, malformed, and mismatched keys all
return the same 401 Unauthorized body — the rejection is intentionally indistinguishable to
prevent existence-oracle attacks.
All error responses follow RFC 7807:
{
"type": "https://live.deadlock-api.com/errors/api_key_unauthorized",
"title": "Unauthorized",
"status": 401,
"detail": "API key is missing or invalid."
}60–90 s spectate delay for public games
Valve's spectate API delivers public game data 60–90 seconds behind real game time. This is inherent to the upstream data source — our parse-to-delivery pipeline adds under 500 ms on top.
Subscribe to a Match
POST /api/v1/subscribe
Probe the live match, allocate a slot, and mint a scoped Centrifugo connection token.
Bills one match unit per unique (API key, match_id) pair. Retries on the same pair
return the original token for free.
Authentication: X-Api-Key header
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
match_id | integer | yes | Deadlock match identifier |
curl -X POST https://live.deadlock-api.com/api/v1/subscribe \
-H "X-Api-Key: dlk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"match_id": 28850808}'Success response — 200 OK:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"channel": "match:28850808",
"expires_at": "<ISO-8601 timestamp, 4 hours after subscribe>"
}The token is an HS256-signed Centrifugo connection JWT carrying a pre-authorised
subs claim for match:{match_id}. The accompanying url is the Centrifugo
WebSocket endpoint your client connects to.
Errors:
| Status | type | Condition |
|---|---|---|
400 | — | match_id outside the supported i64 range |
401 | api_key_unauthorized | X-Api-Key missing, malformed, or mismatched |
403 | api_key_forbidden | Customer is shadow-banned or account is deleted |
409 | subscription_conflict | Another customer already holds this match |
410 | match_completed | Match has already ended |
502 | valve_unavailable | Upstream broadcast feed is currently unavailable |
503 | probes_at_capacity | Global capacity breaker is full; retry shortly |
Get Match
GET /api/v1/matches/{match_id}
Returns the subscription status for a match.
Authentication: X-Api-Key header
| Path param | Type | Description |
|---|---|---|
match_id | integer | Match identifier |
curl https://live.deadlock-api.com/api/v1/matches/28850808 \
-H "X-Api-Key: dlk_live_YOUR_KEY"Success response — 200 OK:
{
"match_id": 28850808,
"status": "live",
"channel": "match:28850808",
"subscribed_at": "<ISO-8601 timestamp>"
}status is one of pending, live, completed, failed, or unknown. The unknown value is returned by the backend for legacy or transient subscription rows whose status cannot be classified — treat it as a non-terminal "still processing" signal and re-poll.
Errors:
| Status | type | Condition |
|---|---|---|
401 | api_key_unauthorized | X-Api-Key missing, malformed, or mismatched |
404 | subscription_not_found | No subscription exists for this match and API key |
Cancel Subscription
DELETE /api/v1/matches/{match_id}
Cancels a still-pending subscription. Not supported once event processing has started for the match. Refund rules apply per the Terms of Service.
Authentication: X-Api-Key header
curl -X DELETE https://live.deadlock-api.com/api/v1/matches/28850808 \
-H "X-Api-Key: dlk_live_YOUR_KEY"Success response — 204 No Content
Errors:
| Status | type | Condition |
|---|---|---|
401 | api_key_unauthorized | X-Api-Key missing, malformed, or mismatched |
404 | subscription_not_found | No subscription for this match |
409 | subscription_active | Event processing has already started; cancellation is not possible |
Refresh Token
POST /api/v1/matches/{match_id}/token
Mints a replacement Centrifugo connection token for an active subscription. Not billed. Use this before the current token expires.
Authentication: X-Api-Key header
curl -X POST https://live.deadlock-api.com/api/v1/matches/28850808/token \
-H "X-Api-Key: dlk_live_YOUR_KEY"Success response — 200 OK:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_at": "<ISO-8601 timestamp, 4 hours after refresh>"
}The previously issued token remains valid until its own exp, so an in-flight Centrifugo
connection survives the swap. Rotate by calling client.setToken(newToken) on the
existing centrifuge-js client (or the equivalent on other Centrifugo SDKs).
Errors:
| Status | type | Condition |
|---|---|---|
401 | api_key_unauthorized | X-Api-Key missing, malformed, or mismatched |
404 | subscription_not_found | No active subscription for this match |
Account Usage
GET /api/v1/account/usage
Paginated audit log of all subscribe events and their billing status.
Authentication: X-Api-Key header
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number (1-indexed) |
limit | integer | 20 | Results per page (max 100) |
status | string | — | Filter by status: pending, live, completed, failed |
period | string | — | ISO 8601 date range, e.g. <start-date>/<end-date> |
curl "https://live.deadlock-api.com/api/v1/account/usage?page=1&limit=20" \
-H "X-Api-Key: dlk_live_YOUR_KEY"Success response — 200 OK:
{
"total": 42,
"page": 1,
"limit": 20,
"items": [
{
"match_id": 28850808,
"status": "completed",
"subscribed_at": "<ISO-8601 timestamp>",
"completed_at": "<ISO-8601 timestamp>"
}
]
}Errors:
| Status | type | Condition |
|---|---|---|
401 | api_key_unauthorized | X-Api-Key missing, malformed, or mismatched |
422 | invalid_period | period is not a valid ISO 8601 date range |
Export Account Data
POST /api/v1/account/export
Initiates a GDPR Article 15 data export. Returns a 24-hour pre-signed download URL containing a JSON dump of your account row and all subscription audit records.
Authentication: X-Api-Key header
curl -X POST https://live.deadlock-api.com/api/v1/account/export \
-H "X-Api-Key: dlk_live_YOUR_KEY"Success response — 202 Accepted:
{
"download_url": "/api/v1/account/export/eyJhbGci...",
"expires_in": 86400
}Resolve download_url against the base URL, then GET it — no X-Api-Key required, the
token in the path is the credential. The token expires after 24 hours.
Errors:
| Status | type | Condition |
|---|---|---|
401 | api_key_unauthorized | X-Api-Key missing, malformed, or mismatched |
Delete Account
POST /api/v1/account/delete
Initiates GDPR Article 17 account deletion. Soft-deletes the account, anonymises your email
address, and schedules audit-log purge after the legally required retention window.
Subsequent customer-facing API calls return 403.
Authentication: X-Api-Key header
curl -X POST https://live.deadlock-api.com/api/v1/account/delete \
-H "X-Api-Key: dlk_live_YOUR_KEY"Success response — 200 OK:
{
"deleted_at": "<ISO-8601 timestamp>"
}This timestamp is your receipt for the statutory thirty-day window.
Errors:
| Status | type | Condition |
|---|---|---|
401 | api_key_unauthorized | X-Api-Key missing, malformed, or mismatched |
Public Match Token
POST /api/v2/public/subscribe
Free, anonymous Centrifugo connection token for the live match the rotation loop has currently pinned. No authentication, no billing. Intended for evaluation, demo integrations, and read-only spectator clients. The same match is shared across every caller until the loop rotates.
The response shape mirrors the paid POST /api/v1/subscribe, with one addition: match_id —
public callers do not pick the match, so the server tells them which one was pinned.
Authentication: None required (IP-rate-limited)
curl -X POST https://live.deadlock-api.com/api/v2/public/subscribe \
-H "Content-Type: application/json"Success response — 200 OK:
{
"match_id": 28850808,
"url": "wss://broker.deadlock-api.com/connection/websocket",
"channel": "match:28850808",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_in": 3600
}The token is an HS256-signed Centrifugo connection JWT carrying a pre-authorised
subs claim for match:{match_id}. expires_in is the lifetime in seconds, matching
the paid path so client SDKs share their refresh logic.
Errors:
| Status | type | Condition |
|---|---|---|
429 | — | Per-IP rate limit exceeded; honour Retry-After |
500 | jwt_mint_failed | JWT minting failed server-side |
503 | no_public_match | Rotation loop has not yet pinned a live match — retry shortly |