Discovery Overview
What Discovery is: apps, public IDs, heartbeat tokens, token scopes, and how the service behaves.
Discovery gives your players a live server list. Game clients read a public, unauthenticated list; your servers get onto it in one of two ways, depending on where they are hosted. Servers hosted on PingCore connect automatically through a fleet, with no code on your side. Servers hosted anywhere else send an HTTP heartbeat every 30 seconds (see Sending Heartbeats). Discovery is a standalone product: the heartbeat path works even if you host nothing else on PingCore. It is free for up to 5,000 self-hosted game servers per Discovery app (the app's Self-hosted allowance); above that, host the extra game servers on PingCore or contact support to raise it.
You manage Discovery in your workspace. In the sidebar, open Hosting > Discovery. Viewing requires the discovery.view permission; creating apps, changing settings, and issuing tokens require discovery.manage.
Discovery apps
A Discovery app is your tenant on the Discovery service. One app has one server list, its own heartbeat tokens, and its own settings. Create one per game (or per environment, if you want production and staging fully separated).
To create an app, click Add App, enter an App Name and click Create. A new app starts with Private registration and no endpoint verification. Change either in the app's settings (see the registration modes below and Reachability Verification).
You can also start from a game: Add a Discovery app in the Where this game runs card on the game's overview opens the same form with the new app linked to that game. Click Don't link to create it without the link.
Each app also has:
Linked Game (optional): provenance only. Linking a game does not change how heartbeats or the server list behave.
App enabled switch: disabling rejects new heartbeats and stops serving the server list.
Concurrent Server Limit: how many game servers hosted on PingCore may be live at once. PingCore sets it per Discovery app; the default is 50,000. The limit exists to stop a leaked token from flooding the service with fake servers; it is not a cap on normal use. Self-hosted game servers never count against it. Once reached, existing game servers keep reporting normally and only brand-new ones are refused. Contact support to raise it.
Self-hosted allowance: how many self-hosted game servers (the ones that send heartbeats) may be live at once. PingCore sets it per Discovery app; the default is 5,000, and 0 means self-hosting is disabled for the app. Hosted game servers never count against it. Once reached, existing game servers keep reporting normally and only brand-new ones are refused with a 409 (see Sending Heartbeats). Host more game servers on PingCore or contact support to raise it.
Both limits are shown read-only on the app page. Contact support to change them.
When fleets list on the app, or it has a linked game, the app page shows them in a strip under the header. Each name links to its page, or shows as plain text when you do not have the brand permission to open it. The linked game sits apart from the fleets, labelled Linked game (provenance only).
Choosing a registration mode
The Registration setting is the app's trust model for heartbeat tokens. It decides whether the token itself must stay secret.
Private (the default): your servers are machines you operate, and the heartbeat token is a secret they hold. Keep tokens on your servers and backends, never in a game client. Anyone holding a token can register servers on your list, so token secrecy is what protects the list. If you also run No verification, treat that secrecy seriously: a leaked token would let anyone list arbitrary endpoints to your players.
Open: for client-hosted games, where the shipped game itself runs the server (listen servers, player-hosted sessions). The token has to ship inside your game binary, so it is public by design; anyone can extract it, and that is fine. This is the model Steam uses for anonymous game server registration, and the old Quake and Source master servers before it. Instead of token secrecy, the list is protected by two enforced mechanisms:
Mandatory endpoint verification: the Verification setting is locked to UDP echo challenge. A server only reaches the list once it proves it controls the endpoint it advertises. See Reachability Verification.
A per-source-IP server limit: each source IP may register a bounded number of servers on the app (default 10, raisable via Max servers per source IP on the app page). See Sending Heartbeats.
Switching an existing app to Open locks its verification mode to the UDP echo challenge automatically. Like every app setting, the change reaches the Discovery service within about a minute.
An app a fleet uses cannot be switched to Open. Discovery refuses every hosted game server's connection on an open app, so the whole fleet would go offline. The save is refused with a 409 that names the fleets (reason: "fleet_linked", with the fleets in linkedFleets). Keep that app private, and give your client-hosted game its own Discovery app.
Public ID vs tokens
The two credentials play different roles, so it matters which one goes where.
The public ID (prefix
dscp_) identifies your app in the client-facing server list URL:/v1/apps/{publicId}/servers. It is public by design and safe to ship inside your game client. It grants no write access to anything.A heartbeat token (prefix
dsc_) is a bearer credential presented to the service:Authorization: Bearer dsc_.... On a private app it is a secret and belongs on your servers and backends, never in a game client. On an open app it ships inside the game binary and is not a secret (see Choosing a registration mode above); it still routes heartbeats to the right app and can still be rotated.
The app page shows the Public Server List URL with a copy button. That URL also tells you the service base URL used by every endpoint in these docs (for example https://discovery.pingcore.io).
Token scopes
Every token has a scope, chosen when you issue it. On the app page, under Heartbeat Tokens, enter a label, pick a scope, and click Issue Token. The token is shown exactly once: copy it immediately, every later view is masked.
Heartbeat: ingest. Sending heartbeats, delisting servers, and verifying reservations. On a private app it can also read fleet state and matchmaking stats; on an open app it cannot (see below). This is what your game servers use.
Allocate: matchmaking. Allocations, tickets, joinable-session records, reservations made from your backend, and the desired-capacity hint. This is what your matchmaker backend uses.
Both: full access.
Endpoints by credential
No credential (safe to call from a shipped client): the public server list
GET /v1/apps/{publicId}/servers, the location listGET /v1/locations, anonymous player-token issuancePOST /v1/apps/{publicId}/player-tokens, andGET /openapi.json.Heartbeat scope:
POST /v1/heartbeat, delisting, andGET /v1/reservations/verify/{reservationId}.Allocate scope:
POST /v1/apps/{publicId}/allocationsand itsGET/DELETE,PUT /v1/apps/{publicId}/desired-capacity, and the joinable-session record on a server,POST,GET, andDELETE /v1/apps/{publicId}/servers/{serverId}/joinable-session.Allocate scope or a player token: the reservation routes (reserve on a server, quick-join,
GET/DELETEa reservation) and the ticket routes (POST /v1/apps/{publicId}/tickets,GET/DELETE /v1/apps/{publicId}/tickets/{ticketId}). A player token acts within the player bounds described on Choosing How Players Connect.Any active token of the app on a private app, Allocate (or Both) on an open-registration app:
GET /v1/apps/{publicId}/fleet-state,GET /v1/apps/{publicId}/matchmaking-stats, and the matchmaking inspector,GET /v1/apps/{publicId}/matchmaking/queues,.../matchmaking/tickets, and.../matchmaking/matches. An open app's heartbeat token ships inside the game binary, so on these routes it gets a 403 withreason: "scope".
For external heartbeat integrations, issue one token per environment so you can revoke a leaked token without taking everything offline. Servers hosted on PingCore do not choose a token: their fleet agents use the app's oldest active ingest token. Revoking a token disconnects any agent still using it within about a minute; the agents pick up the replacement token automatically within a few minutes, after a brief reconnection gap. No restart is needed. A token used against the wrong surface gets a 403 with a message naming the missing scope.
Status codes
Discovery keeps its error responses distinct so you can diagnose problems from the status code alone:
401: the bearer token is missing or unknown.
403: the token is known but not usable here. It was revoked, the app is disabled, or the token lacks the required scope.
503: the service is degraded, for example because it is starting up. Retry shortly; the token itself may be valid. On an allocation, a 503 with
reason: "agent_push_unavailable"means Discovery could not deliver the allocation to a game server and rolled it back; retry with backoff and the same idempotency key (see Matchmaking Integration).
Treat 401 and 403 as configuration problems on your side; treat 503 as transient.
The revocation window
Revoking a token, disabling an app, or changing app settings takes effect on the Discovery service within about a minute. The service pulls its registry from the platform on a sync interval rather than checking every request, which keeps your heartbeats independent of platform availability. The delay is expected behaviour. Plan token rotation with it in mind: issue the new token, roll it out to your external integrations, then revoke the old one. For servers hosted on PingCore, fleet agents use the app's oldest active ingest token; after you revoke the old token they reconnect with the new one automatically within a few minutes, with a brief reconnection gap in between. No restart is needed. While the agents reconnect, a fleet briefly reads as under capacity, so the autoscaler may add servers transiently; if that matters, rotate during a low-traffic window.
What Discovery stores
Only live state. A server exists in Discovery for as long as it keeps heartbeating (plus a 90 second grace window). Discovery keeps no analytics, and the only history is a diagnostic list of the last 50 matchmaking matches per app, which expires after 24 hours. If your servers stop reporting, the list empties on its own and there is nothing to clean up.
API reference
The service publishes its full OpenAPI 3.1 document at GET /openapi.json on the same base URL as every other endpoint (for example https://discovery.pingcore.io/openapi.json). It is public, carries no secrets, and loads into Swagger UI, Postman, or a code generator directly. The same document powers the API Reference section of this portal. The pages in this category explain the workflows; the spec is the field-by-field contract for every endpoint, parameter, and response shape.
Next steps
Sending Heartbeats: keep your servers listed.
The Public Server List: read the list from your game client, with filtering and sorting.
Reachability Verification: prove players can actually connect.
Choosing How Players Connect: decide whether players reserve seats through your backend, with tokens your login service signs, or with anonymous tokens and no backend at all.
Reservations and Quick-Join: hold seats on a server before the party connects. Works for heartbeat servers too.
Matchmaking Integration: allocate fleet servers for matches, or use the built-in ticket matchmaker, from your backend or straight from the game client.
Latency and Location Targeting: measure a player's latency to each location and send it so matches and joins land nearby.
Hosting your servers on PingCore? Fleets connect them to Discovery automatically, with optional autoscaling and matchmaking on top.
Shipping an Update: update the build every fleet server reports, one server at a time.