Minecraft server status API: fields, caching, and evidence windows
Treat each response as bounded evidence, branch on the canonical evidenceCode, and turn expired or ambiguous results into Unknown.
- Last verified
- Evidence cutoff
Direct answer: evidenceCode is the canonical machine-readable meaning of a server observation. verdict is the closed display class derived from that code. Keep observedAt and validUntil with the result, and after validUntil show Unknown until fresh evidence arrives. Latency, player counts, MOTD text, and unknownReason do not override that rule.
This page describes the public MinecraftStatus API as reviewed on 2026-07-21. The field tables below follow the same response shapes served by the API; when a contract changes, the live API protocol sheet is the current reference.
Public endpoint register and limits
The API protocol sheet and the response examples below use the same endpoint register.
Use the interactive checker when a person needs the same server observation with interpretation rather than raw JSON.
| Methods | Path | Output | Limit |
|---|---|---|---|
GET, OPTIONS | /api/status/java/{address} | minecraftstatus-server-status/java-unversioned | 20 requests per 60 seconds per client |
GET, OPTIONS | /api/status/bedrock/{address} | minecraftstatus-server-status/bedrock-unversioned | 20 requests per 60 seconds per client |
GET, OPTIONS | /api/services | minecraftstatus-service-view/v2 | 60 requests per 60 seconds per client |
GET | /api/health | minecraftstatus-health/v2 | Unlimited |
GET | /api/v1/community/status | minecraftstatus-community-status/v1 | Unlimited |
GET, OPTIONS | /api/v1/status/java?address=... | minecraftstatus-observation/v1 | 30 requests per 60 seconds per client |
GET, OPTIONS | /api/v1/status/bedrock?address=... | minecraftstatus-observation/v1 | 30 requests per 60 seconds per client |
POST, OPTIONS | /api/v1/status/batch | minecraftstatus-batch/v1 | 30 requests per 60 seconds per client |
GET, OPTIONS | /api/v1/jobs/{jobId} | minecraftstatus-job/v1 | 30 requests per 60 seconds per client |
GET, OPTIONS | /api/v1/services | minecraftstatus-services/v1 | 30 requests per 60 seconds per client |
GET, OPTIONS | /api/v1/incidents | minecraftstatus-incidents/v1 | 30 requests per 60 seconds per client |
GET, OPTIONS | /api/v1/incidents/{incidentId} | minecraftstatus-incident/v1 | 30 requests per 60 seconds per client |
GET, OPTIONS | /api/v1/history/{targetId} | minecraftstatus-history/v1 | 30 requests per 60 seconds per client |
GET, OPTIONS | /api/v1/versions | minecraftstatus-versions/v1 | 30 requests per 60 seconds per client |
GET, OPTIONS | /api/v1/badges/{targetId}.svg | image/svg+xml | 30 requests per 60 seconds per client |
GET | /api/v1/openapi.json | openapi-3.1.0 | Unlimited |
Unversioned Java and Bedrock routes consume one shared 20 requests per 60 seconds server-probe budget. Every anonymous versioned v1 route shares a 30 requests per 60 seconds request budget plus 5,000 target-observation units per day. Registered developer keys receive 120 requests per 60 seconds and 100,000 target-observation units per day; the directory service key receives 1,200 requests per 60 seconds and 1,000,000 units per day. Batch units are charged per input target; job polling is request-limited but never consumes another target unit. A server-route 429 means no outbound check ran for that rejected request; it does not mean the target server is Offline. /api/services, /api/v1/services, /api/v1/incidents, /api/v1/history, /api/v1/versions, /api/health, and the community heartbeat read local state on the request path rather than probing an upstream service. Badges and the OpenAPI document are public cacheable artifacts with bounded freshness and ETags. Bearer keys are server-side credentials; the directory key is never embedded in browser JavaScript.
Server evidence fields
Every successful Java or Bedrock server response includes these common fields:
| Field | Contract |
|---|---|
verdict | online, offline, or unknown; derived from evidenceCode |
evidenceCode | Canonical closed transport meaning; branch integrations on this field |
host, port | Parsed public request identity, not a private resolved address or connect target |
latency | Completed observation time in milliseconds, or null when not applicable |
observedAt | RFC 3339 timestamp for the observation |
validUntil | RFC 3339 evidence boundary; after it passes, the effective state is Unknown |
method | Network action that produced the observation |
unknownReason | Deprecated human compatibility copy, present only for Unknown and derived from evidenceCode |
The closed server evidence mapping is:
evidenceCode | verdict |
|---|---|
status_response | online |
connection_refused | offline |
timeout | unknown |
closed_without_status | unknown |
connection_reset | unknown |
dns_unresolved | unknown |
outbound_capacity | unknown |
invalid_frame | unknown |
invalid_payload | unknown |
rate_limited | unknown |
internal_error | unknown |
Only connection_refused from an admitted target means Offline. Silence, timeouts, resets, malformed data, DNS ambiguity, capacity limits, and internal failures remain Unknown. unknownReason is display copy, not a second taxonomy.
Java response shape
Java adds:
| Field | Contract |
|---|---|
version.name, version.protocol | Advertised Java version name and protocol number |
players.online, players.max, players.sample | Advertised counts and bounded sample array |
motd.raw, motd.clean, motd.html | Raw, plain, and sanitized presentation forms |
favicon | Sanitized PNG data URL or null |
{
"verdict": "online",
"evidenceCode": "status_response",
"host": "java.example",
"port": 25565,
"latency": 42,
"observedAt": "2026-07-21T12:00:00.000Z",
"validUntil": "2026-07-21T12:00:30.000Z",
"method": "java-status-handshake",
"version": { "name": "1.21.8", "protocol": 772 },
"players": { "online": 12, "max": 100, "sample": [] },
"motd": { "raw": "Contract fixture", "clean": "Contract fixture", "html": "Contract fixture" },
"favicon": null
}The version, player, MOTD, and favicon values are server advertisements. Read the Java status response guide before presenting them as more than that.
Bedrock response shape
Bedrock has the same common evidence fields, version object, player object, and MOTD forms. It adds gamemode and serverId; it does not include the Java favicon field.
{
"verdict": "online",
"evidenceCode": "status_response",
"host": "bedrock.example",
"port": 19132,
"latency": 42,
"observedAt": "2026-07-21T12:00:00.000Z",
"validUntil": "2026-07-21T12:00:30.000Z",
"method": "bedrock-raknet-unconnected-ping",
"version": { "name": "1.21.100", "protocol": 776 },
"players": { "online": 12, "max": 100, "sample": [] },
"motd": { "raw": "Contract fixture", "clean": "Contract fixture", "html": "Contract fixture" },
"gamemode": "Survival",
"serverId": "123456789"
}Versioned v1 response shapes
The versioned routes return one canonical observation envelope for Java and Bedrock. target preserves edition, normalized address, port, and port mode; freshness describes whether the evidence window is current. A valid target that cannot be reached still returns HTTP 200 with an unknown verdict and its evidence code. Invalid input, exhausted capacity, and unavailable API infrastructure use the documented request-error envelope instead.
Java and Bedrock v1 observation
{
"contract": "minecraftstatus-observation/v1",
"evidenceCode": "status_response",
"freshness": "fresh",
"freshnessReason": "current",
"latencyMs": 42,
"method": "java-status-handshake",
"motd": {
"sanitizedParts": [
{
"text": "Canonical v1 fixture"
}
],
"text": "Canonical v1 fixture"
},
"observationId": "00000000-0000-4000-8000-000000000011",
"observedAt": "2026-07-21T12:00:00.000Z",
"players": {
"max": 100,
"online": 12,
"source": "server-reported"
},
"serverNow": "2026-07-21T12:00:00.000Z",
"target": {
"address": "java.example",
"edition": "java",
"port": 25565,
"portMode": "implicit",
"targetId": "79a2c750-929c-52df-a74e-cfc42148fec9"
},
"validUntil": "2026-07-21T12:03:00.000Z",
"vantage": "api-contract-v1-fixture",
"verdict": "online",
"version": {
"protocol": 772,
"reportedName": "1.21.8"
}
}{
"contract": "minecraftstatus-observation/v1",
"evidenceCode": "status_response",
"freshness": "fresh",
"freshnessReason": "current",
"latencyMs": 42,
"method": "bedrock-raknet-unconnected-ping",
"motd": {
"sanitizedParts": [
{
"text": "Canonical v1 fixture"
}
],
"text": "Canonical v1 fixture"
},
"observationId": "00000000-0000-4000-8000-000000000012",
"observedAt": "2026-07-21T12:00:00.000Z",
"players": {
"max": 100,
"online": 12,
"source": "server-reported"
},
"serverNow": "2026-07-21T12:00:00.000Z",
"target": {
"address": "bedrock.example",
"edition": "bedrock",
"port": 19132,
"portMode": "port",
"targetId": "a7f0e98b-1351-5679-b257-38d70536bdc6"
},
"validUntil": "2026-07-21T12:03:00.000Z",
"vantage": "api-contract-v1-fixture",
"verdict": "online",
"version": {
"protocol": 776,
"reportedName": "1.21.100"
}
}Batch and pending job response shapes
The batch endpoint accepts at most 50 Java or Bedrock targets. It preserves the input order and emits an independent observation, pending receipt, or error for each target; one invalid address does not discard the rest. A pending receipt contains a short-lived jobId, pollUrl, and expiresAt. Polling is scoped to the original caller and does not create another probe or spend another target-observation unit.
Batch result
{
"contract": "minecraftstatus-batch/v1",
"results": [
{
"input": {
"address": "java.example",
"edition": "java"
},
"kind": "observation",
"observation": {
"contract": "minecraftstatus-observation/v1",
"evidenceCode": "status_response",
"freshness": "fresh",
"freshnessReason": "current",
"latencyMs": 42,
"method": "java-status-handshake",
"motd": {
"sanitizedParts": [
{
"text": "Canonical v1 fixture"
}
],
"text": "Canonical v1 fixture"
},
"observationId": "00000000-0000-4000-8000-000000000011",
"observedAt": "2026-07-21T12:00:00.000Z",
"players": {
"max": 100,
"online": 12,
"source": "server-reported"
},
"serverNow": "2026-07-21T12:00:00.000Z",
"target": {
"address": "java.example",
"edition": "java",
"port": 25565,
"portMode": "implicit",
"targetId": "79a2c750-929c-52df-a74e-cfc42148fec9"
},
"validUntil": "2026-07-21T12:03:00.000Z",
"vantage": "api-contract-v1-fixture",
"verdict": "online",
"version": {
"protocol": 772,
"reportedName": "1.21.8"
}
},
"target": {
"address": "java.example",
"edition": "java",
"port": 25565,
"portMode": "implicit",
"targetId": "79a2c750-929c-52df-a74e-cfc42148fec9"
}
},
{
"input": {
"address": "bedrock.example",
"edition": "bedrock"
},
"kind": "observation",
"observation": {
"contract": "minecraftstatus-observation/v1",
"evidenceCode": "status_response",
"freshness": "fresh",
"freshnessReason": "current",
"latencyMs": 42,
"method": "bedrock-raknet-unconnected-ping",
"motd": {
"sanitizedParts": [
{
"text": "Canonical v1 fixture"
}
],
"text": "Canonical v1 fixture"
},
"observationId": "00000000-0000-4000-8000-000000000012",
"observedAt": "2026-07-21T12:00:00.000Z",
"players": {
"max": 100,
"online": 12,
"source": "server-reported"
},
"serverNow": "2026-07-21T12:00:00.000Z",
"target": {
"address": "bedrock.example",
"edition": "bedrock",
"port": 19132,
"portMode": "port",
"targetId": "a7f0e98b-1351-5679-b257-38d70536bdc6"
},
"validUntil": "2026-07-21T12:03:00.000Z",
"vantage": "api-contract-v1-fixture",
"verdict": "online",
"version": {
"protocol": 776,
"reportedName": "1.21.100"
}
},
"target": {
"address": "bedrock.example",
"edition": "bedrock",
"port": 19132,
"portMode": "port",
"targetId": "a7f0e98b-1351-5679-b257-38d70536bdc6"
}
}
]
}Pending job
{
"contract": "minecraftstatus-job/v1",
"createdAt": "2026-07-21T12:00:00.000Z",
"error": null,
"expiresAt": "2026-07-21T12:00:20.000Z",
"jobId": "00000000-0000-4000-8000-000000000021",
"observation": null,
"pollUrl": "https://minecraftstatus.com/api/v1/jobs/00000000-0000-4000-8000-000000000021",
"state": "pending",
"target": {
"address": "java.example",
"edition": "java",
"port": 25565,
"portMode": "implicit",
"targetId": "79a2c750-929c-52df-a74e-cfc42148fec9"
}
}Completed job
{
"contract": "minecraftstatus-job/v1",
"createdAt": "2026-07-21T12:00:00.000Z",
"error": null,
"expiresAt": "2026-07-21T12:00:20.000Z",
"jobId": "00000000-0000-4000-8000-000000000022",
"observation": {
"contract": "minecraftstatus-observation/v1",
"evidenceCode": "status_response",
"freshness": "fresh",
"freshnessReason": "current",
"latencyMs": 42,
"method": "java-status-handshake",
"motd": {
"sanitizedParts": [
{
"text": "Canonical v1 fixture"
}
],
"text": "Canonical v1 fixture"
},
"observationId": "00000000-0000-4000-8000-000000000011",
"observedAt": "2026-07-21T12:00:00.000Z",
"players": {
"max": 100,
"online": 12,
"source": "server-reported"
},
"serverNow": "2026-07-21T12:00:00.000Z",
"target": {
"address": "java.example",
"edition": "java",
"port": 25565,
"portMode": "implicit",
"targetId": "79a2c750-929c-52df-a74e-cfc42148fec9"
},
"validUntil": "2026-07-21T12:03:00.000Z",
"vantage": "api-contract-v1-fixture",
"verdict": "online",
"version": {
"protocol": 772,
"reportedName": "1.21.8"
}
},
"pollUrl": "https://minecraftstatus.com/api/v1/jobs/00000000-0000-4000-8000-000000000022",
"state": "succeeded",
"target": {
"address": "java.example",
"edition": "java",
"port": 25565,
"portMode": "implicit",
"targetId": "79a2c750-929c-52df-a74e-cfc42148fec9"
}
}Caching and validUntil
Apply these rules in order:
Cache the complete observation, including
evidenceCode,observedAt, andvalidUntil.While the evidence window is current, branch on
evidenceCodeor the derivedverdict.After
validUntil, treat Online, Offline, and every other prior state as Unknown until a fresh response arrives.Do not poll faster than the returned evidence window. Repeated callers can share one bounded cache entry and one in-flight check.
Keep edition and address identity in the cache key. Java and Bedrock are different protocols even though they share a client quota.
Treat
429, capacity failure, malformed timestamps, and failed refreshes as Unknown—not Offline and not proof of an outage.
The Online, Offline, and Unknown guide covers the display meaning. The latency guide explains why a status round trip is not gameplay tick performance.
HTTP response policy
| Path | Response status | Cache-Control | CORS origin | OPTIONS |
|---|---|---|---|---|
/api/status/java/{address} | 200 | private, no-store | * | 204 |
/api/status/bedrock/{address} | 200 | private, no-store | * | 204 |
/api/services | 200 | private, no-store | * | 204 |
/api/health | 200 | no-store | none | none |
/api/v1/community/status | 200 | private, no-store | none | none |
/api/v1/status/java?address=... | 200 | private, no-store | * | 204 |
/api/v1/status/bedrock?address=... | 200 | private, no-store | * | 204 |
/api/v1/status/batch | 200 | private, no-store | * | 204 |
/api/v1/jobs/{jobId} | 200 | private, no-store | * | 204 |
/api/v1/services | 200 | private, no-store | * | 204 |
/api/v1/incidents | 200 | private, no-store | * | 204 |
/api/v1/incidents/{incidentId} | 200 | private, no-store | * | 204 |
/api/v1/history/{targetId} | 200 | private, no-store | * | 204 |
/api/v1/versions | 200 | private, no-store | * | 204 |
/api/v1/badges/{targetId}.svg | 200 | public, max-age=60, s-maxage=60 | * | 204 |
/api/v1/openapi.json | 200 | public, max-age=300, s-maxage=300 | * | none |
Successful server, service, incident, history, and version responses emit X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset. Versioned observation and batch responses also emit the remaining target-unit budget. Rejected quota requests emit Retry-After; pending job responses do too. Badges and the OpenAPI document are cacheable public artifacts with ETags. These headers describe client budgets and never change a target verdict.
Local health and community response shapes
/api/health uses the response shape below. The live release, uptime, and time values change at runtime.
{
"schemaVersion": 2,
"contract": "minecraftstatus-health/v2",
"status": "ok",
"domain": "minecraftstatus.com",
"service": "minecraftstatus",
"release": "contract-fixture",
"uptimeSeconds": 42,
"time": "2026-07-21T12:00:00.000Z",
"components": {
"website": { "status": "online", "release": "contract-fixture" },
"discordBot": { "status": "unknown", "release": null, "observedAt": null }
}
}/api/v1/community/status fails closed to this private, no-store Unknown envelope when no admitted local heartbeat exists:
{
"schemaVersion": 1,
"contract": "minecraftstatus-community-status/v1",
"status": "unknown",
"release": null,
"observedAt": null,
"validUntil": null
}/api/services: 13 scoped rows
/api/services returns minecraftstatus-service-view/v2 with snapshotStatus, generatedAt, validUntil, and exactly 13 ordered components. Each component exposes id, label, sourceKind, outcome, state, evidenceCode, timestamps, latency, evidence scope, limitation, and an optional reference URL.
Seven evidence sources are enabled:
| Row | Source | Evidence window | Evidence scope | Limitation |
|---|---|---|---|---|
launcher_versions | Launcher version distribution | 180 seconds | The official manifest endpoint returned a coherent current version manifest to this host. | Distribution metadata only; no game version was downloaded or launched. |
minecraft_public_keys | Minecraft public keys | 180 seconds | The public-key endpoint delivered the required parseable key sets to this host. | Key delivery and parseability do not establish an arbitrary signature or trust chain. |
microsoft_identity_discovery | Microsoft identity discovery | 180 seconds | The consumer OIDC discovery document advertised the pinned issuer and endpoints. | No authorization, consent, login, device code, or token exchange occurred. |
playfab_official_status | PlayFab official status | 120 seconds | This row repeats the fresh official PlayFab summary and pinned Authentication and Xbox Live component states. | This is the official PlayFab report, not a global Minecraft verdict. |
microsoft_xbox_minecraft_auth | Microsoft/Xbox/Minecraft token chain | 900 seconds | One dedicated account refreshed its saved Microsoft sign-in and exchanged it through Xbox user token, XSTS and Minecraft login from the collector host. | One account on one host. Operational means this path worked for this account at the observation time; it does not prove every player can sign in. |
minecraft_entitlement_profile | Minecraft entitlement and account profile | 900 seconds | With a fresh Minecraft token, the entitlement and profile services answered and still showed a Java-owning account matching the canary's recorded profile. | One account on one host. It cannot show entitlement problems that affect other accounts or regions. |
java_authenticated_join | Java authenticated join | 900 seconds | A Java client using that token completed Mojang's session join, a private online-mode server verified it through Mojang's session service, and the client reached the play state. | The server is a private canary on the collector host, not a public server; this checks Mojang's session services, not any server's availability. |
The other 6 explicit not-collected rows return state: "not-collected", outcome: "not-collected", and evidenceCode: "collector_disabled" with null observation timestamps:
| Row | Evidence scope | Limitation |
|---|---|---|
mojang_identity_lookup | The versioned anonymous contract exists, but no public identity is approved or loaded. | No identity lookup is scheduled. |
java_signed_profile | The versioned contract exists, but no approved identity is queried. | Signature presence is not signature verification. |
skin_texture_delivery | No identity-derived texture reference is fetched. | No player texture availability claim is made. |
xbox_network_status | Nothing is inferred; the first-party status page is linked only. | The support page is not scraped or converted into evidence. |
minecraft_realms_metadata | No authenticated Realm list or metadata is read. | An absent collection is not a Realms outage. |
bedrock_authenticated_join | No Bedrock entitlement, RakNet, login, encryption, resource-pack, or play-state flow is attempted. | No Bedrock platform conclusion is made. |
Anonymous synthetic failures stay Unknown. Authenticated canary failures stay Unknown too. Neither can publish degraded or outage. Only the official PlayFab row can provide a scoped degraded or outage state, and that state describes the official PlayFab report within the row's stated scope. The services array is not an overall Minecraft health verdict, and clients must not aggregate it into one.
If the local service snapshot is missing, invalid, stale, or belongs to another release, enabled rows fail closed to Unknown while disabled rows remain explicitly not collected. The three authenticated rows come from their own evidence file: if only that file is missing, invalid, or stale, only those three rows fail closed to Unknown.
Integration checklist
Call the endpoint for the correct edition and retain the address form used for the request.
Branch server UI on canonical
evidenceCode; useverdictas its closed display class.Store and display
observedAtandvalidUntilbeside any status badge.Replace expired evidence with Unknown before rendering or alerting.
Treat service rows independently and retain each row's
evidenceScopeandlimitation.Respect the shared 20-per-60-second server budget, the v1 anonymous 30-per-60-second request budget, and the v1 5,000 target-observation units per day. Registered and directory key allowances are documented above. Batch requests spend one unit per input target; polling a job spends none.
Keep private resolution and connect targets out of logs and public responses.
Contract version
This guide covers contract version 1, reviewed on 2026-07-21. Use the live API protocol sheet for current endpoint schemas and limits.