Everything you do by clicking in the panel β starting the server, sending a console command, editing a file β can also be done with an HTTP request. That's what lets a Discord bot restart the Minecraft server with a command, a script bring the server back up if it goes down, or a routine save a configuration file every day.
This guide shows how to create the key that grants this access and how to use it for the most common operations.
The key acts on behalf of your account. It has no separate permissions: whatever you can do in the panel, it can too, on every server in the account. The most used operations are:
say, whitelist add or save-all.The panel may show its labels in Portuguese; the original name is in parentheses.
discord bot. It needs at least 4 characters, and this name is what will tell you, months later, which key to delete.The Your API Key window (Sua Chave API) shows the full key, which starts with ptlc_. Copy it and keep it somewhere safe: it isn't shown again. If you lose it, delete the key and create another.
Every call needs to say which server to act on. The identifier appears in the address bar when you open the server in the panel:
https://app.redhosting.com.br/server/1a2b3c4d
The identifier is the part after /server/ β in the example, 1a2b3c4d. The examples below use YOUR_SERVER in its place and YOUR_KEY in place of the key.
Every request carries the key and the indication that the conversation is in JSON. This command lists the account's servers and confirms that the key works:
curl https://app.redhosting.com.br/api/client \
-H "Authorization: Bearer YOUR_KEY" \
-H "Accept: application/json"
The response has one item per server. The identifier field of each is the same identifier from the previous step.
curl https://app.redhosting.com.br/api/client/servers/YOUR_SERVER/resources \
-H "Authorization: Bearer YOUR_KEY" \
-H "Accept: application/json"
The current_state field gives the state: running, starting, stopping or offline. Under resources come memory and disk in bytes and CPU as a percentage.
curl -X POST https://app.redhosting.com.br/api/client/servers/YOUR_SERVER/power \
-H "Authorization: Bearer YOUR_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"signal": "restart"}'
signal accepts start, stop, restart and kill. Prefer stop: it shuts down gracefully and lets the server save what's in memory. kill cuts it off immediately, like pulling the plug, and can corrupt the world or open files.
curl -X POST https://app.redhosting.com.br/api/client/servers/YOUR_SERVER/command \
-H "Authorization: Bearer YOUR_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"command": "say Restarting in 5 minutes"}'
The command goes to the console exactly as if you'd typed it there. The server must be on; if it's off, the response is a 502 error.
To list a folder:
curl "https://app.redhosting.com.br/api/client/servers/YOUR_SERVER/files/list?directory=/" \
-H "Authorization: Bearer YOUR_KEY" \
-H "Accept: application/json"
To read a file β the response is the raw content, not JSON:
curl "https://app.redhosting.com.br/api/client/servers/YOUR_SERVER/files/contents?file=/server.properties" \
-H "Authorization: Bearer YOUR_KEY"
To write, the request body is the file's entire new content, which replaces the old one:
curl -X POST "https://app.redhosting.com.br/api/client/servers/YOUR_SERVER/files/write?file=/motd.txt" \
-H "Authorization: Bearer YOUR_KEY" \
-H "Accept: application/json" \
--data-binary @motd.txt
Summary of the endpoints. All start with https://app.redhosting.com.br/api/client/servers/YOUR_SERVER:
| Action | Method | Endpoint |
|---|---|---|
| State and usage | GET | /resources |
| Start, stop, restart | POST | /power |
| Console command | POST | /command |
| List folder | GET | /files/list?directory=/ |
| Read file | GET | /files/contents?file=/path |
| Write file | POST | /files/write?file=/path |
| List backups | GET | /backups |
A Node.js script (version 18 or newer) that checks the state and starts the server when it finds it off. The key comes from an environment variable, not written in the code β that's how it stays out of GitHub along with everything else.
const PANEL = 'https://app.redhosting.com.br/api/client';
const SERVER = 'YOUR_SERVER';
const headers = {
Authorization: `Bearer ${process.env.PANEL_API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
};
async function check() {
const response = await fetch(`${PANEL}/servers/${SERVER}/resources`, { headers });
if (!response.ok) throw new Error(`API responded ${response.status}`);
const { attributes } = await response.json();
if (attributes.current_state === 'offline') {
await fetch(`${PANEL}/servers/${SERVER}/power`, {
method: 'POST',
headers,
body: JSON.stringify({ signal: 'start' }),
});
console.log('Server was off β starting it.');
}
}
check().catch((error) => console.error(error.message));
Run every few minutes by a system scheduler, it brings the server back after an outage. Don't run it at too short an interval: see the request limit in the next section.
| Response | What it means | What to do |
|---|---|---|
| 401 | The key wasn't accepted. | Check that you copied the whole key, including ptlc_, and that the header is Authorization: Bearer. A key deleted in the panel stops working immediately. |
| 403 | The key works, but not here. | The IP the request came from isn't in Allowed IPs, or your account is a subuser of the server without permission for that action. |
| 404 | Server or file not found. | Check the 8-character identifier and the file path, which starts with /. |
| 409 | The server can't do that right now. | It's installing, being transferred or suspended. Wait for it to finish. |
| 429 | Too many requests. | The panel accepts up to 256 requests per minute per account. Space out your calls. |
| 502 | The server must be on. | Happens when sending a command with the server off. Start it first. |
.env file that's in .gitignore, never inside the code.Before putting the script into production
stop, not kill, to shut down.
/server/.