Heartbeat API · v1
Every FiveM server and resource, over HTTP
The same data behind this site, as JSON: 34,951 servers, 1,254,808 distinct resources, and the adoption figures ranking them. Built for Discord bots, server dashboards and anyone deciding which script to ship.
Quickstart
Every endpoint lives under https://heartbeat.re/api/v1 and needs a key. Here is the smallest useful call.
curl -H "Authorization: Bearer $HEARTBEAT_KEY" \
https://heartbeat.re/api/v1/statsAuthentication
Send your key as a bearer token. An X-API-Key header works identically if that suits your client better. A ?api_key= query parameter is accepted as a last resort for clients that cannot set headers, avoid it where you can, since query strings land in access logs and browser history.
Authorization: Bearer hb_live_eyJ2IjoxLCJpZCI6…Rate limits
Free keys allow 60 requests a minute. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset; a 429 adds Retry-After. Counting is per-instance and best-effort rather than globally exact, treat the published number as the contract, not the enforcement.
Response shape
Results are always under data. Lists add meta for paging. Every response carries a snapshot block telling you how fresh the figures are and whether the instance is ingesting live or serving a frozen copy, poll-driven consumers should read it rather than assume.
{
"data": [ … ],
"meta": { "total": 36958, "limit": 50, "offset": 0, "hasMore": true },
"snapshot": { "live": false, "capturedAt": "2026-08-12T19:14:02.000Z" }
}Endpoints
Fifteen endpoints covering raw data, derived analysis and alerting. All of them accept CORS from any origin.
/stats
Network totals: players, servers, capacity, crawl coverage, and 24-hour change. The cheapest call, and the one most bots want.
curl -H "Authorization: Bearer $HEARTBEAT_KEY" \
https://heartbeat.re/api/v1/statsResponse
{
"data": {
"players": 186308,
"servers": 34951,
"populatedServers": 8599,
"slotsFilledPercent": 5.93,
"distinctResources": 1254808,
"coverage": { "serversCrawled": 46798, "serversTotal": 34951, "percent": 36.2 },
"change": { "playersPercent": 0.7, "serversPercent": 0.1 }
}
}/stats/history
Network totals over time, one point per census (roughly every five minutes).
| Parameter | Type | Description |
|---|---|---|
| hours | integer | Window to return, 1–168.(default 24) |
curl -H "Authorization: Bearer $HEARTBEAT_KEY" \
"https://heartbeat.re/api/v1/stats/history?hours=48"/servers
List and filter servers. Combine filters freely, this is how you answer questions like 'the busiest German roleplay servers running more than 100 resources'.
| Parameter | Type | Description |
|---|---|---|
| limit | integer | Rows to return, 1–200.(default 50) |
| offset | integer | Rows to skip, for paging.(default 0) |
| sort | string | players · peak · capacity · upvotes · resources(default players) |
| q | string | Match server name or owner. |
| country | string | ISO-3166 alpha-2, e.g. DE. |
| game | string | gta5 or rdr3. |
| tag | string | Exact tag match, e.g. roleplay. |
| minPlayers | integer | Only servers at or above this player count. |
| crawledOnly | boolean | Only servers whose resources are indexed. |
curl -H "Authorization: Bearer $HEARTBEAT_KEY" \
"https://heartbeat.re/api/v1/servers?country=DE&tag=roleplay&minPlayers=50&limit=10"Response
{
"data": [
{
"joinId": "j4r9zmk",
"name": "KROWN",
"players": 1846,
"maxPlayers": 2048,
"country": "TH",
"countryName": "Thailand",
"tags": ["roleplay", "economy"],
"resourceCount": 218,
"connectUrl": "https://cfx.re/join/j4r9zmk"
}
],
"meta": { "total": 412, "limit": 10, "offset": 0, "hasMore": true }
}/servers/{joinId}
A single server by its Cfx join id, the code in a cfx.re/join link.
| Parameter | Type | Description |
|---|---|---|
| history | boolean | Include 48 hours of player counts. |
curl -H "Authorization: Bearer $HEARTBEAT_KEY" \
"https://heartbeat.re/api/v1/servers/j4r9zmk?history=true"/servers/{joinId}/resources
Every resource a server loads, each annotated with how widely it is used across the network, so you can tell its bespoke code from the community standards.
curl -H "Authorization: Bearer $HEARTBEAT_KEY" \
https://heartbeat.re/api/v1/servers/j4r9zmk/resourcesResponse
{
"data": {
"joinId": "j4r9zmk",
"count": 218,
"resources": [
{ "name": "ox_lib", "servers": 3299, "playerReach": 108736, "playersPerServer": 33 },
{ "name": "sd-mdt", "servers": 12, "playerReach": 840, "playersPerServer": 70 }
]
}
}/resources
The resource leaderboard. Ranked by player reach, total live players across every server running it, rather than raw installs, because a script on 400 empty servers reaches nobody.
| Parameter | Type | Description |
|---|---|---|
| limit | integer | Rows to return, 1–200.(default 50) |
| offset | integer | Rows to skip, for paging.(default 0) |
| sort | string | reach · servers · name(default reach) |
| q | string | Match the resource name. |
curl -H "Authorization: Bearer $HEARTBEAT_KEY" \
"https://heartbeat.re/api/v1/resources?sort=reach&limit=5"Response
{
"data": [
{ "name": "hardcap", "servers": 7123, "playerReach": 134810, "populatedServers": 4957 },
{ "name": "oxmysql", "servers": 6902, "playerReach": 129440, "populatedServers": 4801 }
],
"meta": { "total": 417858, "limit": 5, "offset": 0, "hasMore": true }
}/resources/{name}
One resource, with optional weekly adoption history. URL-encode names containing slashes or spaces.
| Parameter | Type | Description |
|---|---|---|
| history | boolean | Include 7 days of adoption points. |
curl -H "Authorization: Bearer $HEARTBEAT_KEY" \
"https://heartbeat.re/api/v1/resources/ox_lib?history=true"/resources/{name}/servers
Servers known to run a resource, busiest first. Useful for 'who actually uses this script, and how big are they?'
| Parameter | Type | Description |
|---|---|---|
| limit | integer | Servers to return, 1–200.(default 50) |
curl -H "Authorization: Bearer $HEARTBEAT_KEY" \
"https://heartbeat.re/api/v1/resources/ox_lib/servers?limit=20"/regions
Players and servers grouped by the region each server advertises, with each country's share of the network.
| Parameter | Type | Description |
|---|---|---|
| limit | integer | Countries to return.(default 50) |
curl -H "Authorization: Bearer $HEARTBEAT_KEY" \
"https://heartbeat.re/api/v1/regions?limit=10"/search
One call across servers and resources, built for autocomplete and Discord slash commands.
| Parameter | Type | Description |
|---|---|---|
| q | string | At least 2 characters. Required. |
| limit | integer | Per collection, 1–50.(default 10) |
curl -H "Authorization: Bearer $HEARTBEAT_KEY" \
"https://heartbeat.re/api/v1/search?q=police"/frameworks
Framework market share across crawled servers, ESX, QBCore, Qbox, vRP and standalone, with players-per-server. Pass resources=true for each framework's own top-resource leaderboard, which is a very different list from the global one.
| Parameter | Type | Description |
|---|---|---|
| resources | boolean | Include each framework's top resources. |
| resourceLimit | integer | Resources per framework, 1-50.(default 10) |
curl -H "Authorization: Bearer $HEARTBEAT_KEY" "https://heartbeat.re/api/v1/frameworks?resources=true"Response
{
"data": [
{ "id": "esx", "label": "ESX", "servers": 4897, "players": 46797, "playersPerServer": 9.6 },
{ "id": "vrp", "label": "vRP", "servers": 1049, "players": 25959, "playersPerServer": 24.7 }
]
}/resources/momentum
Rising and falling resources. Ranked by change in share of crawled servers, not raw install count, while the crawler is still sweeping, absolute counts climb for everything at once, so a raw-count ranking would measure our coverage rather than actual adoption.
| Parameter | Type | Description |
|---|---|---|
| hours | integer | Window, 1-168.(default 24) |
| limit | integer | Rows per direction.(default 20) |
curl -H "Authorization: Bearer $HEARTBEAT_KEY" "https://heartbeat.re/api/v1/resources/momentum?hours=48"/servers/{joinId}/similar
Servers with the most overlapping resource sets (Jaccard similarity), plus the resources those peers run that this server doesn't, the practical version of 'what is everyone like me installing?'
| Parameter | Type | Description |
|---|---|---|
| limit | integer | Peers to return, 1-25.(default 8) |
curl -H "Authorization: Bearer $HEARTBEAT_KEY" https://heartbeat.re/api/v1/servers/j4r9zmk/similar/watches
Register a Discord webhook alert on a server or resource. Only https Discord webhook URLs are accepted, and alerts fire on threshold crossings with a 15-minute cooldown. Requires an instance running the ingest worker, a read-only snapshot refuses rather than accepting a watch it can never deliver.
curl -X POST https://heartbeat.re/api/v1/watches -H "Authorization: Bearer $HEARTBEAT_KEY" -H "Content-Type: application/json" -d '{
"kind": "server",
"target": "j4r9zmk",
"condition": "below",
"threshold": 100,
"webhookUrl": "https://discord.com/api/webhooks/…"
}'/keys
Create a key programmatically. No authentication required, limited to 5 per hour per IP. The key is returned once and never again.
curl -X POST https://heartbeat.re/api/v1/keys \
-H "Content-Type: application/json" \
-d '{"name":"my-discord-bot"}'Response
{
"data": {
"key": "hb_live_eyJ2IjoxLCJpZCI6…",
"keyId": "a1b2c3d4e5f6",
"tier": "free",
"rateLimitPerMinute": 60,
"notice": "Store this key now, it is not recoverable and is shown only once."
}
}Errors
Failures return a matching HTTP status and a stable error.code, branch on the code, not the message, which may be reworded.
| Status | Code | Meaning |
|---|---|---|
| 400 | bad_request | A parameter is missing or malformed. |
| 401 | missing_key | No key was sent. |
| 401 | invalid_key | The key failed signature verification. |
| 403 | revoked_key | The key was valid but has been revoked. |
| 404 | not_found | No server or resource by that identifier. |
| 429 | rate_limited | Too many requests. See Retry-After. |
| 500 | server_error | Something broke on our side. |
{
"error": {
"code": "rate_limited",
"message": "Rate limit of 60 requests/minute exceeded.",
"docs": "https://heartbeat.re/docs#rate_limited"
}
}What the numbers do and don't mean
- Player counts are self-reported. They come from each server's own listing. Nothing here independently verifies them.
- Resource coverage is partial and growing. The bulk server list omits resource data, so it is gathered one server at a time, most-populated first.
/statsreports exact coverage, read it before treating an install count as complete. - Resource rankings are already aggregates. A resource's
serversandplayerReachcover the whole crawled network, but/resources/{name}/serverslists only the busiest installs. - Check the snapshot block. When
snapshot.liveis false the instance is serving a frozen copy, andcapturedAttells you from when.
Data comes from the public Cfx.re server list. Heartbeat is not affiliated with Cfx.re or Rockstar Games.