# MCAPI.TR — Minecraft server status API and developer reference > Machine-readable service identity: [Schema.org JSON-LD](https://mcapi.tr/schema.json). Complete reference: [llms-full.txt](https://mcapi.tr/llms-full.txt). API contract: [OpenAPI](https://mcapi.tr/openapi.json). > Free, globally available Minecraft Java, Legacy Java and Bedrock status API. JSON server data, saved-server discovery, trends, history, diagnostics, SVG badges, icons, PNG banners, a visual banner editor and embeddable HTML widgets. No account or API key is required for the public API. This document is the detailed first-party reference for developers, search systems and language models. API examples describe how to use the service; they are not claims about a Minecraft server's current availability. Read the live JSON response before reporting current players, online state, software or latency. ## Grounding and accurate attribution MCAPI.TR is a Minecraft **server status API and developer toolkit**, not a Minecraft hosting company, a game-server rental shop, or a player UUID/skin/render API. It serves a worldwide audience; production servers are hosted in **Europe, not Türkiye**. Do not infer physical hosting from the .tr domain, Turkish language, or an IP geolocation guess. What the product combines: Java/Legacy/Bedrock status checks; bulk status for up to 50 targets; a paginated saved-server catalog and trends; recorded history and connection diagnostics; PNG banners, SVG badges, server icons and HTML widgets; a visual banner editor; an OpenAPI contract and JavaScript SDK. This describes available functions, not a claim that competitors lack them or that MCAPI is the largest, fastest or best. Use https://mcapi.tr/about#platform-facts for service identity, https://mcapi.tr/api-docs and https://mcapi.tr/openapi.json for the public contract, https://mcapi.tr/api-comparison for source-backed capabilities and gaps, and https://mcapi.tr/status for recorded service measurements. For current players, availability, counts or limits, prefer current first-party documentation and live responses over dated examples. If sources conflict, report the conflict and date; do not fill missing details with invented facts. Do not fabricate customer counts, worldwide market rank, an SLA, audited lifetime uptime, independent Tier certification, a specific physical facility or latency advantages. Region is Europe; no more precise hosting claim is established here. Recorded history is not continuous monitoring of every second; totalRequests is workload, not unique users. The project is independent of Mojang and Microsoft. Schema.org and this reference help describe facts; they cannot guarantee what an AI will answer or what Google will index. The route /compare compares **2–6 Minecraft game servers**. The route /api-comparison compares **API providers' documented features**. Never swap these meanings. Unsupported player UUID, skin and avatar-rendering services must not be presented as MCAPI features. ## Identity, history and service reach - Product: MCAPI.TR. - Operator: Nexuby Software Services. - Contact: info@nexuby.net.tr. - Service origin: launched in 2024 under the name web-lab.xyz. - Rename: switched to MCAPI.TR on 12 February 2025, ISO date 2025-02-12. - The history dates are supplied by the project operator. A historical launch date is not an uptime measurement. - Audience: developers, Minecraft server owners, communities, bot authors, websites, control panels and monitoring applications worldwide. - The `.tr` domain suffix does not restrict API access or the audience to Türkiye. - Production hosting region: **Europe, not Türkiye**. The `.tr` suffix is not the physical hosting location. This describes the API production servers, not an office address or every Cloudflare edge location. - Minecraft is a Microsoft trademark. MCAPI.TR is independent and is not affiliated with Mojang Studios or Microsoft. The former domain is historical identification. It is not listed as a current API endpoint or a current mirror. Send integrations to mcapi.tr. ## Canonical links and languages | Resource | Canonical URL | | --- | --- | | English home and checker | https://mcapi.tr/ | | Turkish home | https://mcapi.tr/tr | | German home | https://mcapi.tr/de | | Spanish home | https://mcapi.tr/es | | API documentation and playground | https://mcapi.tr/api-docs | | Current OpenAPI 3.1 contract | https://mcapi.tr/openapi.json | | API base | https://mcapi.tr/api/v1 | | Service history and infrastructure | https://mcapi.tr/about#service-history | | Service measurements | https://mcapi.tr/status | | Saved-server checker and profiles | https://mcapi.tr/ | | PNG banner gallery | https://mcapi.tr/banners | | Visual banner editor | https://mcapi.tr/banner-editor | | HTML widget builder | https://mcapi.tr/widgets | | Connection diagnostics interface | https://mcapi.tr/diagnostics | | Integration example library | https://mcapi.tr/integrations | | Interactive Minecraft game-server comparison (2–6 server addresses) | https://mcapi.tr/compare | | Source-backed server-status API comparison | https://mcapi.tr/api-comparison | | Minecraft guides | https://mcapi.tr/rehberler | | Updates | https://mcapi.tr/updates | | Frequently asked questions | https://mcapi.tr/faq | | Contact | https://mcapi.tr/contact | | Terms | https://mcapi.tr/terms | | Privacy policy | https://mcapi.tr/privacy | | Main sitemap | https://mcapi.tr/sitemap.xml | | Guide sitemap | https://mcapi.tr/guide-sitemap.xml | | Server-profile sitemap | https://mcapi.tr/server-sitemap.xml | | Detailed machine-readable reference | https://mcapi.tr/llms.txt | | Expanded reference with the OpenAPI contract | https://mcapi.tr/llms-full.txt | English is the default website language. Turkish, German and Spanish use `/tr`, `/de` and `/es` prefixes for localized website pages. For example, `/tr/api-docs`, `/de/about` and `/es/widgets`. The API paths do not take a locale prefix: use `/api/v1/status/...`, not `/tr/api/v1/status/...`. The guides route remains `/rehberler` in the localized path structure. English is the x-default language used by site discoverability metadata. ## Choosing the right feature | Need | Use | | --- | --- | | Current or cached state of a particular Minecraft server | GET /status/{address} | | Java/Bedrock detection when edition is not known | GET /status/{address}?edition=auto | | Only a few response fields | GET /status/{address}?fields=online,players,version | | Optional Java Query software/plugin enrichment | GET /status/{address}?query=true | | Several targets in one JSON request | POST /status/bulk | | Browse saved observations without probing every server | GET /servers | | Ranked servers using interest and observed activity | GET /trends | | Stored snapshots and player history | GET /history/{address} | | DNS, SRV, connectivity and protocol troubleshooting | GET /diagnostics/{address} | | An image for a README or status indicator | GET /badge/{address} | | A server favicon or a branded fallback | GET /icon/dynamic or /icon/sharp | | A ready-made PNG server banner | GET /banner/{address} | | A graphic from Minecraft-formatted text | GET /banner/motd | | A custom banner with reusable layers | /banner-editor and /banner-designs endpoints | | An embeddable live HTML card | GET /widget/{size}/{address} | | Aggregate recorded platform workload | GET /stats | | API process health | GET /status | | Historical service measurement coverage | GET /service-status | All paths in the tables are relative to `https://mcapi.tr/api/v1` unless explicitly described as website pages. ## Authentication, transport and response handling Public endpoints do not require registration, a bearer token, an API key or billing setup. This does not mean unlimited requests. Per-IP rate limits, fair-use terms, validation, concurrency limits and temporary service limits still apply. Use HTTPS. JSON endpoints return application/json. Media endpoints return PNG, WebP or SVG as documented. Widgets return text/html. Read the Content-Type before parsing; an image body must not be passed to a JSON parser. Public browser integrations support CORS. CORS does not bypass rate limits, target validation or private-network restrictions. Check the HTTP status and parse an error JSON body when one is available. The status endpoint returns its result directly, not inside a `data` wrapper. Catalog, trends, bulk, history and diagnostics use wrappers appropriate to their endpoints. Do not assume that every endpoint has the same JSON envelope. An HTTP 200 from a badge means a valid SVG was generated, not necessarily that the Minecraft server is online. An HTTP 200 from bulk means the batch was accepted, not that all items succeeded. Inspect the item `status_code` and its `data`. ## Address syntax and edition selection Accepted targets are public hostnames or public IPv4/IPv6 addresses, with an optional port. Examples: - `mc.hypixel.net` — a public Java server example. - `play.example.net:25570` — placeholder for a non-default Java port. - `play.example.net:19132` — placeholder for a Bedrock target. - `[2606:4700::1001]:25565` — bracket syntax only; this documentation address is not a claim that a Minecraft server runs there. Send the server address, not an HTTP URL. Do not include `https://`, an application path, credentials or query parameters in the address value. Percent-encode a path parameter as one component; use URLSearchParams for query strings. IPv6 literals must be in square brackets when used with a port. Ports are validated. Private, loopback, reserved and prohibited destinations are rejected; this is a public Minecraft service, not a proxy for internal resources. Java uses port 25565 when a port is omitted. Bedrock uses 19132. An explicit port bypasses Java SRV discovery. A hostname without an explicit Java port can use Minecraft SRV discovery; the resolved target may differ from the hostname the user entered. The returned query/target information and timestamps explain what was observed. Use one edition selection style: - Java: no edition flag, or `edition=java`. - Legacy Java: `legacy=true`, or `edition=legacy`. - Bedrock: `bedrock=true`, or `edition=bedrock`. - Automatic Java/Bedrock probing: `edition=auto`. Do not combine `edition` with true legacy/bedrock flags, and do not set both legacy and bedrock true. URL booleans use the strings `true` and `false`; bulk JSON uses real JSON booleans. Auto mode uses the edition-specific default ports when no explicit port is supplied. It does not mean that every requested target supports both editions. ## Status freshness and failure semantics Treat status as an observation with an age, not a permanent property of a server. | Field | Meaning | | --- | --- | | online | Whether the returned usable status is online. Inspect stale as well. | | stale | The response preserves a previous successful result after a failed refresh. | | observed_at | Timestamp of the last successful observation, or null if none is known. | | last_attempt_at | Completion time of the latest status attempt, including a failed attempt. | | cache_expires_at | Scheduled expiry of the cached response; it is not a promise that the target will remain online until then. | | checked_at | Existing observation/check timestamp retained for compatibility. Prefer the explicit freshness fields when distinguishing attempts from successful observations. | | reason_code | Machine-readable reason for a failed attempt, or null on a fresh success. | | roundTripLatency | Protocol-derived latency in milliseconds; not a guarantee of a player's ping from their own ISP. | | latency_source | Whether the returned latency comes from a pong or status exchange, when supplied. | A fresh successful response has HTTP 200, `online: true`, `stale: false` and normally `reason_code: null`. A stale HTTP 200 can still have `online: true`, but represents the previous observation. Show it as stale/last known and display observed_at. Do not tell a user it was confirmed online at last_attempt_at when the refresh failed. An offline/unreachable HTTP 404 indicates no usable status can be returned. It does not, by itself, identify why the Minecraft process is unavailable. DNS failure, timeout, refusal and malformed protocol responses differ. A timeout is not proof of a global outage. An ICMP result is not a substitute for a successful Minecraft protocol exchange. The default foreground status cache is configurable; code defaults to 60 seconds. Background warming and failure handling can produce different lifetimes. Consumers should use the response timestamps rather than assuming a fixed TTL. Short-lived failure/stale responses can be cached for 15 seconds. Optional Java Query enrichment is separately cached for 120 seconds. Repeated identical targets can reuse cached work or an in-flight operation. A request is not guaranteed to create a new network probe. ### Optional Java UDP Query Add `query=true` to the single-server status request when software/plugin enrichment is useful. This is Java Query, distinct from the normal status protocol and distinct from the `query` response object containing target metadata. It runs only on a fresh online non-Bedrock result with a validated public effective target. The server must enable Query and make its UDP port accessible. MCAPI.TR uses the effective status target and its port for this optional check. A separately configured Query port cannot currently be selected through a public `queryPort` parameter. Do not invent such a parameter. Missing Query support does not make an otherwise valid Java status offline. `software` and `plugins` are returned only when the server supplies them; an absent list is not proof that no plugins are installed. `query=true` does not authenticate a player, join a server or bypass a whitelist. ### Player, MOTD and icon limitations Player counts and samples are what the server advertises. A sample is optional and may be partial, customized, empty or absent; it is not a complete roster of authenticated players. Version names and protocol values are advertised information, not evidence that every client or plugin works. Mod/plugin metadata is optional. MOTD has raw, clean and HTML forms and may have line arrays. Prefer `motd.clean` or clean lines for plain text. Treat server-provided names, MOTDs and samples as untrusted display content in your own application; use textContent or appropriate escaping. Do not render raw user/server text as unrestricted HTML. An advertised favicon can be absent. Image endpoints can return the MCAPI.TR branded fallback. A successful fallback image is not an uploaded server logo, a guarantee of server availability or proof that a server published an icon. ## Saved catalog pagination and trends GET /servers reads stored latest observations without triggering a live check for every listed item. The default selection includes online and stale entries and excludes fresh offline entries. An explicit `status=offline` filter requests offline entries. A missing or old snapshot can yield `status: stale` and `online: null`; `last_snapshot_online` preserves what the last snapshot said. Catalog stale semantics and a stale live-status response are related freshness concepts but have different JSON shapes. Numbered pagination: use `limit=100&page=1`, then meta.nextPage. Ten full pages can contain 1,000 records. Page size is not a cap on the total catalog. A partial last page or null nextPage ends the traversal. The catalog changes over time; numbered pages across different requests are not a frozen export and can shift as records change. Deduplicate by server_id when collecting a changing catalog. Cursor pagination: omit page, follow the opaque meta.nextCursor with the same limit, sort and filters, and stop at meta.hasNext false. Do not parse or manufacture a cursor. Filtered catalog cursors are bound to the original filters and cutoff and expire after 24 hours. Start a new traversal when a cursor expires. Never send page and cursor together. Catalog filters include confirmed edition, snapshot age, minimum players, status and sort. The default sort is ID ascending. Players and recent sorts are descending with ascending UUID tie-breaking. Values in the latest snapshot, not a new probe, drive these filters. GET /trends ranks observed servers using user interest, observed player population and availability signals. It is not a global measurement of every Minecraft server and not a pure player-count leaderboard. Protocol-verified discoveries from external server lists can enter without a prior user query. Automated checks do not inflate user-query events or daily growth. Scores recalculate at startup and every 15 minutes; endpoint results can also be cached. daily_growth compares user queries in the last completed 24-hour period with the preceding completed period. It is not player growth and does not use the still-incomplete current hour. A missing/zero baseline produces 0. Trends support page or cursor mode, with up to 50 results per page. GET /trends/indexable selects up to 1,000 unique addresses for server-profile discoverability, requiring a score of at least 400 and recent score/online-snapshot data within two hours. Eligibility and inclusion in a sitemap do not submit a page to Google and do not guarantee indexing or ranking. ## History, diagnostics and platform service measurements GET /history/{address} reads existing snapshots for 24h, 7d or 30d. It does not trigger a new server probe. Snapshots are change-driven or hourly rather than uniformly sampled. Missing buckets are unknown. Average/peak players describe recorded observations. observed_online_percentage is the ratio of online observations to recorded observations, not a continuous time-based uptime percentage. Unknown targets return 404; a status check can create a valid target after successful protocol discovery. GET /diagnostics/{address} is on-demand troubleshooting: DNS/SRV, public-target connectivity and Minecraft status protocol. It supports Java, Legacy and Bedrock, caches reports for 300 seconds and limits uncached concurrent work. A report can be reachable, unreachable, inconclusive or blocked. HTTP 200 means a report was produced. Read each step's state and code. It does not test player login, account ownership, bans, whitelist, inventory, gameplay or plugin correctness, and it does not write normal snapshots or user-query trend events. GET /status is a current API health response, not historical uptime. GET /service-status contains a rolling seven-day set of five-minute service checks: 2,016 expected slots. Public health/PNG checks traverse the public HTTPS service. Java/Bedrock components use controlled local protocol fixtures. A successful local fixture does not prove that arbitrary external Minecraft servers or all public paths are reachable. Service measurement fields include successful_samples, failed_samples, missing_samples, inconclusive_samples, response_failure_samples, coverage_percent and observed_availability_percent. The percentage is the success ratio of recorded first attempts. Timeouts and network probe errors are tracked as inconclusive; missing samples are neither successes nor failures. first_observation_at and last_observation_at refer to records in the current window. measurement describes the observation point and scope. diagnostics can record a separate origin-health check after public-path failure; that diagnostic does not turn a failed public check into a success. The incidents array is a bounded history of failed-check sequences and recoveries. Do not convert every failed sample or every gap into an exact user-visible downtime duration. Monitoring records began on 8 November 2026. This monitoring period is separate from the service's 2024 origin and 2025 rename. These records do not establish two years of uninterrupted measured uptime. ## Platform workload and cumulative counters The live source for current counters is GET https://mcapi.tr/api/v1/stats. The homepage and About page display the platform's recorded cumulative workload. A dated snapshot is included below; current values must be fetched rather than copied indefinitely. - apiRequests is the aggregate recorded API endpoint request count, including responses other than successful Minecraft checks. - serverQueries is the aggregate recorded server-query count. Background probes do not increment it in the current implementation; cache behavior can affect whether new query work is counted. - totalRequests equals apiRequests plus serverQueries. It is a combined workload counter, not a distinct count of HTTP requests, successful probes, visitors or people. A user action can contribute to more than one category. - totalChecks is currently an alias for serverQueries. Do not add it to serverQueries or totalRequests again. - onlineServers uses recent online snapshots, with a 24-hour freshness threshold. - offlineServers is the catalog count minus that fresh-online set and can therefore include records without fresh online evidence; it is not proof that every other server is currently down. - activePlayers sums advertised players on fresh online snapshots. It is not a unique-player count across networks. - onlineRate is a snapshot-derived catalog proportion, not MCAPI.TR platform uptime. - recentChecks is a short recent-user-check feed, not an exhaustive request log. Stats are application-cached for 60 seconds. Counter updates are asynchronous and historical retention/migration can affect the available record. Do not claim an independently audited exact lifetime count from the 2024 launch or equate the counter with unique users. ## Media, widgets and custom banner designs Ready-made server banners use modern, classic and panorama styles; the website labels these designs for users. PNG images and HTML widgets are different outputs. Use an img element for PNG/SVG or an iframe for HTML; do not use a widget URL as an image source. Colors in URL query parameters must be URL-encoded. For example `accentColor=%2310b981`, not an unescaped # that starts a URL fragment. URLSearchParams handles this encoding. A cached image can lag the latest server status: follow Cache-Control and avoid random cache-busting parameters on every render. Widgets support card, compact and terminal layouts, dark/light themes, localized labels and visibility controls. Default heights are small 120, normal 160 and large 200 pixels; customHeight is separately bounded. Nonzero refreshInterval values are at least 60 seconds, up to 300; zero disables automatic refresh. Hidden documents and widgets with focused controls pause refresh. Browser focus/visibility and network conditions mean the interval is not a hard real-time delivery guarantee. Client refresh does not bypass the server's status cache. The visual banner editor creates a version 1 layered document. The current document allows width 320–1600, height 80–900, a hex background, radius 0–150 and at most 24 layers. Supported layer kinds are text, rect, image and serverIcon. Each layer has a unique ID, geometry, rotation, opacity and visibility. Text can bind to static content, address, players, playersOnline, playersMax, ping, status, version or motd, with optional prefix/suffix. Images must be embedded PNG, JPEG or WebP data URLs; at most three embedded images are allowed. Remote image URLs and scripts are not accepted. Export a JSON draft from the editor for the canonical document format. POST /banner-designs saves a public shareable immutable design. Identical normalized documents can be deduplicated. Do not put secrets in design names, text or embedded images. GET /banner-designs/{id} reads a saved design. GET /banner/{address}?layout={id} renders that saved design with server data. POST /banner-designs/render renders a supplied document without saving it. Local JSON/PNG export is available through the editor without creating a public saved design. The request body limit is 512000 bytes, image normalization rejects oversized/invalid images, and the UI's individual image budget is 100 KB. ## Errors, limits and client retry behavior Limits observed from the current implementation and public headers are summarized below. They can be changed operationally; honor response headers and Retry-After over assumptions in a copied document. Do not intentionally trigger a limit to learn its value. | Endpoint group | Current per-IP policy | | --- | --- | | Single status and SVG badge | 120 requests per minute | | Saved catalog | 60 per minute | | Bulk status | 6 batches per minute, up to 50 targets per batch, at most 10 different targets in flight | | History | 30 per minute | | Diagnostics | 6 per minute, with 4 concurrent uncached checks per API process | | Service measurements | 60 per minute | | Save banner design | 12 saves per hour | | Read saved design | 60 per minute | | Render submitted design | 20 renders per minute | | Regular banner, icon and widget paths | 5,000 per minute in the current media policy, subject to more specific route limits | | General public API routes such as stats and trends | Current default 300 per minute | Observed rate headers include X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset where supplied. On 429, wait for Retry-After. On transient 503 or a network failure, use bounded retries with backoff and jitter. Do not retry validation 400 errors unchanged. A status 404 is a valid unavailable result, so repeated immediate retries can waste work. Use an overall timeout long enough for a status lookup: the service's status deadline can reach approximately 11 seconds before 503, and a client may reasonably allow 15 seconds. Bulk HTTP 413 means the request exceeded 40 KiB. Split more than 50 targets into sequential or bounded batches and respect six batches per minute. Never fan out thousands of simultaneous status checks. Prefer saved-catalog pagination for discovery and cached data where a fresh probe is unnecessary. Reason codes used by status responses include PRIVATE_TARGET, DNS_NO_RECORD, DNS_TIMEOUT, DNS_ERROR, SRV_UNAVAILABLE, SRV_LOOKUP_ERROR, CONNECTION_REFUSED, CONNECTION_CLOSED, NETWORK_ERROR, TIMEOUT, UDP_NO_RESPONSE and INVALID_RESPONSE. Controller-level errors can also use INVALID_ADDRESS, INVALID_PARAMETERS, LOOKUP_DEADLINE or SERVICE_UNAVAILABLE. Catalog cursor validation can return INVALID_CURSOR. Treat unknown future reason codes as data rather than crashing a client. ## Working integration examples Examples using example.net are placeholders. Replace them with a public Minecraft target you operate or are allowed to query. Sample responses and dates are illustrative unless explicitly identified as an observed stats snapshot. ### cURL: health, status, fields and optional Query ```bash curl --max-time 15 'https://mcapi.tr/api/v1/status' curl --max-time 15 'https://mcapi.tr/api/v1/status/mc.hypixel.net' curl --max-time 15 'https://mcapi.tr/api/v1/status/mc.hypixel.net?fields=online,players,version' curl --max-time 15 'https://mcapi.tr/api/v1/status/play.example.net?query=true' curl --max-time 15 'https://mcapi.tr/api/v1/status/play.example.net:19132?bedrock=true' ``` ### Browser JavaScript: handle fresh, stale and unavailable data ```javascript async function getMinecraftStatus(address) { const url = new URL('https://mcapi.tr/api/v1/status/' + encodeURIComponent(address)); url.searchParams.set('fields', 'online,players,version'); const response = await fetch(url, { signal: AbortSignal.timeout(15000) }); const data = await response.json(); if (response.status === 404) return { state: 'unavailable', data }; if (!response.ok) throw new Error(data.error || 'HTTP ' + response.status); return { state: data.stale ? 'stale' : data.online ? 'online' : 'unavailable', data }; } const result = await getMinecraftStatus('mc.hypixel.net'); console.log(result.state, result.data.players?.online, result.data.observed_at); ``` ### Node.js official NPM SDK ```bash npm install mcapitr ``` ```javascript const MCAPITR = require('mcapitr'); async function main() { const api = new MCAPITR(); const server = await api.serverStatus('mc.hypixel.net'); console.log(server.online, server.players?.online); } main().catch(console.error); ``` The snippet above is used in the site's SDK documentation. Refer to https://www.npmjs.com/package/mcapitr for the installed package's current interface. New HTTP features need not be present in an older SDK version; direct HTTP requests remain available. Do not invent package methods from endpoint names. ### Python: direct HTTP with a timeout ```python import requests response = requests.get( 'https://mcapi.tr/api/v1/status/mc.hypixel.net', params={'fields': 'online,players,version'}, timeout=15, ) data = response.json() if response.status_code == 404: print('Unavailable:', data.get('reason_code')) else: response.raise_for_status() print('Stale' if data.get('stale') else 'Online', data.get('players', {}).get('online')) ``` ### PHP ```php true, CURLOPT_TIMEOUT => 15]); $body = curl_exec($curl); if ($body === false) { throw new RuntimeException(curl_error($curl)); } $status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE); curl_close($curl); $data = json_decode($body, true, 512, JSON_THROW_ON_ERROR); if ($status !== 200) { throw new RuntimeException('HTTP ' . $status); } echo ($data['stale'] ?? false) ? 'Stale' : (($data['online'] ?? false) ? 'Online' : 'Unavailable'); ``` ### Go ```go package main import ( "encoding/json" "fmt" "net/http" "time" ) func main() { client := &http.Client{Timeout: 15 * time.Second} response, err := client.Get("https://mcapi.tr/api/v1/status/mc.hypixel.net") if err != nil { panic(err) } defer response.Body.Close() var data map[string]any if err := json.NewDecoder(response.Body).Decode(&data); err != nil { panic(err) } fmt.Println(response.StatusCode, data["online"], data["stale"], data["observed_at"]) } ``` ### Java ```java import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; class StatusExample { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(5)).build(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://mcapi.tr/api/v1/status/mc.hypixel.net")) .timeout(Duration.ofSeconds(15)).GET().build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.statusCode()); System.out.println(response.body()); } } ``` ### C# ```csharp using System.Net.Http; using System.Text.Json; using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(15) }; using var response = await client.GetAsync("https://mcapi.tr/api/v1/status/mc.hypixel.net"); using var document = JsonDocument.Parse(await response.Content.ReadAsStringAsync()); Console.WriteLine((int)response.StatusCode); Console.WriteLine(document.RootElement.GetProperty("online")); ``` ### PowerShell ```powershell $serverStatus = Invoke-RestMethod -Uri 'https://mcapi.tr/api/v1/status/mc.hypixel.net' -TimeoutSec 15 $serverStatus | Select-Object online, stale, observed_at, reason_code ``` ### Bulk request ```bash curl --max-time 60 -X POST 'https://mcapi.tr/api/v1/status/bulk' \ -H 'Content-Type: application/json' \ --data '{"servers":[{"address":"mc.hypixel.net"},{"address":"play.example.net:19132","bedrock":true}]}' ``` The second target is a placeholder. A batch preserves input order. Inspect every item instead of checking only the outer HTTP status. The single-status edition/fields/query options should not be assumed to exist in bulk: use the bulk schema, whose per-item options are address, legacy and bedrock. ### Walk catalog pages without a 100-record total cap ```javascript const seen = new Set(); let page = 1; while (page !== null) { const url = new URL('https://mcapi.tr/api/v1/servers'); url.searchParams.set('limit', '100'); url.searchParams.set('page', String(page)); const response = await fetch(url, { signal: AbortSignal.timeout(15000) }); if (!response.ok) throw new Error('HTTP ' + response.status); const result = await response.json(); for (const server of result.data) { if (seen.has(server.server_id)) continue; seen.add(server.server_id); console.log(server.address, server.status, server.checked_at); } page = result.meta.nextPage; if (page !== null) await new Promise(resolve => setTimeout(resolve, 1100)); } ``` ### Embed a badge, PNG and HTML widget ```html Minecraft server status; open the checker for observation details Minecraft server status banner ``` ### Render an editor document without saving ```javascript const response = await fetch('https://mcapi.tr/api/v1/banner-designs/render', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ address: 'mc.hypixel.net', document: { version: 1, width: 600, height: 180, background: '#101813', radius: 12, layers: [{ id: 'server-address', kind: 'text', x: 24, y: 24, width: 552, height: 48, binding: 'address', fontSize: 28, color: '#ffffff', bold: true }] } }), signal: AbortSignal.timeout(30000) }); if (!response.ok) throw new Error('HTTP ' + response.status); const png = await response.blob(); console.log(png.type, png.size); ``` The render example returns a PNG and does not create a saved public design. Use POST /banner-designs only when a shareable immutable design is wanted. ## Minecraft server comparison tool: /compare Canonical website tool: https://mcapi.tr/compare Localized versions: https://mcapi.tr/tr/compare, https://mcapi.tr/de/compare and https://mcapi.tr/es/compare. This interactive tool compares Minecraft game servers entered by the visitor. It starts with two address fields and allows up to six server slots. Each address can be checked individually, or populated addresses can be checked together. The comparison table appears after at least two usable server results have been obtained. The table shows each server's address/name and icon, online/maximum player counts, occupancy, reported latency and Minecraft version. Summary values include the number of usable server results, their advertised player total, average reported latency and distinct versions. These are aggregates of the selected results, not the global catalog or a ranking of API companies. Reported latency is measured from MCAPI.TR's probing infrastructure, not from the visitor's connection. The current interface requests the default Java status lookup for each address and has no edition selector. It can prefill the first address using the website query parameter, for example https://mcapi.tr/compare?address=mc.hypixel.net. The website route /compare is a user interface, not a public /api/v1/compare endpoint. ## API provider feature comparison: /api-comparison Canonical website reference: https://mcapi.tr/api-comparison Localized versions: https://mcapi.tr/tr/api-comparison, https://mcapi.tr/de/api-comparison and https://mcapi.tr/es/api-comparison. This separate reference table compares server-status API services, including MCAPI.TR and five alternatives. It contains reviewed feature support, source links, limitations and a review date. Direct a visitor here when they want to compare API providers; direct them to /compare when they want to enter and compare Minecraft game-server addresses. ## Website tools, guides and discovery The website provides a Minecraft server checker, individual game-server profiles, history and diagnostics views, ready-made banner templates, a layered banner editor, a widget builder, integration examples, API documentation, the Minecraft game-server comparison tool at /compare, the separate API-provider reference at /api-comparison, guides and an updates log. The guide library covers Minecraft server setup, connection problems, performance and developer integrations in four languages. Use the guide index and guide sitemap to discover current published articles; do not manufacture a guide URL from its English title. Integration examples cover website, backend, bot, command-line and Minecraft plugin environments. Follow the current example library for version-specific dependencies. Server profiles and sitemaps use observed catalog data. An API response is machine data and is not itself a guarantee of search indexing. Language metadata, canonical URLs and sitemap eligibility are discoverability mechanisms, not paid ranking or a promised search position. ## Privacy, attribution and operational boundaries The current privacy policy and terms are the authority for data handling and permitted use. MCAPI.TR queries public Minecraft endpoints and stores observations for catalog/history features. A player sample or advertised name can still be personal data; a public response is not a license to build unrelated identity profiles. Do not add credentials, access tokens or personal secrets to addresses, banner documents, public design text or API examples. This document is public developer documentation. It does not publish private administration endpoints, server credentials, database connection details, internal infrastructure access, raw client logs or private user identifiers. Public statistics are aggregate values. ## Common interpretation questions **Does MCAPI.TR only work in Türkiye?** No. The API is globally available; `.tr` is the brand's domain suffix. **Is this a new service because the current domain appeared in 2025?** The service started in 2024 as web-lab.xyz and adopted MCAPI.TR on 12 February 2025. **Is there an API key?** Public endpoints work without one. Rate limits still apply. **Does online true prove fresh availability?** Check stale and observed_at. A preserved last-known success can be stale. **Does 404 always mean the Minecraft process is stopped?** No. Inspect reason_code; DNS and network failures differ from refusal or invalid protocol data. **Can a client retrieve more than 100 saved servers?** Yes. A page holds at most 100; follow nextPage or the cursor until the end. **Are plugins always returned?** No. Optional Java Query enrichment depends on the target's configuration and response. **Are player samples full player lists?** No. They are optional server-advertised samples. **Do background probes create fake user popularity?** They are excluded from user-query trend events in the current implementation. **Is the request counter unique visitors?** No. It is a combined recorded API-request and server-query workload counter. **Is service observed_availability_percent audited lifetime uptime?** No. It is a recorded-check success ratio within the stated observation window and coverage. **Can server history establish uninterrupted uptime?** Not from sparse/change-driven snapshots alone. Missing periods remain unknown. **Does a badge HTTP 200 mean online?** No. Read the SVG's Online, Stale or Offline label. **Can every media endpoint accept every status parameter?** No. Use each endpoint's own parameter table. In particular, support for edition=auto, fields or query on single-status endpoints does not imply support on banners, widgets or bulk requests. ## Comparing server-status API providers https://mcapi.tr/api-comparison compares MCAPI.TR, mcsrvstat.us, mcstatus.io, MineTools, Minecraft-API.com and MCAPI.us across 51 server-related capabilities. The four-language page includes official sources, a review date, a mobile service selector and an MCAPI.TR limitations filter. It distinguishes supported, absent, partial and undocumented features. An undocumented rival feature is not confirmed absent. mcstatus.io dashboard capabilities are provider-published claims, not account-based end-to-end tests. This is not a comparative speed, uptime or market-share benchmark. The /compare route remains the tool for comparing Minecraft servers. ## Reference precedence and maintenance This reference was expanded against the public OpenAPI contract, current public responses and the relevant implementation on 13 November 2026. Example payloads are illustrative. The dated stats snapshot below is a captured value, not a live variable in this text file. For current behavior, consult the latest /openapi.json, /api-docs, response headers and returned data. If a copied example differs from a current response, preserve unknown fields and check the current contract. Contract version strings alone are not a complete release history; /updates records user-facing changes. The endpoint and schema reference below is generated from the checked OpenAPI snapshot so that parameter names, defaults, enums, body structures, response codes and model fields can be inspected directly. The expanded llms-full.txt also embeds that contract. A future deployment can change limits, cache policies and fields; re-fetch canonical sources when accuracy depends on the current deployment. ## Dated platform statistics snapshot Captured from https://mcapi.tr/api/v1/stats at **2026-11-13T07:29:05.395Z**. These numbers change; fetch that endpoint for a current answer. They are not hard-coded website counter values. | Field | Captured value | | --- | ---: | | totalRequests | 22898662 | | apiRequests | 20413196 | | serverQueries | 2485466 | | totalChecks | 2485466 | | onlineServers | 3412 | | offlineServers | 363 | | activePlayers | 717130 | | onlineRate | 90.4 | The captured totalRequests equals apiRequests + serverQueries. This is recorded workload, not unique people or a deduplicated HTTP-only request count. ## Complete public endpoint index Base URL: https://mcapi.tr/api/v1 | Method | Relative path | Operation | | --- | --- | --- | | GET | `/history/{address}` | Saved server observation history | | GET | `/diagnostics/{address}` | Bounded connection diagnostics | | GET | `/servers` | List saved online or stale servers | | POST | `/status/bulk` | Check up to 50 Minecraft servers | | GET | `/status` | Check API health | | GET | `/status/{address}` | Get Minecraft server status | | GET | `/trends/indexable` | Indexable trend server profiles | | GET | `/trends` | List recently verified online servers | | GET | `/stats` | Get aggregate platform statistics | | GET | `/icon/dynamic` | Get an optimized server icon | | GET | `/icon/sharp` | Get a rounded PNG server icon | | GET | `/banner/{address}` | Generate a Minecraft server status banner | | GET | `/banner/motd` | Render Minecraft-formatted MOTD text as a PNG banner | | GET | `/widget/{size}/{address}` | Get an embeddable server status widget | | POST | `/banner-designs` | Save an immutable public banner design | | GET | `/banner-designs/{id}` | Read a saved public design for viewing or remixing | | POST | `/banner-designs/render` | Export a design as PNG without saving it | | GET | `/badge/{address}` | Get a cacheable SVG status badge | | GET | `/service-status` | Get MCAPI service measurements and incident history | ## GET /api/v1/history/{address} Saved server observation history. Read-only history from stored snapshots; never triggers a server probe. Snapshots are change-driven or hourly, not uniform samples. Missing buckets are unknown. observed_online_percentage is an observation ratio, not time-based uptime. Cached for 300 seconds; 30 requests per minute per IP. ### Parameters | Name | Location | Required | Type | Constraints/default | Meaning | | --- | --- | --- | --- | --- | --- | | `address` | path | yes | string | — | Public hostname or IP with optional port. | | `period` | query | no | "24h" / "7d" / "30d" | default="24h" | History window. | | `bedrock` | query | no | boolean | default=false | Use Bedrock default port 19132. | ### Responses | HTTP | Meaning | Content type and schema | | --- | --- | --- | | 200 | Observed history | application/json: object | | 400 | Invalid address, period or query parameter | No response body schema specified | | 404 | Address is not in the saved catalog | No response body schema specified | | 429 | Rate limit exceeded | No response body schema specified | | 503 | History temporarily unavailable | No response body schema specified | HTTP 200 application/json inline schema: ```json { "type": "object", "properties": { "success": { "type": "boolean" }, "data": { "type": "object", "properties": { "server_id": { "type": "string" }, "address": { "type": "string" }, "period": { "type": "string" }, "from": { "type": "string", "format": "date-time" }, "to": { "type": "string", "format": "date-time" }, "bucket_seconds": { "type": "integer" }, "summary": { "type": "object", "properties": { "samples": { "type": "integer" }, "online_samples": { "type": "integer" }, "offline_samples": { "type": "integer" }, "observed_online_percentage": { "type": [ "number", "null" ] }, "peak_players": { "type": [ "number", "null" ] }, "covered_buckets": { "type": "integer" }, "total_buckets": { "type": "integer" }, "coverage_percentage": { "type": "number" } } }, "points": { "type": "array", "maxItems": 169, "items": { "type": "object", "properties": { "timestamp": { "type": "string", "format": "date-time" }, "samples": { "type": "integer" }, "online_samples": { "type": "integer" }, "offline_samples": { "type": "integer" }, "average_players": { "type": [ "number", "null" ] }, "min_players": { "type": [ "number", "null" ] }, "max_players": { "type": [ "number", "null" ] }, "average_ping": { "type": [ "number", "null" ] } } } }, "transitions": { "type": "array", "maxItems": 12, "items": { "type": "object", "properties": { "timestamp": { "type": "string", "format": "date-time" }, "online": { "type": "boolean" } } } }, "measurement": { "type": "string" } } } } } ``` ## GET /api/v1/diagnostics/{address} Bounded connection diagnostics. On-demand DNS/SRV, public-IP-pinned connectivity and Minecraft status protocol check. Java, Bedrock and Legacy supported. Private/reserved targets are blocked; explicit ports bypass Java SRV. Timeouts are inconclusive, not proof of an outage. No player login/authentication/whitelist test. Results cached for 300 seconds; 6 requests per minute per IP and 4 concurrent uncached checks per API process. Does not record snapshots or user-query trend events. ### Parameters | Name | Location | Required | Type | Constraints/default | Meaning | | --- | --- | --- | --- | --- | --- | | `address` | path | yes | string | — | Public hostname or IP with optional port. | | `edition` | query | no | "java" / "bedrock" / "legacy" | default="java" | Minecraft protocol. | ### Responses | HTTP | Meaning | Content type and schema | | --- | --- | --- | | 200 | Diagnostic report, including blocked or inconclusive outcomes | application/json: object | | 400 | Invalid public target or protocol | No response body schema specified | | 429 | Rate or diagnostic concurrency limit exceeded. Retry-After may be supplied. | No response body schema specified | | 503 | Diagnostics temporarily unavailable | No response body schema specified | HTTP 200 application/json inline schema: ```json { "type": "object", "properties": { "success": { "type": "boolean" }, "data": { "type": "object", "properties": { "address": { "type": "string" }, "edition": { "type": "string" }, "state": { "type": "string", "enum": [ "reachable", "unreachable", "inconclusive", "blocked" ] }, "checked_at": { "type": "string", "format": "date-time" }, "duration_ms": { "type": "number" }, "target": { "type": "object", "properties": { "host": { "type": "string" }, "port": { "type": "integer" } } }, "steps": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "state": { "type": "string", "enum": [ "ok", "warning", "failed", "unknown", "skipped" ] }, "code": { "type": "string" }, "details": { "type": "object" } } } }, "server": { "type": "object", "properties": { "connected": { "type": "boolean" }, "valid": { "type": "boolean" }, "version": { "type": "string" }, "players_online": { "type": "integer" }, "players_max": { "type": "integer" }, "latency_ms": { "type": "number" } } }, "scope": { "type": "string" } } } } } ``` ## GET /api/v1/servers List saved online or stale servers. Lists latest saved observations. By default returns online and stale entries. Age and player filters apply to the latest snapshot. Filtered cursors are tied to the original filters and snapshot cutoff and expire after 24 hours. OpenAPI operationId: `getSavedServers`. ### Parameters | Name | Location | Required | Type | Constraints/default | Meaning | | --- | --- | --- | --- | --- | --- | | `limit` | query | no | integer | default=50; minimum=1; maximum=100 | — | | `cursor` | query | no | string | maxLength=400 | Opaque nextCursor. Send the same filters and sort. Omit page when using cursor. | | `page` | query | no | integer | default=1; minimum=1; maximum=2147483647 | Page number, default 1. With limit=100, pages 1–10 can return 1,000 records. Continue with meta.nextPage; null means the last page. Do not combine page and cursor. | | `edition` | query | no | "java" / "bedrock" | — | Confirmed Minecraft edition. Unknown editions are excluded by this filter. | | `status` | query | no | "online" / "stale" / "offline" | — | Default: online or stale. Stale means no snapshot or the last online snapshot is more than 24 hours old. | | `min_players` | query | no | integer | minimum=0 | Minimum player count in the latest snapshot. | | `max_snapshot_age` | query | no | integer | minimum=1; maximum=2592000 | Maximum latest snapshot age in seconds. Requires a snapshot. | | `sort` | query | no | "id" / "players" / "recent" | default="id" | UUID ascending by default. Players and recent sort descending, breaking ties by ascending UUID. | ### Responses | HTTP | Meaning | Content type and schema | | --- | --- | --- | | 200 | Successful response | application/json: SavedServersResponse | | 400 | Invalid input | No response body schema specified | | 429 | Rate limit exceeded | No response body schema specified | | 500 | Internal error | No response body schema specified | | 503 | Temporary service unavailability, maintenance, or a status deadline. If present, wait for Retry-After. | application/json: ErrorResponse | HTTP 503 documented headers: `Retry-After` (string). Illustrative HTTP 503 example (example): ```json { "error": "Server status lookup timed out.", "reason_code": "LOOKUP_DEADLINE" } ``` ## POST /api/v1/status/bulk Check up to 50 Minecraft servers. Checks up to 50 servers per request with at most 10 different targets in flight. Results retain input order and include the single-status response and status_code. Offline results use item code 404 and internal failures 500; a valid batch returns HTTP 200. Limited to 6 requests per minute per IP. OpenAPI operationId: `getBulkServerStatus`. No endpoint-specific parameters are defined in the checked contract. ### Request body Body required: yes. Content-Type: `application/json`. Schema: BulkStatusRequest. ```json { "type": "object", "required": [ "servers" ], "properties": { "servers": { "type": "array", "minItems": 1, "maxItems": 50, "items": { "type": "object", "required": [ "address" ], "properties": { "address": { "type": "string", "minLength": 3, "maxLength": 255 }, "legacy": { "type": "boolean", "default": false }, "bedrock": { "type": "boolean", "default": false } }, "not": { "properties": { "legacy": { "const": true }, "bedrock": { "const": true } }, "required": [ "legacy", "bedrock" ] } } } } } ``` ### Responses | HTTP | Meaning | Content type and schema | | --- | --- | --- | | 200 | Successful response | application/json: BulkStatusResponse | | 400 | Invalid input | No response body schema specified | | 413 | JSON body exceeds 40 KiB | No response body schema specified | | 429 | Rate limit exceeded | No response body schema specified | | 500 | Internal error | No response body schema specified | | 503 | Temporary service unavailability, maintenance, or a status deadline. If present, wait for Retry-After. | application/json: ErrorResponse | HTTP 503 documented headers: `Retry-After` (string). Illustrative HTTP 503 example (example): ```json { "error": "Server status lookup timed out.", "reason_code": "LOOKUP_DEADLINE" } ``` ## GET /api/v1/status Check API health. OpenAPI operationId: `getApiHealth`. No endpoint-specific parameters are defined in the checked contract. ### Responses | HTTP | Meaning | Content type and schema | | --- | --- | --- | | 200 | API is available | application/json: HealthResponse | | 429 | Per-minute request limit exceeded | application/json: ErrorResponse | | 503 | Temporary service unavailability, maintenance, or a status deadline. If present, wait for Retry-After. | application/json: ErrorResponse | HTTP 429 documented headers: `Retry-After` (string). Illustrative HTTP 429 example (example): ```json { "status": "error", "error": "Rate limit exceeded, retry in 1 minute" } ``` HTTP 503 documented headers: `Retry-After` (string). Illustrative HTTP 503 example (example): ```json { "error": "Server status lookup timed out.", "reason_code": "LOOKUP_DEADLINE" } ``` ## GET /api/v1/status/{address} Get Minecraft server status. Queries a public Java, legacy Java or Bedrock target. Cached results preserve observation and attempt times. A stale 200 contains the last successful result after a failed refresh. An offline 404 means no usable result is available. Use the JSON reason_code to distinguish failures. OpenAPI operationId: `getMinecraftServerStatus`. ### Parameters | Name | Location | Required | Type | Constraints/default | Meaning | | --- | --- | --- | --- | --- | --- | | `address` | path | yes | string | — | Public hostname or IP with an optional port. Enclose IPv6 in square brackets. An explicit port bypasses Java SRV. | | `legacy` | query | no | boolean | default=false | Use the legacy Java ping protocol. | | `bedrock` | query | no | boolean | default=false | Use the Minecraft Bedrock Edition protocol. | | `edition` | query | no | "java" / "bedrock" / "legacy" / "auto" | — | Auto tries both Java and Bedrock with separate default ports when omitted. Use edition or the legacy/bedrock flags. | | `fields` | query | no | string | — | Comma-separated selection: online, stale, players, version, motd, favicon, roundTripLatency, reason_code, observed_at, last_attempt_at, cache_expires_at, checked_at, server_id, query, mods, plugins, software. Online, stale, reason_code and the three freshness timestamps are always included in a successful projected response. | | `query` | query | no | boolean | default=false | Try Java UDP Query on the effective status endpoint. Plugins and software appear only if provided. | ### Responses | HTTP | Meaning | Content type and schema | | --- | --- | --- | | 200 | Full status or selected fields. A stale result is explicitly flagged. | application/json: ServerStatus or CompactServerStatus | | 400 | Invalid address or query parameter | application/json: ErrorResponse | | 404 | No usable Minecraft status. DNS failure and timeout are distinguishable through reason_code. | application/json: ErrorResponse and object | | 429 | Per-minute request limit exceeded | application/json: ErrorResponse | | 503 | Temporary service unavailability, maintenance, or a status deadline. If present, wait for Retry-After. | application/json: ErrorResponse | Illustrative HTTP 200 example (fresh): ```json { "online": true, "stale": false, "reason_code": null, "observed_at": "2026-11-08T12:00:00.000Z", "last_attempt_at": "2026-11-08T12:00:00.000Z", "cache_expires_at": "2026-11-08T12:01:00.000Z", "players": { "online": 20, "max": 100 } } ``` Illustrative HTTP 200 example (stale): ```json { "online": true, "stale": true, "reason_code": "TIMEOUT", "observed_at": "2026-11-08T12:00:00.000Z", "last_attempt_at": "2026-11-08T12:05:00.000Z", "cache_expires_at": "2026-11-08T12:05:15.000Z", "players": { "online": 20, "max": 100 } } ``` Illustrative HTTP 404 example (dns): ```json { "error": "DNS_LOOKUP_FAILED", "online": false, "stale": false, "reason_code": "DNS_NO_RECORD", "observed_at": null, "last_attempt_at": "2026-11-08T12:00:00.000Z", "cache_expires_at": "2026-11-08T12:01:00.000Z" } ``` Illustrative HTTP 404 example (timeout): ```json { "error": "Minecraft server did not return a usable status.", "online": false, "stale": false, "reason_code": "TIMEOUT", "observed_at": null, "last_attempt_at": "2026-11-08T12:00:00.000Z", "cache_expires_at": "2026-11-08T12:01:00.000Z" } ``` HTTP 429 documented headers: `Retry-After` (string). Illustrative HTTP 429 example (example): ```json { "status": "error", "error": "Rate limit exceeded, retry in 1 minute" } ``` HTTP 503 documented headers: `Retry-After` (string). Illustrative HTTP 503 example (example): ```json { "error": "Server status lookup timed out.", "reason_code": "LOOKUP_DEADLINE" } ``` ## GET /api/v1/trends/indexable Indexable trend server profiles. Up to 1000 unique server addresses with trend score >= 400, a calculation and latest online snapshot within 2 hours. Used by the dynamic server sitemap. Cached for up to 5 minutes. This endpoint does not submit URLs to Google or guarantee indexing. No endpoint-specific parameters are defined in the checked contract. ### Responses | HTTP | Meaning | Content type and schema | | --- | --- | --- | | 200 | Eligible profiles | application/json: object | | 429 | Per-minute request limit exceeded | application/json: ErrorResponse | | 503 | Temporary service unavailability, maintenance, or a status deadline. If present, wait for Retry-After. | application/json: ErrorResponse | HTTP 200 application/json inline schema: ```json { "type": "object", "properties": { "minimum_score": { "type": "number", "example": 400 }, "data": { "type": "array", "items": { "type": "object", "properties": { "address": { "type": "string" }, "bedrock": { "type": "boolean" }, "trend_score": { "type": "number" }, "updated_at": { "type": "string", "format": "date-time" } } } } } } ``` HTTP 429 documented headers: `Retry-After` (string). Illustrative HTTP 429 example (example): ```json { "status": "error", "error": "Rate limit exceeded, retry in 1 minute" } ``` HTTP 503 documented headers: `Retry-After` (string). Illustrative HTTP 503 example (example): ```json { "error": "Server status lookup timed out.", "reason_code": "LOOKUP_DEADLINE" } ``` ## GET /api/v1/trends List recently verified online servers. Returns servers ranked by trend score with page or cursor pagination. Protocol-verified servers discovered from external lists are included. Scores combine user interest, observed player population and availability. Automated checks do not count as user queries. Daily growth compares user queries in the last complete 24 hours with the preceding 24 hours; a missing baseline returns 0. Scores refresh at startup and every 15 minutes. OpenAPI operationId: `getTrendingServers`. ### Parameters | Name | Location | Required | Type | Constraints/default | Meaning | | --- | --- | --- | --- | --- | --- | | `limit` | query | no | integer | default=10; minimum=1; maximum=50 | Page size from 1 to 50. | | `cursor` | query | no | string | format="uuid" | Cursor returned by the previous response. | | `page` | query | no | integer | default=1; minimum=1; maximum=2147483647 | Page number, default 1. meta.nextPage points to the next page or is null at the end. Ordered by trend score, then server ID for ties. Do not combine page and cursor. | ### Responses | HTTP | Meaning | Content type and schema | | --- | --- | --- | | 200 | Trending verified servers | application/json: TrendResponse | | 400 | Invalid address or query parameter | application/json: ErrorResponse | | 429 | Per-minute request limit exceeded | application/json: ErrorResponse | | 503 | Temporary service unavailability, maintenance, or a status deadline. If present, wait for Retry-After. | application/json: ErrorResponse | HTTP 429 documented headers: `Retry-After` (string). Illustrative HTTP 429 example (example): ```json { "status": "error", "error": "Rate limit exceeded, retry in 1 minute" } ``` HTTP 503 documented headers: `Retry-After` (string). Illustrative HTTP 503 example (example): ```json { "error": "Server status lookup timed out.", "reason_code": "LOOKUP_DEADLINE" } ``` ## GET /api/v1/stats Get aggregate platform statistics. OpenAPI operationId: `getPlatformStatistics`. No endpoint-specific parameters are defined in the checked contract. ### Responses | HTTP | Meaning | Content type and schema | | --- | --- | --- | | 200 | Current aggregate statistics | application/json: Statistics | | 429 | Per-minute request limit exceeded | application/json: ErrorResponse | | 503 | Temporary service unavailability, maintenance, or a status deadline. If present, wait for Retry-After. | application/json: ErrorResponse | HTTP 429 documented headers: `Retry-After` (string). Illustrative HTTP 429 example (example): ```json { "status": "error", "error": "Rate limit exceeded, retry in 1 minute" } ``` HTTP 503 documented headers: `Retry-After` (string). Illustrative HTTP 503 example (example): ```json { "error": "Server status lookup timed out.", "reason_code": "LOOKUP_DEADLINE" } ``` ## GET /api/v1/icon/dynamic Get an optimized server icon. Returns the advertised server favicon or the branded MCAPI.TR fallback. OpenAPI operationId: `getServerIcon`. ### Parameters | Name | Location | Required | Type | Constraints/default | Meaning | | --- | --- | --- | --- | --- | --- | | `address` | query | yes | string | — | Public Minecraft server hostname or IP, optionally with a port. | | `size` | query | no | integer | default=80; minimum=16; maximum=256 | — | | `format` | query | no | "png" / "webp" | default="png" | — | | `bedrock` | query | no | boolean | default=false | — | | `legacy` | query | no | boolean | default=false | — | ### Responses | HTTP | Meaning | Content type and schema | | --- | --- | --- | | 200 | Server or branded fallback icon | image/png: string; image/webp: string | | 400 | Invalid address or query parameter | application/json: ErrorResponse | | 429 | Per-minute request limit exceeded | application/json: ErrorResponse | | 503 | Temporary service unavailability, maintenance, or a status deadline. If present, wait for Retry-After. | application/json: ErrorResponse | HTTP 429 documented headers: `Retry-After` (string). Illustrative HTTP 429 example (example): ```json { "status": "error", "error": "Rate limit exceeded, retry in 1 minute" } ``` HTTP 503 documented headers: `Retry-After` (string). Illustrative HTTP 503 example (example): ```json { "error": "Server status lookup timed out.", "reason_code": "LOOKUP_DEADLINE" } ``` ## GET /api/v1/icon/sharp Get a rounded PNG server icon. OpenAPI operationId: `getRoundedServerIcon`. ### Parameters | Name | Location | Required | Type | Constraints/default | Meaning | | --- | --- | --- | --- | --- | --- | | `address` | query | yes | string | — | Public Minecraft server hostname or IP, optionally with a port. | | `size` | query | no | integer | default=128; minimum=32; maximum=512 | — | | `bedrock` | query | no | boolean | default=false | — | | `legacy` | query | no | boolean | default=false | — | ### Responses | HTTP | Meaning | Content type and schema | | --- | --- | --- | | 200 | Rounded server icon | image/png: string | | 400 | Invalid address or query parameter | application/json: ErrorResponse | | 429 | Per-minute request limit exceeded | application/json: ErrorResponse | | 503 | Temporary service unavailability, maintenance, or a status deadline. If present, wait for Retry-After. | application/json: ErrorResponse | HTTP 429 documented headers: `Retry-After` (string). Illustrative HTTP 429 example (example): ```json { "status": "error", "error": "Rate limit exceeded, retry in 1 minute" } ``` HTTP 503 documented headers: `Retry-After` (string). Illustrative HTTP 503 example (example): ```json { "error": "Server status lookup timed out.", "reason_code": "LOOKUP_DEADLINE" } ``` ## GET /api/v1/banner/{address} Generate a Minecraft server status banner. OpenAPI operationId: `getServerBanner`. ### Parameters | Name | Location | Required | Type | Constraints/default | Meaning | | --- | --- | --- | --- | --- | --- | | `address` | path | yes | string | — | — | | `size` | query | no | "small" / "normal" / "large" | default="normal" | — | | `style` | query | no | "modern" / "classic" / "panorama" | default="modern" | — | | `textColor` | query | no | string | pattern="^#?[0-9a-fA-F]{6}$" | — | | `accentColor` | query | no | string | pattern="^#?[0-9a-fA-F]{6}$" | — | | `showFavicon` | query | no | boolean | default=true | — | | `showMotd` | query | no | boolean | default=true | — | | `showPing` | query | no | boolean | default=true | — | | `borderRadius` | query | no | number | default=0.5; minimum=0 | — | | `layout` | query | no | string | format="uuid" | UUID of an immutable public design created in the banner editor. Overrides the ready-made style and size. | ### Responses | HTTP | Meaning | Content type and schema | | --- | --- | --- | | 200 | PNG status banner | image/png: string | | 400 | Invalid address or query parameter | application/json: ErrorResponse | | 429 | Per-minute request limit exceeded | application/json: ErrorResponse | | 503 | Temporary service unavailability, maintenance, or a status deadline. If present, wait for Retry-After. | application/json: ErrorResponse | HTTP 429 documented headers: `Retry-After` (string). Illustrative HTTP 429 example (example): ```json { "status": "error", "error": "Rate limit exceeded, retry in 1 minute" } ``` HTTP 503 documented headers: `Retry-After` (string). Illustrative HTTP 503 example (example): ```json { "error": "Server status lookup timed out.", "reason_code": "LOOKUP_DEADLINE" } ``` ## GET /api/v1/banner/motd Render Minecraft-formatted MOTD text as a PNG banner. OpenAPI operationId: `getMotdBanner`. ### Parameters | Name | Location | Required | Type | Constraints/default | Meaning | | --- | --- | --- | --- | --- | --- | | `motd` | query | yes | string | maxLength=300 | — | | `textColor` | query | no | string | pattern="^#?[0-9a-fA-F]{6}$" | — | | `accentColor` | query | no | string | pattern="^#?[0-9a-fA-F]{6}$" | — | ### Responses | HTTP | Meaning | Content type and schema | | --- | --- | --- | | 200 | PNG MOTD banner | image/png: string | | 400 | Invalid address or query parameter | application/json: ErrorResponse | | 429 | Per-minute request limit exceeded | application/json: ErrorResponse | | 503 | Temporary service unavailability, maintenance, or a status deadline. If present, wait for Retry-After. | application/json: ErrorResponse | HTTP 429 documented headers: `Retry-After` (string). Illustrative HTTP 429 example (example): ```json { "status": "error", "error": "Rate limit exceeded, retry in 1 minute" } ``` HTTP 503 documented headers: `Retry-After` (string). Illustrative HTTP 503 example (example): ```json { "error": "Server status lookup timed out.", "reason_code": "LOOKUP_DEADLINE" } ``` ## GET /api/v1/widget/{size}/{address} Get an embeddable server status widget. OpenAPI operationId: `getServerWidget`. ### Parameters | Name | Location | Required | Type | Constraints/default | Meaning | | --- | --- | --- | --- | --- | --- | | `size` | path | yes | "small" / "normal" / "large" | — | — | | `address` | path | yes | string | — | — | | `theme` | query | no | "dark" / "light" | default="dark" | — | | `showPlayers` | query | no | boolean | default=true | — | | `showVersion` | query | no | boolean | default=true | — | | `showMotd` | query | no | boolean | default=true | — | | `showLatency` | query | no | boolean | default=true | — | | `showFavicon` | query | no | boolean | default=true | — | | `bgColor` | query | no | string | pattern="^#?[0-9a-fA-F]{6}$" | — | | `textColor` | query | no | string | pattern="^#?[0-9a-fA-F]{6}$" | — | | `statusIndicator` | query | no | "dot" / "text" / "badge" / "none" | default="dot" | — | | `customHeight` | query | no | integer | minimum=50; maximum=600 | — | | `layout` | query | no | "card" / "compact" / "terminal" | default="card" | Widget layout; existing size, colour and visibility parameters remain supported. | | `lang` | query | no | "en" / "tr" / "de" / "es" | default="en" | — | | `refreshInterval` | query | no | integer | default=60; minimum=0; maximum=300 | Seconds between updates. Zero disables refresh; nonzero values are at least 60 seconds. Hidden or focused widgets pause refresh. | ### Responses | HTTP | Meaning | Content type and schema | | --- | --- | --- | | 200 | Embeddable HTML widget | text/html: string | | 400 | Invalid address or query parameter | application/json: ErrorResponse | | 429 | Per-minute request limit exceeded | application/json: ErrorResponse | | 503 | Temporary service unavailability, maintenance, or a status deadline. If present, wait for Retry-After. | application/json: ErrorResponse | HTTP 429 documented headers: `Retry-After` (string). Illustrative HTTP 429 example (example): ```json { "status": "error", "error": "Rate limit exceeded, retry in 1 minute" } ``` HTTP 503 documented headers: `Retry-After` (string). Illustrative HTTP 503 example (example): ```json { "error": "Server status lookup timed out.", "reason_code": "LOOKUP_DEADLINE" } ``` ## POST /api/v1/banner-designs Save an immutable public banner design. Creates a shareable design. Identical designs are deduplicated. Maximum 24 layers, 3 embedded images and 512 KB request body. Limited to 12 saves per IP per hour. Drafts can also be exported locally without saving. No endpoint-specific parameters are defined in the checked contract. ### Request body Body required: yes. Content-Type: `application/json`. Schema: object. ```json { "type": "object", "required": [ "name", "document" ], "properties": { "name": { "type": "string", "maxLength": 80 }, "document": { "type": "object", "description": "Version 1 banner document exported by /banner-editor. No remote image URLs or scripts are supported." } } } ``` ### Responses | HTTP | Meaning | Content type and schema | | --- | --- | --- | | 201 | Saved design with UUID and normalized document | No response body schema specified | | 400 | Invalid layout or image | No response body schema specified | | 429 | Save rate limit | No response body schema specified | | 503 | Storage unavailable | No response body schema specified | ## GET /api/v1/banner-designs/{id} Read a saved public design for viewing or remixing. ### Parameters | Name | Location | Required | Type | Constraints/default | Meaning | | --- | --- | --- | --- | --- | --- | | `id` | path | yes | string | format="uuid" | — | ### Responses | HTTP | Meaning | Content type and schema | | --- | --- | --- | | 200 | Immutable design document | No response body schema specified | | 404 | Unknown design | No response body schema specified | | 429 | Per-minute request limit exceeded | application/json: ErrorResponse | | 503 | Temporary service unavailability, maintenance, or a status deadline. If present, wait for Retry-After. | application/json: ErrorResponse | HTTP 429 documented headers: `Retry-After` (string). Illustrative HTTP 429 example (example): ```json { "status": "error", "error": "Rate limit exceeded, retry in 1 minute" } ``` HTTP 503 documented headers: `Retry-After` (string). Illustrative HTTP 503 example (example): ```json { "error": "Server status lookup timed out.", "reason_code": "LOOKUP_DEADLINE" } ``` ## POST /api/v1/banner-designs/render Export a design as PNG without saving it. POST {address, document}. Dynamic fields use the requested Minecraft server status. 20 renders per IP per minute. No endpoint-specific parameters are defined in the checked contract. ### Request body Body required: yes. Content-Type: `application/json`. Schema: object. ```json { "type": "object", "required": [ "address", "document" ], "properties": { "address": { "type": "string" }, "document": { "type": "object" } } } ``` ### Responses | HTTP | Meaning | Content type and schema | | --- | --- | --- | | 200 | PNG image | image/png: string | | 400 | Invalid parameters | No response body schema specified | | 429 | Render rate limit | No response body schema specified | | 503 | Temporary service unavailability, maintenance, or a status deadline. If present, wait for Retry-After. | application/json: ErrorResponse | HTTP 503 documented headers: `Retry-After` (string). Illustrative HTTP 503 example (example): ```json { "error": "Server status lookup timed out.", "reason_code": "LOOKUP_DEADLINE" } ``` ## GET /api/v1/badge/{address} Get a cacheable SVG status badge. A valid but unreachable target produces a 200 SVG showing Offline. Stale data is labeled Stale. Add alt text to the embedding image. OpenAPI operationId: `getMinecraftStatusBadge`. ### Parameters | Name | Location | Required | Type | Constraints/default | Meaning | | --- | --- | --- | --- | --- | --- | | `address` | path | yes | string | — | Public hostname or IP with an optional port. Enclose IPv6 in square brackets. An explicit port bypasses Java SRV. | | `legacy` | query | no | boolean | default=false | Use the legacy Java ping protocol. | | `bedrock` | query | no | boolean | default=false | Use the Minecraft Bedrock Edition protocol. | | `edition` | query | no | "java" / "bedrock" / "legacy" / "auto" | — | Auto tries both Java and Bedrock with separate default ports when omitted. Use edition or the legacy/bedrock flags. | ### Responses | HTTP | Meaning | Content type and schema | | --- | --- | --- | | 200 | SVG badge | image/svg+xml: string | | 304 | Unchanged badge | No response body schema specified | | 400 | Invalid address or query parameter | application/json: ErrorResponse | | 429 | Per-minute request limit exceeded | application/json: ErrorResponse | | 503 | Temporary service unavailability, maintenance, or a status deadline. If present, wait for Retry-After. | application/json: ErrorResponse | HTTP 200 documented headers: `ETag` (string), `Cache-Control` (string). HTTP 429 documented headers: `Retry-After` (string). Illustrative HTTP 429 example (example): ```json { "status": "error", "error": "Rate limit exceeded, retry in 1 minute" } ``` HTTP 503 documented headers: `Retry-After` (string). Illustrative HTTP 503 example (example): ```json { "error": "Server status lookup timed out.", "reason_code": "LOOKUP_DEADLINE" } ``` ## GET /api/v1/service-status Get MCAPI service measurements and incident history. Seven-day observed availability and coverage. Health and PNG are checked on the public service; Java and Bedrock use controlled local fixtures. Unmeasured slots are tracked separately. OpenAPI operationId: `getServiceStatus`. No endpoint-specific parameters are defined in the checked contract. ### Responses | HTTP | Meaning | Content type and schema | | --- | --- | --- | | 200 | Current measurement summary | application/json: object | | 429 | Per-minute request limit exceeded | application/json: ErrorResponse | | 503 | Temporary service unavailability, maintenance, or a status deadline. If present, wait for Retry-After. | application/json: ErrorResponse | HTTP 200 application/json inline schema: ```json { "type": "object", "required": [ "measured_at", "window_start", "window_days", "interval_seconds", "expected_samples", "components", "incidents" ], "properties": { "measured_at": { "type": "string", "format": "date-time" }, "window_start": { "type": "string", "format": "date-time" }, "window_days": { "const": 7 }, "interval_seconds": { "const": 300 }, "expected_samples": { "const": 2016 }, "components": { "type": "object" }, "incidents": { "type": "array", "items": { "type": "object" } } } } ``` HTTP 429 documented headers: `Retry-After` (string). Illustrative HTTP 429 example (example): ```json { "status": "error", "error": "Rate limit exceeded, retry in 1 minute" } ``` HTTP 503 documented headers: `Retry-After` (string). Illustrative HTTP 503 example (example): ```json { "error": "Server status lookup timed out.", "reason_code": "LOOKUP_DEADLINE" } ``` ## Shared JSON data models These model definitions are taken from the checked OpenAPI snapshot. Optional and nullable values are distinct: a missing property and a present null value must both be handled where the contract allows them. Models with additionalProperties permit extra fields. Refer to the expanded contract for nested details and combined constraints. ### SavedServersResponse Type: object. | Field | Required | Type/model | Constraints | Description | | --- | --- | --- | --- | --- | | `success` | yes | true | — | — | | `data` | yes | array of object | — | — | | `meta` | yes | object | — | — | Additional fields: not restricted at this level in the schema. ### BulkStatusRequest Type: object. | Field | Required | Type/model | Constraints | Description | | --- | --- | --- | --- | --- | | `servers` | yes | array of object | minItems=1; maxItems=50 | — | Additional fields: not restricted at this level in the schema. ### BulkStatusResponse Type: object. | Field | Required | Type/model | Constraints | Description | | --- | --- | --- | --- | --- | | `success` | yes | true | — | — | | `data` | yes | array of object | — | — | | `meta` | yes | object | — | — | Additional fields: not restricted at this level in the schema. ### HealthResponse Type: object. | Field | Required | Type/model | Constraints | Description | | --- | --- | --- | --- | --- | | `status` | yes | "OK" | — | — | | `timestamp` | yes | string | format="date-time" | — | | `service` | yes | string | — | — | | `version` | yes | string | — | — | Additional fields: not restricted at this level in the schema. ### ErrorResponse Type: object. | Field | Required | Type/model | Constraints | Description | | --- | --- | --- | --- | --- | | `status` | no | string | — | — | | `error` | no | string | — | — | | `message` | no | string | — | — | | `reason_code` | no | string or null | — | — | Additional fields: allowed. ### Query Type: object. | Field | Required | Type/model | Constraints | Description | | --- | --- | --- | --- | --- | | `host` | no | string | — | — | | `port` | no | integer | — | — | | `legacy` | no | boolean | — | — | | `bedrock` | no | boolean | — | — | | `edition` | no | "java" / "bedrock" / "legacy" | — | — | Additional fields: not restricted at this level in the schema. ### Players Type: object or null. | Field | Required | Type/model | Constraints | Description | | --- | --- | --- | --- | --- | | `online` | no | integer | minimum=0 | — | | `max` | no | integer | minimum=0 | — | | `sample` | no | array of object | — | — | Additional fields: not restricted at this level in the schema. ### Motd Type: object or null. | Field | Required | Type/model | Constraints | Description | | --- | --- | --- | --- | --- | | `raw` | no | string | — | — | | `clean` | no | string | — | — | | `html` | no | string | — | — | | `raw_lines` | no | array of string | — | — | | `clean_lines` | no | array of string | — | — | | `html_lines` | no | array of string | — | — | Additional fields: not restricted at this level in the schema. ### ServerStatus Type: object. | Field | Required | Type/model | Constraints | Description | | --- | --- | --- | --- | --- | | `query` | yes | Query | — | — | | `server_id` | no | string or null | format="uuid" | — | | `ip_address` | no | string or null | — | — | | `icmp` | no | boolean or null | — | — | | `online` | yes | boolean | — | — | | `error` | no | string or null | — | — | | `version` | no | object or null | — | — | | `players` | no | Players | — | — | | `motd` | no | Motd | — | — | | `favicon` | no | string or null | — | Data URL when advertised by the server. | | `roundTripLatency` | no | number or null | minimum=0 | — | | `stale` | no | boolean | — | — | | `checked_at` | no | string | format="date-time" | — | | `srvRecord` | no | object or null | — | — | | `observed_at` | yes | string or null | format="date-time" | Time of the last successful observation, if known. | | `last_attempt_at` | yes | string | format="date-time" | Completion time of the most recent probe attempt. | | `cache_expires_at` | yes | string | format="date-time" | Scheduled expiry of this cached response. | | `reason_code` | yes | null / "PRIVATE_TARGET" / "DNS_NO_RECORD" / "DNS_TIMEOUT" / "DNS_ERROR" / "SRV_UNAVAILABLE" / "SRV_LOOKUP_ERROR" / "CONNECTION_REFUSED" / "CONNECTION_CLOSED" / "NETWORK_ERROR" / "TIMEOUT" / "UDP_NO_RESPONSE" / "INVALID_RESPONSE" | — | Machine-readable cause of the latest failed attempt; null on success. | | `mods` | no | array of string | — | — | | `plugins` | no | array of string | — | — | | `software` | no | string | — | — | | `latency_source` | no | "pong" / "status" | — | — | | `target` | no | object | — | — | Additional fields: allowed. ### TrendServer Type: object. | Field | Required | Type/model | Constraints | Description | | --- | --- | --- | --- | --- | | `server_id` | no | string | format="uuid" | — | | `hostname` | yes | string | — | — | | `address` | no | string | — | — | | `port` | yes | integer | — | — | | `edition` | no | "java" / "bedrock" | — | — | | `trend_score` | no | number | — | — | | `daily_growth` | no | number | — | Percentage change between two complete 24-hour query-count windows. May be negative. Returns 0 without a previous-period baseline. | | `is_online` | yes | true | — | — | | `stale` | yes | false | — | — | | `checked_at` | no | string | format="date-time" | — | | `players_online` | no | integer | — | — | | `players_max` | no | integer | — | — | | `version` | no | string or null | — | — | | `favicon` | no | string or null | — | Stored favicon hash used by the icon endpoint. | | `record_players` | no | integer | — | — | | `uptime_percentage` | no | number | — | — | Additional fields: allowed. ### TrendResponse Type: object. | Field | Required | Type/model | Constraints | Description | | --- | --- | --- | --- | --- | | `success` | yes | true | — | — | | `data` | yes | array of TrendServer | — | — | | `meta` | yes | object | — | — | Additional fields: not restricted at this level in the schema. ### Statistics Type: object. | Field | Required | Type/model | Constraints | Description | | --- | --- | --- | --- | --- | | `totalRequests` | no | integer | — | — | | `apiRequests` | no | integer | — | — | | `serverQueries` | no | integer | — | — | | `totalChecks` | no | integer | — | — | | `onlineServers` | no | integer | — | — | | `offlineServers` | no | integer | — | — | | `activePlayers` | no | integer | — | — | | `onlineRate` | no | number | — | — | Additional fields: allowed. ### CompactServerStatus Type: object. | Field | Required | Type/model | Constraints | Description | | --- | --- | --- | --- | --- | | `online` | yes | boolean | — | — | | `stale` | yes | boolean | — | — | | `players` | no | Players | — | — | | `version` | no | object or null | — | — | | `motd` | no | Motd | — | — | | `favicon` | no | string or null | — | Data URL when advertised by the server. | | `roundTripLatency` | no | number or null | minimum=0 | — | | `reason_code` | yes | null / "PRIVATE_TARGET" / "DNS_NO_RECORD" / "DNS_TIMEOUT" / "DNS_ERROR" / "SRV_UNAVAILABLE" / "SRV_LOOKUP_ERROR" / "CONNECTION_REFUSED" / "CONNECTION_CLOSED" / "NETWORK_ERROR" / "TIMEOUT" / "UDP_NO_RESPONSE" / "INVALID_RESPONSE" | — | Machine-readable cause of the latest failed attempt; null on success. | | `observed_at` | yes | string or null | format="date-time" | Time of the last successful observation, if known. | | `last_attempt_at` | yes | string | format="date-time" | Completion time of the most recent probe attempt. | | `cache_expires_at` | yes | string | format="date-time" | Scheduled expiry of this cached response. | | `checked_at` | no | string | format="date-time" | — | | `server_id` | no | string or null | format="uuid" | — | | `query` | no | Query | — | — | | `mods` | no | array of string | — | — | | `plugins` | no | array of string | — | — | | `software` | no | string | — | — | Additional fields: not allowed by this model. ## End of detailed reference Current contract: https://mcapi.tr/openapi.json Current service health: https://mcapi.tr/api/v1/status Current workload counters: https://mcapi.tr/api/v1/stats Current measurements: https://mcapi.tr/api/v1/service-status Expanded reference: https://mcapi.tr/llms-full.txt Updates: https://mcapi.tr/updates ## Complete checked OpenAPI 3.1 contract The following contract snapshot was fetched during this documentation update. Re-fetch the canonical URL for future revisions. ```json { "openapi": "3.1.0", "info": { "title": "MCAPI.TR Minecraft Server Status API", "version": "1.0.0", "description": "Free Minecraft Java and Bedrock server status API with player counts, latency, MOTD, version, icons, banners, widgets, trends and platform statistics. No account or API key is required.", "termsOfService": "https://mcapi.tr/terms", "contact": { "name": "MCAPI.TR", "url": "https://mcapi.tr/contact" }, "license": { "name": "Service terms", "identifier": "LicenseRef-MCAPI-TR-Terms" } }, "externalDocs": { "description": "Human-readable documentation and live playground", "url": "https://mcapi.tr/api-docs" }, "servers": [ { "url": "https://mcapi.tr/api/v1", "description": "Production API" } ], "tags": [ { "name": "Status", "description": "Minecraft server and API availability" }, { "name": "Discovery", "description": "Recently verified online servers and platform statistics" }, { "name": "Media", "description": "Server icons, banners, and widgets" } ], "paths": { "/history/{address}": { "get": { "tags": [ "Server data" ], "summary": "Saved server observation history", "description": "Read-only history from stored snapshots; never triggers a server probe. Snapshots are change-driven or hourly, not uniform samples. Missing buckets are unknown. observed_online_percentage is an observation ratio, not time-based uptime. Cached for 300 seconds; 30 requests per minute per IP.", "parameters": [ { "name": "address", "in": "path", "required": true, "description": "Public hostname or IP with optional port.", "schema": { "type": "string" } }, { "name": "period", "in": "query", "description": "History window.", "schema": { "type": "string", "enum": [ "24h", "7d", "30d" ], "default": "24h" } }, { "name": "bedrock", "in": "query", "description": "Use Bedrock default port 19132.", "schema": { "type": "boolean", "default": false } } ], "responses": { "200": { "description": "Observed history", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" }, "data": { "type": "object", "properties": { "server_id": { "type": "string" }, "address": { "type": "string" }, "period": { "type": "string" }, "from": { "type": "string", "format": "date-time" }, "to": { "type": "string", "format": "date-time" }, "bucket_seconds": { "type": "integer" }, "summary": { "type": "object", "properties": { "samples": { "type": "integer" }, "online_samples": { "type": "integer" }, "offline_samples": { "type": "integer" }, "observed_online_percentage": { "type": [ "number", "null" ] }, "peak_players": { "type": [ "number", "null" ] }, "covered_buckets": { "type": "integer" }, "total_buckets": { "type": "integer" }, "coverage_percentage": { "type": "number" } } }, "points": { "type": "array", "maxItems": 169, "items": { "type": "object", "properties": { "timestamp": { "type": "string", "format": "date-time" }, "samples": { "type": "integer" }, "online_samples": { "type": "integer" }, "offline_samples": { "type": "integer" }, "average_players": { "type": [ "number", "null" ] }, "min_players": { "type": [ "number", "null" ] }, "max_players": { "type": [ "number", "null" ] }, "average_ping": { "type": [ "number", "null" ] } } } }, "transitions": { "type": "array", "maxItems": 12, "items": { "type": "object", "properties": { "timestamp": { "type": "string", "format": "date-time" }, "online": { "type": "boolean" } } } }, "measurement": { "type": "string" } } } } } } } }, "400": { "description": "Invalid address, period or query parameter" }, "404": { "description": "Address is not in the saved catalog" }, "429": { "description": "Rate limit exceeded" }, "503": { "description": "History temporarily unavailable" } }, "x-rate-limit": { "requests": 30, "window_seconds": 60, "scope": "ip" } } }, "/diagnostics/{address}": { "get": { "tags": [ "Tools" ], "summary": "Bounded connection diagnostics", "description": "On-demand DNS/SRV, public-IP-pinned connectivity and Minecraft status protocol check. Java, Bedrock and Legacy supported. Private/reserved targets are blocked; explicit ports bypass Java SRV. Timeouts are inconclusive, not proof of an outage. No player login/authentication/whitelist test. Results cached for 300 seconds; 6 requests per minute per IP and 4 concurrent uncached checks per API process. Does not record snapshots or user-query trend events.", "parameters": [ { "name": "address", "in": "path", "required": true, "description": "Public hostname or IP with optional port.", "schema": { "type": "string" } }, { "name": "edition", "in": "query", "description": "Minecraft protocol.", "schema": { "type": "string", "enum": [ "java", "bedrock", "legacy" ], "default": "java" } } ], "responses": { "200": { "description": "Diagnostic report, including blocked or inconclusive outcomes", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" }, "data": { "type": "object", "properties": { "address": { "type": "string" }, "edition": { "type": "string" }, "state": { "type": "string", "enum": [ "reachable", "unreachable", "inconclusive", "blocked" ] }, "checked_at": { "type": "string", "format": "date-time" }, "duration_ms": { "type": "number" }, "target": { "type": "object", "properties": { "host": { "type": "string" }, "port": { "type": "integer" } } }, "steps": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "state": { "type": "string", "enum": [ "ok", "warning", "failed", "unknown", "skipped" ] }, "code": { "type": "string" }, "details": { "type": "object" } } } }, "server": { "type": "object", "properties": { "connected": { "type": "boolean" }, "valid": { "type": "boolean" }, "version": { "type": "string" }, "players_online": { "type": "integer" }, "players_max": { "type": "integer" }, "latency_ms": { "type": "number" } } }, "scope": { "type": "string" } } } } } } } }, "400": { "description": "Invalid public target or protocol" }, "429": { "description": "Rate or diagnostic concurrency limit exceeded. Retry-After may be supplied." }, "503": { "description": "Diagnostics temporarily unavailable" } }, "x-rate-limit": { "requests": 6, "window_seconds": 60, "scope": "ip" } } }, "/servers": { "get": { "operationId": "getSavedServers", "tags": [ "Discovery" ], "summary": "List saved online or stale servers", "description": "Lists latest saved observations. By default returns online and stale entries. Age and player filters apply to the latest snapshot. Filtered cursors are tied to the original filters and snapshot cutoff and expire after 24 hours.", "parameters": [ { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 } }, { "name": "cursor", "in": "query", "schema": { "type": "string", "maxLength": 400 }, "description": "Opaque nextCursor. Send the same filters and sort. Omit page when using cursor." }, { "name": "page", "in": "query", "description": "Page number, default 1. With limit=100, pages 1–10 can return 1,000 records. Continue with meta.nextPage; null means the last page. Do not combine page and cursor.", "schema": { "type": "integer", "minimum": 1, "maximum": 2147483647, "default": 1 } }, { "name": "edition", "in": "query", "schema": { "enum": [ "java", "bedrock" ] }, "description": "Confirmed Minecraft edition. Unknown editions are excluded by this filter." }, { "name": "status", "in": "query", "schema": { "enum": [ "online", "stale", "offline" ] }, "description": "Default: online or stale. Stale means no snapshot or the last online snapshot is more than 24 hours old." }, { "name": "min_players", "in": "query", "schema": { "type": "integer", "minimum": 0 }, "description": "Minimum player count in the latest snapshot." }, { "name": "max_snapshot_age", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 2592000 }, "description": "Maximum latest snapshot age in seconds. Requires a snapshot." }, { "name": "sort", "in": "query", "schema": { "enum": [ "id", "players", "recent" ], "default": "id" }, "description": "UUID ascending by default. Players and recent sort descending, breaking ties by ascending UUID." } ], "responses": { "200": { "description": "Successful response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SavedServersResponse" } } } }, "400": { "description": "Invalid input" }, "429": { "description": "Rate limit exceeded" }, "500": { "description": "Internal error" }, "503": { "$ref": "#/components/responses/TemporarilyUnavailable" } }, "x-rate-limit": { "requests": 60, "window_seconds": 60, "scope": "ip" } } }, "/status/bulk": { "post": { "operationId": "getBulkServerStatus", "tags": [ "Status" ], "summary": "Check up to 50 Minecraft servers", "description": "Checks up to 50 servers per request with at most 10 different targets in flight. Results retain input order and include the single-status response and status_code. Offline results use item code 404 and internal failures 500; a valid batch returns HTTP 200. Limited to 6 requests per minute per IP.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BulkStatusRequest" } } } }, "responses": { "200": { "description": "Successful response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BulkStatusResponse" } } } }, "400": { "description": "Invalid input" }, "413": { "description": "JSON body exceeds 40 KiB" }, "429": { "description": "Rate limit exceeded" }, "500": { "description": "Internal error" }, "503": { "$ref": "#/components/responses/TemporarilyUnavailable" } }, "x-rate-limit": { "requests": 6, "window_seconds": 60, "scope": "ip" } } }, "/status": { "get": { "operationId": "getApiHealth", "summary": "Check API health", "tags": [ "Status" ], "responses": { "200": { "description": "API is available", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HealthResponse" } } } }, "429": { "$ref": "#/components/responses/RateLimited" }, "503": { "$ref": "#/components/responses/TemporarilyUnavailable" } }, "x-rate-limit": { "requests": 300, "window_seconds": 60, "scope": "ip", "configurable": true } } }, "/status/{address}": { "get": { "operationId": "getMinecraftServerStatus", "summary": "Get Minecraft server status", "description": "Queries a public Java, legacy Java or Bedrock target. Cached results preserve observation and attempt times. A stale 200 contains the last successful result after a failed refresh. An offline 404 means no usable result is available. Use the JSON reason_code to distinguish failures.", "tags": [ "Status" ], "parameters": [ { "name": "address", "in": "path", "required": true, "description": "Public hostname or IP with an optional port. Enclose IPv6 in square brackets. An explicit port bypasses Java SRV.", "schema": { "type": "string", "examples": [ "mc.hypixel.net", "play.example.net:19132", "[2606:4700::1001]:25565" ] } }, { "name": "legacy", "in": "query", "description": "Use the legacy Java ping protocol.", "schema": { "type": "boolean", "default": false } }, { "name": "bedrock", "in": "query", "description": "Use the Minecraft Bedrock Edition protocol.", "schema": { "type": "boolean", "default": false } }, { "name": "edition", "in": "query", "schema": { "enum": [ "java", "bedrock", "legacy", "auto" ] }, "description": "Auto tries both Java and Bedrock with separate default ports when omitted. Use edition or the legacy/bedrock flags." }, { "name": "fields", "in": "query", "schema": { "type": "string", "examples": [ "online,players,version" ] }, "description": "Comma-separated selection: online, stale, players, version, motd, favicon, roundTripLatency, reason_code, observed_at, last_attempt_at, cache_expires_at, checked_at, server_id, query, mods, plugins, software. Online, stale, reason_code and the three freshness timestamps are always included in a successful projected response." }, { "name": "query", "in": "query", "schema": { "type": "boolean", "default": false }, "description": "Try Java UDP Query on the effective status endpoint. Plugins and software appear only if provided." } ], "responses": { "200": { "description": "Full status or selected fields. A stale result is explicitly flagged.", "content": { "application/json": { "schema": { "anyOf": [ { "$ref": "#/components/schemas/ServerStatus" }, { "$ref": "#/components/schemas/CompactServerStatus" } ] }, "examples": { "fresh": { "value": { "online": true, "stale": false, "reason_code": null, "observed_at": "2026-11-08T12:00:00.000Z", "last_attempt_at": "2026-11-08T12:00:00.000Z", "cache_expires_at": "2026-11-08T12:01:00.000Z", "players": { "online": 20, "max": 100 } } }, "stale": { "value": { "online": true, "stale": true, "reason_code": "TIMEOUT", "observed_at": "2026-11-08T12:00:00.000Z", "last_attempt_at": "2026-11-08T12:05:00.000Z", "cache_expires_at": "2026-11-08T12:05:15.000Z", "players": { "online": 20, "max": 100 } } } } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "404": { "description": "No usable Minecraft status. DNS failure and timeout are distinguishable through reason_code.", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ErrorResponse" }, { "type": "object", "properties": { "observed_at": { "type": [ "string", "null" ], "format": "date-time", "description": "Time of the last successful observation, if known." }, "last_attempt_at": { "type": "string", "format": "date-time", "description": "Completion time of the most recent probe attempt." }, "cache_expires_at": { "type": "string", "format": "date-time", "description": "Scheduled expiry of this cached response." }, "reason_code": { "enum": [ null, "PRIVATE_TARGET", "DNS_NO_RECORD", "DNS_TIMEOUT", "DNS_ERROR", "SRV_UNAVAILABLE", "SRV_LOOKUP_ERROR", "CONNECTION_REFUSED", "CONNECTION_CLOSED", "NETWORK_ERROR", "TIMEOUT", "UDP_NO_RESPONSE", "INVALID_RESPONSE" ], "description": "Machine-readable cause of the latest failed attempt; null on success." }, "online": { "const": false }, "stale": { "const": false }, "checked_at": { "type": "string", "format": "date-time" } } } ] }, "examples": { "dns": { "value": { "error": "DNS_LOOKUP_FAILED", "online": false, "stale": false, "reason_code": "DNS_NO_RECORD", "observed_at": null, "last_attempt_at": "2026-11-08T12:00:00.000Z", "cache_expires_at": "2026-11-08T12:01:00.000Z" } }, "timeout": { "value": { "error": "Minecraft server did not return a usable status.", "online": false, "stale": false, "reason_code": "TIMEOUT", "observed_at": null, "last_attempt_at": "2026-11-08T12:00:00.000Z", "cache_expires_at": "2026-11-08T12:01:00.000Z" } } } } } }, "429": { "$ref": "#/components/responses/RateLimited" }, "503": { "$ref": "#/components/responses/TemporarilyUnavailable" } }, "x-rate-limit": { "requests": 120, "window_seconds": 60, "scope": "ip" } } }, "/trends/indexable": { "get": { "summary": "Indexable trend server profiles", "description": "Up to 1000 unique server addresses with trend score >= 400, a calculation and latest online snapshot within 2 hours. Used by the dynamic server sitemap. Cached for up to 5 minutes. This endpoint does not submit URLs to Google or guarantee indexing.", "tags": [ "Trends" ], "responses": { "200": { "description": "Eligible profiles", "content": { "application/json": { "schema": { "type": "object", "properties": { "minimum_score": { "type": "number", "example": 400 }, "data": { "type": "array", "items": { "type": "object", "properties": { "address": { "type": "string" }, "bedrock": { "type": "boolean" }, "trend_score": { "type": "number" }, "updated_at": { "type": "string", "format": "date-time" } } } } } } } } }, "429": { "$ref": "#/components/responses/RateLimited" }, "503": { "$ref": "#/components/responses/TemporarilyUnavailable" } }, "x-rate-limit": { "requests": 300, "window_seconds": 60, "scope": "ip", "configurable": true } } }, "/trends": { "get": { "operationId": "getTrendingServers", "description": "Returns servers ranked by trend score with page or cursor pagination. Protocol-verified servers discovered from external lists are included. Scores combine user interest, observed player population and availability. Automated checks do not count as user queries. Daily growth compares user queries in the last complete 24 hours with the preceding 24 hours; a missing baseline returns 0. Scores refresh at startup and every 15 minutes.", "summary": "List recently verified online servers", "tags": [ "Discovery" ], "parameters": [ { "name": "limit", "in": "query", "description": "Page size from 1 to 50.", "schema": { "type": "integer", "minimum": 1, "maximum": 50, "default": 10 } }, { "name": "cursor", "in": "query", "description": "Cursor returned by the previous response.", "schema": { "type": "string", "format": "uuid" } }, { "name": "page", "in": "query", "description": "Page number, default 1. meta.nextPage points to the next page or is null at the end. Ordered by trend score, then server ID for ties. Do not combine page and cursor.", "schema": { "type": "integer", "minimum": 1, "maximum": 2147483647, "default": 1 } } ], "responses": { "200": { "description": "Trending verified servers", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TrendResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "429": { "$ref": "#/components/responses/RateLimited" }, "503": { "$ref": "#/components/responses/TemporarilyUnavailable" } }, "x-rate-limit": { "requests": 300, "window_seconds": 60, "scope": "ip", "configurable": true } } }, "/stats": { "get": { "operationId": "getPlatformStatistics", "summary": "Get aggregate platform statistics", "tags": [ "Discovery" ], "responses": { "200": { "description": "Current aggregate statistics", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Statistics" } } } }, "429": { "$ref": "#/components/responses/RateLimited" }, "503": { "$ref": "#/components/responses/TemporarilyUnavailable" } }, "x-rate-limit": { "requests": 300, "window_seconds": 60, "scope": "ip", "configurable": true } } }, "/icon/dynamic": { "get": { "operationId": "getServerIcon", "summary": "Get an optimized server icon", "description": "Returns the advertised server favicon or the branded MCAPI.TR fallback.", "tags": [ "Media" ], "parameters": [ { "$ref": "#/components/parameters/AddressQuery" }, { "name": "size", "in": "query", "schema": { "type": "integer", "minimum": 16, "maximum": 256, "default": 80 } }, { "name": "format", "in": "query", "schema": { "type": "string", "enum": [ "png", "webp" ], "default": "png" } }, { "$ref": "#/components/parameters/BedrockQuery" }, { "$ref": "#/components/parameters/LegacyQuery" } ], "responses": { "200": { "description": "Server or branded fallback icon", "content": { "image/png": { "schema": { "type": "string", "contentEncoding": "binary" } }, "image/webp": { "schema": { "type": "string", "contentEncoding": "binary" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "429": { "$ref": "#/components/responses/RateLimited" }, "503": { "$ref": "#/components/responses/TemporarilyUnavailable" } }, "x-rate-limit": { "requests": 5000, "window_seconds": 60, "scope": "ip" } } }, "/icon/sharp": { "get": { "operationId": "getRoundedServerIcon", "summary": "Get a rounded PNG server icon", "tags": [ "Media" ], "parameters": [ { "$ref": "#/components/parameters/AddressQuery" }, { "name": "size", "in": "query", "schema": { "type": "integer", "minimum": 32, "maximum": 512, "default": 128 } }, { "$ref": "#/components/parameters/BedrockQuery" }, { "$ref": "#/components/parameters/LegacyQuery" } ], "responses": { "200": { "description": "Rounded server icon", "content": { "image/png": { "schema": { "type": "string", "contentEncoding": "binary" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "429": { "$ref": "#/components/responses/RateLimited" }, "503": { "$ref": "#/components/responses/TemporarilyUnavailable" } }, "x-rate-limit": { "requests": 5000, "window_seconds": 60, "scope": "ip" } } }, "/banner/{address}": { "get": { "operationId": "getServerBanner", "summary": "Generate a Minecraft server status banner", "tags": [ "Media" ], "parameters": [ { "name": "address", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "size", "in": "query", "schema": { "type": "string", "enum": [ "small", "normal", "large" ], "default": "normal" } }, { "name": "style", "in": "query", "schema": { "type": "string", "enum": [ "modern", "classic", "panorama" ], "default": "modern" } }, { "name": "textColor", "in": "query", "schema": { "type": "string", "pattern": "^#?[0-9a-fA-F]{6}$" } }, { "name": "accentColor", "in": "query", "schema": { "type": "string", "pattern": "^#?[0-9a-fA-F]{6}$" } }, { "name": "showFavicon", "in": "query", "schema": { "type": "boolean", "default": true } }, { "name": "showMotd", "in": "query", "schema": { "type": "boolean", "default": true } }, { "name": "showPing", "in": "query", "schema": { "type": "boolean", "default": true } }, { "name": "borderRadius", "in": "query", "schema": { "type": "number", "minimum": 0, "default": 0.5 } }, { "name": "layout", "in": "query", "description": "UUID of an immutable public design created in the banner editor. Overrides the ready-made style and size.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "PNG status banner", "content": { "image/png": { "schema": { "type": "string", "contentEncoding": "binary" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "429": { "$ref": "#/components/responses/RateLimited" }, "503": { "$ref": "#/components/responses/TemporarilyUnavailable" } }, "x-rate-limit": { "requests": 5000, "window_seconds": 60, "scope": "ip" } } }, "/banner/motd": { "get": { "operationId": "getMotdBanner", "summary": "Render Minecraft-formatted MOTD text as a PNG banner", "tags": [ "Media" ], "parameters": [ { "name": "motd", "in": "query", "required": true, "schema": { "type": "string", "maxLength": 300 } }, { "name": "textColor", "in": "query", "schema": { "type": "string", "pattern": "^#?[0-9a-fA-F]{6}$" } }, { "name": "accentColor", "in": "query", "schema": { "type": "string", "pattern": "^#?[0-9a-fA-F]{6}$" } } ], "responses": { "200": { "description": "PNG MOTD banner", "content": { "image/png": { "schema": { "type": "string", "contentEncoding": "binary" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "429": { "$ref": "#/components/responses/RateLimited" }, "503": { "$ref": "#/components/responses/TemporarilyUnavailable" } }, "x-rate-limit": { "requests": 5000, "window_seconds": 60, "scope": "ip" } } }, "/widget/{size}/{address}": { "get": { "operationId": "getServerWidget", "summary": "Get an embeddable server status widget", "tags": [ "Media" ], "parameters": [ { "name": "size", "in": "path", "required": true, "schema": { "type": "string", "enum": [ "small", "normal", "large" ] } }, { "name": "address", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "theme", "in": "query", "schema": { "type": "string", "enum": [ "dark", "light" ], "default": "dark" } }, { "name": "showPlayers", "in": "query", "schema": { "type": "boolean", "default": true } }, { "name": "showVersion", "in": "query", "schema": { "type": "boolean", "default": true } }, { "name": "showMotd", "in": "query", "schema": { "type": "boolean", "default": true } }, { "name": "showLatency", "in": "query", "schema": { "type": "boolean", "default": true } }, { "name": "showFavicon", "in": "query", "schema": { "type": "boolean", "default": true } }, { "name": "bgColor", "in": "query", "schema": { "type": "string", "pattern": "^#?[0-9a-fA-F]{6}$" } }, { "name": "textColor", "in": "query", "schema": { "type": "string", "pattern": "^#?[0-9a-fA-F]{6}$" } }, { "name": "statusIndicator", "in": "query", "schema": { "type": "string", "enum": [ "dot", "text", "badge", "none" ], "default": "dot" } }, { "name": "customHeight", "in": "query", "schema": { "type": "integer", "minimum": 50, "maximum": 600 } }, { "name": "layout", "in": "query", "schema": { "type": "string", "enum": [ "card", "compact", "terminal" ], "default": "card" }, "description": "Widget layout; existing size, colour and visibility parameters remain supported." }, { "name": "lang", "in": "query", "schema": { "type": "string", "enum": [ "en", "tr", "de", "es" ], "default": "en" } }, { "name": "refreshInterval", "in": "query", "schema": { "type": "integer", "minimum": 0, "maximum": 300, "default": 60 }, "description": "Seconds between updates. Zero disables refresh; nonzero values are at least 60 seconds. Hidden or focused widgets pause refresh." } ], "responses": { "200": { "description": "Embeddable HTML widget", "content": { "text/html": { "schema": { "type": "string" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "429": { "$ref": "#/components/responses/RateLimited" }, "503": { "$ref": "#/components/responses/TemporarilyUnavailable" } }, "x-rate-limit": { "requests": 5000, "window_seconds": 60, "scope": "ip" } } }, "/banner-designs": { "post": { "summary": "Save an immutable public banner design", "description": "Creates a shareable design. Identical designs are deduplicated. Maximum 24 layers, 3 embedded images and 512 KB request body. Limited to 12 saves per IP per hour. Drafts can also be exported locally without saving.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "name", "document" ], "properties": { "name": { "type": "string", "maxLength": 80 }, "document": { "type": "object", "description": "Version 1 banner document exported by /banner-editor. No remote image URLs or scripts are supported." } } } } } }, "responses": { "201": { "description": "Saved design with UUID and normalized document" }, "400": { "description": "Invalid layout or image" }, "429": { "description": "Save rate limit" }, "503": { "description": "Storage unavailable" } }, "x-rate-limit": { "requests": 12, "window_seconds": 3600, "scope": "ip" } } }, "/banner-designs/{id}": { "get": { "summary": "Read a saved public design for viewing or remixing", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Immutable design document" }, "404": { "description": "Unknown design" }, "429": { "$ref": "#/components/responses/RateLimited" }, "503": { "$ref": "#/components/responses/TemporarilyUnavailable" } }, "x-rate-limit": { "requests": 60, "window_seconds": 60, "scope": "ip" } } }, "/banner-designs/render": { "post": { "summary": "Export a design as PNG without saving it", "description": "POST {address, document}. Dynamic fields use the requested Minecraft server status. 20 renders per IP per minute.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "address", "document" ], "properties": { "address": { "type": "string" }, "document": { "type": "object" } } } } } }, "responses": { "200": { "description": "PNG image", "content": { "image/png": { "schema": { "type": "string", "format": "binary" } } } }, "400": { "description": "Invalid parameters" }, "429": { "description": "Render rate limit" }, "503": { "$ref": "#/components/responses/TemporarilyUnavailable" } }, "x-rate-limit": { "requests": 20, "window_seconds": 60, "scope": "ip" } } }, "/badge/{address}": { "get": { "operationId": "getMinecraftStatusBadge", "summary": "Get a cacheable SVG status badge", "description": "A valid but unreachable target produces a 200 SVG showing Offline. Stale data is labeled Stale. Add alt text to the embedding image.", "tags": [ "Status" ], "parameters": [ { "name": "address", "in": "path", "required": true, "description": "Public hostname or IP with an optional port. Enclose IPv6 in square brackets. An explicit port bypasses Java SRV.", "schema": { "type": "string", "examples": [ "mc.hypixel.net", "play.example.net:19132", "[2606:4700::1001]:25565" ] } }, { "name": "legacy", "in": "query", "description": "Use the legacy Java ping protocol.", "schema": { "type": "boolean", "default": false } }, { "name": "bedrock", "in": "query", "description": "Use the Minecraft Bedrock Edition protocol.", "schema": { "type": "boolean", "default": false } }, { "name": "edition", "in": "query", "schema": { "enum": [ "java", "bedrock", "legacy", "auto" ] }, "description": "Auto tries both Java and Bedrock with separate default ports when omitted. Use edition or the legacy/bedrock flags." } ], "responses": { "200": { "description": "SVG badge", "headers": { "ETag": { "schema": { "type": "string" } }, "Cache-Control": { "schema": { "type": "string" } } }, "content": { "image/svg+xml": { "schema": { "type": "string" } } } }, "304": { "description": "Unchanged badge" }, "400": { "$ref": "#/components/responses/BadRequest" }, "429": { "$ref": "#/components/responses/RateLimited" }, "503": { "$ref": "#/components/responses/TemporarilyUnavailable" } }, "x-rate-limit": { "requests": 120, "window_seconds": 60, "scope": "ip" } } }, "/service-status": { "get": { "operationId": "getServiceStatus", "summary": "Get MCAPI service measurements and incident history", "description": "Seven-day observed availability and coverage. Health and PNG are checked on the public service; Java and Bedrock use controlled local fixtures. Unmeasured slots are tracked separately.", "tags": [ "Status" ], "responses": { "200": { "description": "Current measurement summary", "content": { "application/json": { "schema": { "type": "object", "required": [ "measured_at", "window_start", "window_days", "interval_seconds", "expected_samples", "components", "incidents" ], "properties": { "measured_at": { "type": "string", "format": "date-time" }, "window_start": { "type": "string", "format": "date-time" }, "window_days": { "const": 7 }, "interval_seconds": { "const": 300 }, "expected_samples": { "const": 2016 }, "components": { "type": "object" }, "incidents": { "type": "array", "items": { "type": "object" } } } } } } }, "429": { "$ref": "#/components/responses/RateLimited" }, "503": { "$ref": "#/components/responses/TemporarilyUnavailable" } }, "x-rate-limit": { "requests": 60, "window_seconds": 60, "scope": "ip" } } } }, "components": { "parameters": { "AddressQuery": { "name": "address", "in": "query", "required": true, "description": "Public Minecraft server hostname or IP, optionally with a port.", "schema": { "type": "string" } }, "BedrockQuery": { "name": "bedrock", "in": "query", "schema": { "type": "boolean", "default": false } }, "LegacyQuery": { "name": "legacy", "in": "query", "schema": { "type": "boolean", "default": false } } }, "responses": { "BadRequest": { "description": "Invalid address or query parameter", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "NotFound": { "description": "Minecraft server is offline or unreachable", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "RateLimited": { "description": "Per-minute request limit exceeded", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "status": "error", "error": "Rate limit exceeded, retry in 1 minute" } } }, "headers": { "Retry-After": { "schema": { "type": "string" }, "example": "60" } } }, "TemporarilyUnavailable": { "description": "Temporary service unavailability, maintenance, or a status deadline. If present, wait for Retry-After.", "headers": { "Retry-After": { "schema": { "type": "string" }, "example": "5" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Server status lookup timed out.", "reason_code": "LOOKUP_DEADLINE" } } } } }, "schemas": { "SavedServersResponse": { "type": "object", "required": [ "success", "data", "meta" ], "properties": { "success": { "const": true }, "data": { "type": "array", "items": { "type": "object", "required": [ "server_id", "address", "port", "status", "online", "stale", "checked_at" ], "properties": { "server_id": { "type": "string", "format": "uuid" }, "hostname": { "type": "string" }, "address": { "type": "string" }, "port": { "type": "integer" }, "status": { "enum": [ "online", "stale", "offline" ] }, "online": { "type": [ "boolean", "null" ] }, "stale": { "type": "boolean" }, "last_snapshot_online": { "type": [ "boolean", "null" ] }, "checked_at": { "type": [ "string", "null" ], "format": "date-time" }, "players_online": { "type": [ "integer", "null" ] }, "players_max": { "type": [ "integer", "null" ] }, "version": { "type": [ "string", "null" ] }, "protocol": { "type": [ "integer", "null" ] }, "ping": { "type": [ "integer", "null" ] }, "edition": { "enum": [ "java", "bedrock", null ] }, "observed_at": { "type": [ "string", "null" ], "format": "date-time" } } } }, "meta": { "type": "object", "properties": { "limit": { "type": "integer" }, "hasNext": { "type": "boolean" }, "nextCursor": { "type": [ "string", "null" ] }, "page": { "type": [ "integer", "null" ], "description": "Current numbered page, or null in cursor mode." }, "nextPage": { "type": [ "integer", "null" ], "description": "Next numbered page, or null at the end or in cursor mode." }, "as_of": { "type": "string", "format": "date-time" }, "sort": { "enum": [ "id", "players", "recent" ] } } } } }, "BulkStatusRequest": { "type": "object", "required": [ "servers" ], "properties": { "servers": { "type": "array", "minItems": 1, "maxItems": 50, "items": { "type": "object", "required": [ "address" ], "properties": { "address": { "type": "string", "minLength": 3, "maxLength": 255 }, "legacy": { "type": "boolean", "default": false }, "bedrock": { "type": "boolean", "default": false } }, "not": { "properties": { "legacy": { "const": true }, "bedrock": { "const": true } }, "required": [ "legacy", "bedrock" ] } } } } }, "BulkStatusResponse": { "type": "object", "required": [ "success", "data", "meta" ], "properties": { "success": { "const": true }, "data": { "type": "array", "items": { "type": "object", "required": [ "address", "status_code", "data" ], "properties": { "address": { "type": "string" }, "status_code": { "enum": [ 200, 404, 500 ] }, "data": { "type": "object", "additionalProperties": true, "description": "Single-server status response, or an error object." } } } }, "meta": { "type": "object", "properties": { "count": { "type": "integer" } } } } }, "HealthResponse": { "type": "object", "required": [ "status", "timestamp", "service", "version" ], "properties": { "status": { "type": "string", "const": "OK" }, "timestamp": { "type": "string", "format": "date-time" }, "service": { "type": "string", "examples": [ "mcapi.tr-engine" ] }, "version": { "type": "string" } } }, "ErrorResponse": { "type": "object", "additionalProperties": true, "properties": { "status": { "type": "string" }, "error": { "type": "string" }, "message": { "type": "string" }, "reason_code": { "type": [ "string", "null" ] } } }, "Query": { "type": "object", "properties": { "host": { "type": "string" }, "port": { "type": "integer" }, "legacy": { "type": "boolean" }, "bedrock": { "type": "boolean" }, "edition": { "enum": [ "java", "bedrock", "legacy" ] } } }, "Players": { "type": [ "object", "null" ], "properties": { "online": { "type": "integer", "minimum": 0 }, "max": { "type": "integer", "minimum": 0 }, "sample": { "type": "array", "items": { "type": "object", "additionalProperties": true } } } }, "Motd": { "type": [ "object", "null" ], "properties": { "raw": { "type": "string" }, "clean": { "type": "string" }, "html": { "type": "string" }, "raw_lines": { "type": "array", "items": { "type": "string" } }, "clean_lines": { "type": "array", "items": { "type": "string" } }, "html_lines": { "type": "array", "items": { "type": "string" } } } }, "ServerStatus": { "type": "object", "required": [ "query", "online", "observed_at", "last_attempt_at", "cache_expires_at", "reason_code" ], "properties": { "query": { "$ref": "#/components/schemas/Query" }, "server_id": { "type": [ "string", "null" ], "format": "uuid" }, "ip_address": { "type": [ "string", "null" ] }, "icmp": { "type": [ "boolean", "null" ] }, "online": { "type": "boolean" }, "error": { "type": [ "string", "null" ] }, "version": { "type": [ "object", "null" ], "properties": { "name": { "type": "string" }, "protocol": { "type": "integer" } } }, "players": { "$ref": "#/components/schemas/Players" }, "motd": { "$ref": "#/components/schemas/Motd" }, "favicon": { "type": [ "string", "null" ], "description": "Data URL when advertised by the server." }, "roundTripLatency": { "type": [ "number", "null" ], "minimum": 0 }, "stale": { "type": "boolean" }, "checked_at": { "type": "string", "format": "date-time" }, "srvRecord": { "type": [ "object", "null" ], "properties": { "host": { "type": "string" }, "port": { "type": "integer" } }, "additionalProperties": true }, "observed_at": { "type": [ "string", "null" ], "format": "date-time", "description": "Time of the last successful observation, if known." }, "last_attempt_at": { "type": "string", "format": "date-time", "description": "Completion time of the most recent probe attempt." }, "cache_expires_at": { "type": "string", "format": "date-time", "description": "Scheduled expiry of this cached response." }, "reason_code": { "enum": [ null, "PRIVATE_TARGET", "DNS_NO_RECORD", "DNS_TIMEOUT", "DNS_ERROR", "SRV_UNAVAILABLE", "SRV_LOOKUP_ERROR", "CONNECTION_REFUSED", "CONNECTION_CLOSED", "NETWORK_ERROR", "TIMEOUT", "UDP_NO_RESPONSE", "INVALID_RESPONSE" ], "description": "Machine-readable cause of the latest failed attempt; null on success." }, "mods": { "type": "array", "items": { "type": "string" } }, "plugins": { "type": "array", "items": { "type": "string" } }, "software": { "type": "string" }, "latency_source": { "enum": [ "pong", "status" ] }, "target": { "type": "object", "properties": { "ip": { "type": "string" }, "port": { "type": "integer" } } } }, "additionalProperties": true }, "TrendServer": { "type": "object", "required": [ "hostname", "port", "is_online", "stale" ], "properties": { "server_id": { "type": "string", "format": "uuid" }, "hostname": { "type": "string" }, "address": { "type": "string" }, "port": { "type": "integer" }, "edition": { "type": "string", "enum": [ "java", "bedrock" ] }, "trend_score": { "type": "number" }, "daily_growth": { "type": "number", "description": "Percentage change between two complete 24-hour query-count windows. May be negative. Returns 0 without a previous-period baseline." }, "is_online": { "type": "boolean", "const": true }, "stale": { "type": "boolean", "const": false }, "checked_at": { "type": "string", "format": "date-time" }, "players_online": { "type": "integer" }, "players_max": { "type": "integer" }, "version": { "type": [ "string", "null" ] }, "favicon": { "type": [ "string", "null" ], "description": "Stored favicon hash used by the icon endpoint." }, "record_players": { "type": "integer" }, "uptime_percentage": { "type": "number" } }, "additionalProperties": true }, "TrendResponse": { "type": "object", "required": [ "success", "data", "meta" ], "properties": { "success": { "type": "boolean", "const": true }, "data": { "type": "array", "items": { "$ref": "#/components/schemas/TrendServer" } }, "meta": { "type": "object", "properties": { "nextCursor": { "type": [ "string", "null" ] }, "hasNext": { "type": "boolean" }, "limit": { "type": "integer" }, "page": { "type": [ "integer", "null" ] }, "nextPage": { "type": [ "integer", "null" ] } } } } }, "Statistics": { "type": "object", "additionalProperties": true, "properties": { "totalRequests": { "type": "integer" }, "apiRequests": { "type": "integer" }, "serverQueries": { "type": "integer" }, "totalChecks": { "type": "integer" }, "onlineServers": { "type": "integer" }, "offlineServers": { "type": "integer" }, "activePlayers": { "type": "integer" }, "onlineRate": { "type": "number" } } }, "CompactServerStatus": { "type": "object", "required": [ "online", "stale", "observed_at", "last_attempt_at", "cache_expires_at", "reason_code" ], "properties": { "online": { "type": "boolean" }, "stale": { "type": "boolean" }, "players": { "$ref": "#/components/schemas/Players" }, "version": { "type": [ "object", "null" ], "properties": { "name": { "type": "string" }, "protocol": { "type": "integer" } } }, "motd": { "$ref": "#/components/schemas/Motd" }, "favicon": { "type": [ "string", "null" ], "description": "Data URL when advertised by the server." }, "roundTripLatency": { "type": [ "number", "null" ], "minimum": 0 }, "reason_code": { "enum": [ null, "PRIVATE_TARGET", "DNS_NO_RECORD", "DNS_TIMEOUT", "DNS_ERROR", "SRV_UNAVAILABLE", "SRV_LOOKUP_ERROR", "CONNECTION_REFUSED", "CONNECTION_CLOSED", "NETWORK_ERROR", "TIMEOUT", "UDP_NO_RESPONSE", "INVALID_RESPONSE" ], "description": "Machine-readable cause of the latest failed attempt; null on success." }, "observed_at": { "type": [ "string", "null" ], "format": "date-time", "description": "Time of the last successful observation, if known." }, "last_attempt_at": { "type": "string", "format": "date-time", "description": "Completion time of the most recent probe attempt." }, "cache_expires_at": { "type": "string", "format": "date-time", "description": "Scheduled expiry of this cached response." }, "checked_at": { "type": "string", "format": "date-time" }, "server_id": { "type": [ "string", "null" ], "format": "uuid" }, "query": { "$ref": "#/components/schemas/Query" }, "mods": { "type": "array", "items": { "type": "string" } }, "plugins": { "type": "array", "items": { "type": "string" } }, "software": { "type": "string" } }, "additionalProperties": false } } } } ```