Skip to content

Blog ·

Choosing a game panel by the API you automate

Six game panels, measured on what their APIs actually let you do. The decisive question is not features but whether the panel enforces a suspension at all.

By Provibr

Most comparisons of game server panels are written for the person who will click around in one. If you are going to sell game servers, you are not that person. You will see the panel roughly twice a year, and your billing system will see it every few minutes, forever.

So the useful comparison is a different one: what does the API let you do, what does it refuse to tell you, and which of the promises in the interface does the panel actually enforce when a customer stops paying.

Everything below was measured while building integrations against Pterodactyl 1.11, Pelican 1.0.0-beta38, WISP 3.7.5, PufferPanel 3.0.9, GameAP 4.4.2 and MCSManager 10.18.2, in August 2026.

One panel is deliberately not in the table. AMP is not here because we have not measured it. It is a reasonable product with a real API, and writing a comparison row from its documentation rather than from its responses would be exactly the kind of confident-sounding filler this piece is arguing against.

Getting in: six panels, five different credential models

PanelCredentialNotes
PterodactylTwo static keys, ptla_ and ptlc_Both required
PelicanTwo static keys, papp_ and pacc_Both required
WISPOne key, no prefixNothing to validate before the first call
PufferPanelOAuth2 client credentialsOpaque token, one hour, scope admin
GameAPOne Sanctum bearer tokenNo expiry column in the panel's own schema
MCSManagerOne key, header x-request-api-keyAPI access is off by default

Three of those need a warning.

Pterodactyl and Pelican need both keys, and the reason is structural: there is no power endpoint on the Application API. An integration set up with only an application key can create servers that its owner cannot start.

Pelican accepts a client key on the Application API. GET /api/application/servers, /nodes and /users all return 200 with the wrong key, and the mistake only surfaces on a write, as a validation error about a missing user field. Pterodactyl answers 403 to the same request. On Pelican, checking the key prefix is the only way to catch a swapped pair before it becomes a confusing failure at provisioning time. On WISP, which has no prefix at all, there is no way to catch it.

MCSManager ships with its API disabled. A fresh install has enableApiKey set to false, and until somebody turns it on, every call returns 403 "Insufficient Permissions", including calls made with a valid key belonging to a valid administrator. That is a support ticket on day one for anyone who does not know to look. While you are in there: MCSManager also rate-limits at eight requests per second per session cookie, so a client that keeps cookies gets throttled where a client that discards them does not.

The question that decides it: does suspend do anything?

Every one of these panels can be told to suspend a server. That is not the question. The question is whether a customer who still has panel credentials can undo it.

PanelMechanismDoes the panel enforce it?
Pterodactylsuspend / unsuspend on the Application APIYes
PelicanSameYes
WISPSameYes
MCSManagerSet the instance end time in the past, then killYes
PufferPanelStop, then killNo
GameAPStop, then set blockedNo

The three Pterodactyl-family panels have a real primitive and there is nothing to discuss.

MCSManager is the surprise. It has no suspend endpoint either, but it has an expiry: set an instance's end time into the past and the daemon refuses to start it. We checked that against the panel rather than against our own guard, with a raw request, and got 500 Instance expired. Unable to start the instance. That is enforcement. Two caveats: you have to kill the instance as well, because otherwise a running server keeps running until the hourly expiry check catches it, up to sixty minutes later. And if a customer had set their own expiry date, it is on you to put it back on resume; ours does not, yet.

PufferPanel has nothing. There is no suspend endpoint and no suspended column in its data model; the status vocabulary is running and installing. The best available action is to stop the server and kill it if it does not stop. A customer with panel access can press start.

GameAP has a flag that does not do anything. There is a blocked field, and setting it is administrative only. We set it on a running SA-MP server and the server stayed online, answering live game queries, and could be started again from the panel afterwards.

That distinction is worth building into your own data model rather than smoothing over. On the two panels that do not enforce it, the honest description of what happened is "the server was stopped and blocked in the panel, but a direct login can start it again", and that belongs in the audit record of the action. Recording six panels as "suspended" when two of them merely wish they were is how a billing system quietly stops collecting.

Creating a server: four different shapes

There is no common ground here at all. Four of these panels model a game server in a fundamentally different way, and the shape of the create call follows.

Pterodactyl and Pelican want everything at once. Name, owner, egg, docker image, startup command, the complete environment variable set including the ones the customer never sees, limits, feature_limits and an allocation. There is no partial create; a missing field is a refusal per field. One value worth knowing: limits.io is validated between:10,1000, so sending 0 for "unlimited" is a 422 on a field no customer will ever hear about. Pelican inverted that rule, where 0 is fine and omitting the field is the error.

PufferPanel is inside out. You mint the server identifier yourself, eight characters, then PUT the entire template definition inline, because the template list does not carry variables. Creating does not install: that is a second call. And deleting requires stopping first, or you get a 500.

GameAP creates a database row and nothing else. POST /api/servers gives you a server with installed: 0; installation is a second call whose outcome lands in a daemon task rather than in the HTTP response, so you poll. There is no external ID and no idempotency key, and names are not unique, which together mean a retried create silently produces a duplicate. The returned ID is the only identity you get, so store it before anything else can go wrong.

MCSManager has no template concept at all. An instance is a start command, and that is the whole abstraction. There is a list of quick-install presets, sixty-three of them, but none carries an ID: the panel matches on title plus description, fifty of the sixty-three titles are not unique, and the values are language-dependent. Anything keyed on them breaks when the customer changes the panel language.

What you can see afterwards

PanelUsage figuresNode capacityLive console
PterodactylCPU, memory, disk, network, uptimeFrom the nodeYes
PelicanSameFrom the nodeYes
WISPSame, without uptimeCapacity yes, occupancy noYes
PufferPanelCPU and memory onlyNone reportedPolled, not streamed
GameAPNoneNot readable, 403Separate protocol
MCSManagerCPU and memory; disk always 0Per daemonSocket.io, not plain WebSocket

Two entries there are worse than they look. GameAP returns 403 on /api/nodes for an API token, so a placement engine cannot see capacity at all and has to be told where to put things. And MCSManager's disk figure is not merely unreliable: the field is declared as zero in the daemon and never assigned, so it is always zero, on every instance, forever.

Pterodactyl's /resources endpoint caches for twenty seconds, which matters more than it sounds: poll faster than that and you get the same bytes back, and a naive network-rate calculation turns identical counters into a dip that never happened. Pelican inherited the same behaviour. WISP does not cache it, but WISP has no uptime field, which is the field you would use to tell a fresh reading from a repeated one.

How to actually choose

  • You need enforceable suspension and a real API. Pterodactyl, or Pelican if you want the actively developed fork. This is the boring correct answer for most people selling game hosting.
  • You want Docker-free hosting on small machines. MCSManager, and it is a better fit than its reputation suggests, because expiry gives you real enforcement. Accept that you will get two usage metrics and no console integration.
  • You already run PufferPanel or GameAP. Fine, but build your suspension on top: the platform has to block panel access, because the panel will not.
  • You are choosing today with no legacy. The panel's API is going to be the constraint on your automation for years, and two of these six cannot enforce the one operation your billing system most depends on.

What is not measured here

AMP, as stated above. Pterodactyl versions below 1.11, on a panel where this is exactly the kind of behaviour that shifts in point releases. Rate limits on Pterodactyl and Pelican, which would need hundreds of requests against a live panel to establish honestly. MCSManager with Docker enabled, where more metrics should exist but where we have never seen a populated field. And classic PHP GameAP, since the panel we measured is the Go rewrite, which differs at least in its authentication layer.

The API traps behind the first two rows are written up in full in five Pterodactyl API traps, and Pterodactyl next to Pelican covers the fork. Provibr integrates all six of these panels through an agent that runs inside your own network; the setup notes are under Pterodactyl, Pelican, PufferPanel, GameAP and MCSManager.

Start with one host and one agent

Create an account, install the agent with a single command and connect your first Proxmox host. The trial runs for 14 days and asks for no payment details.