Customer API documentation
Connect your applications to MarvinMC Hosting with scoped API keys.
Quick start
Create a key under Security > API keys, select servers and permissions, and authenticate with Authorization: Bearer <key>. Use HTTPS. Keys start with mmc_ and are shown only once. Never put keys in URLs, public JavaScript or repositories.
Applications can also use explicitly approved OAuth server permissions. Their available endpoints and scopes differ from personal API keys: Server authorisation and hosting API
Base URL: https://hosting.marvinmc.net/api/client/v1
Set MMC_API_KEY to your secret in your local environment before running the examples.
curl --fail-with-body 'https://hosting.marvinmc.net/api/client/v1/servers' \
-H "Authorization: Bearer $MMC_API_KEY"
{
"servers": [
{
"id": "1234567890123456789",
"name": "EXAMPLE_SERVER"
}
]
}
Example response with placeholder data. Replace SERVER_ID with an ID from your own server list. The next request sends a real console command.
curl --fail-with-body -X POST 'https://hosting.marvinmc.net/api/client/v1/servers/SERVER_ID/command' \
-H "Authorization: Bearer $MMC_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"command":"say hi"}'
Access and limits
Access requires all three: an API-enabled server type, access to the server, and the matching key permission. Free Servers have customer API access disabled. Disabled servers are omitted from lists and direct requests return HTTP 403 with api_disabled. Existing keys do not bypass a later plan restriction. Browser sessions are separate from customer API keys.
Keys never inherit administrator rights. Creation and editing require your password or two-factor code. Removing a server, reducing permissions, revoking the key or changing your password removes the corresponding access. Keys live for 1 to 365 days; up to 20 active keys per account. In-flight actions may finish; queued actions are rechecked before execution.
60 requests per minute per key and 600 per IP. HTTP 429 includes Retry-After: 60. Wait before retrying and use backoff. JSON request bodies may be at most 1 MiB. Recent request metadata is kept for 30 days, without tokens or request contents.
server.read- Read status and statistics
console.read- Read console
console.write- Send console commands
power- Start, stop, restart and kill
files.read- Read and search files
files.write- Edit text files
backups.read- List backups
backups.create- Create backups
Endpoints
GET/servers
List servers
Returns servers with id and name. Only selected, accessible, API-enabled servers are included.
Required permission: Selected accessible servers
200 Request completed successfully.
GET/servers/{id}/stats
Read server statistics
Returns current state and node statistics. Available metrics depend on the runtime.
Required permission: server.read
idRequired- Your server ID as a string, not a JavaScript number.
200 Request completed successfully.
GET/servers/{id}/console
Read console output
Returns logs, log_cursor, log_mode and log_reset with live state and statistics. The initial snapshot is bounded to the latest 500 lines / 256 KiB; later requests can fetch only new lines. An offline server has no active console output.
Required permission: console.read
idRequired- Your server ID as a string, not a JavaScript number.
cursorOptional- Opaque log_cursor from the previous response. Omit for the initial snapshot. Append logs only when log_mode is delta and log_reset is false.
200 Request completed successfully.
POST/servers/{id}/command
Send a console command
Sends a command to the actual server console. /say hi becomes say hi; //say hi becomes /say hi. Requires a running compatible server.
Required permission: console.write
idRequired- Your server ID as a string, not a JavaScript number.
JSON request body
{
"command": "say hi"
} 200 Request completed successfully.
POST/servers/{id}/power
Change power state
Queues start, stop, restart or kill. Kill terminates immediately. CAPTCHA-required actions must be performed in the web panel.
Required permission: power
idRequired- Your server ID as a string, not a JavaScript number.
Idempotency-KeyOptional- For a new power or backup action, send a unique Idempotency-Key (up to 200 characters). Reuse it only when retrying that exact action. Retries return the original job instead of executing twice. Retained for the job retention period (90 days for completed jobs).
JSON request body
{
"action": "restart"
} 202 Job accepted; execution is pending.
GET/servers/{id}/files
List a directory
Lists files and directories below path. Defaults to /server; does not recursively list contents.
Required permission: files.read
idRequired- Your server ID as a string, not a JavaScript number.
pathOptional- Path relative to the server file root, for example /server/server.properties or /backups. URL-encode query values.
200 Request completed successfully.
GET/servers/{id}/file
Read a text file
Returns a text file for editing, not a binary download. Existing editor size limits and file permissions apply.
Required permission: files.read
idRequired- Your server ID as a string, not a JavaScript number.
pathRequired- Path relative to the server file root, for example /server/server.properties or /backups. URL-encode query values.
200 Request completed successfully.
PUT/servers/{id}/file
Save a text file
Writes content to path. Existing file, storage and server-operation restrictions apply. This is not a binary upload endpoint.
Required permission: files.write
idRequired- Your server ID as a string, not a JavaScript number.
JSON request body
{
"path": "/server/example.txt",
"content": "example"
} 200 Request completed successfully.
GET/servers/{id}/search
Search files recursively
Returns entries with path, directory and, for text matches, line and snippet. Append each page and follow next_cursor until null. An empty page does not end the search if next_cursor is present. total_scanned reports progress; skipped indicates unreadable folders/files or the depth limit. limited indicates unfinished or incomplete results. Per-request limits: 100 results, 20,000 traversal steps, 2.5 seconds, 16 MiB text. Text files up to 512 KiB, maximum depth 24, no symlink traversal. Deduplicate by path if files change during the search. API rate limits apply to each page.
Required permission: files.read
idRequired- Your server ID as a string, not a JavaScript number.
pathOptional- Path relative to the server file root, for example /server/server.properties or /backups. URL-encode query values.
queryRequired- Search term, 2 to 100 characters.
contentOptional- 0 searches names only; 1 also searches bounded text contents.
cursorOptional- Unchanged next_cursor from the previous search response. Keep path, query and content unchanged. Expires after 30 minutes. Omit to start a new search.
200 Request completed successfully.
GET/servers/{id}/backups
List backups
Returns existing backups and backup storage information, subject to the server permissions.
Required permission: backups.read
idRequired- Your server ID as a string, not a JavaScript number.
200 Request completed successfully.
POST/servers/{id}/backups
Create a backup
Queues a tar.gz backup with an automatic timestamp name. A running server requires confirm_stop=true and the power scope. It stops for the backup and restarts after success if still active. Without confirmation, only offline backups are permitted. The backup quota still applies.
Required permission: backups.create
idRequired- Your server ID as a string, not a JavaScript number.
Idempotency-KeyOptional- For a new power or backup action, send a unique Idempotency-Key (up to 200 characters). Reuse it only when retrying that exact action. Retries return the original job instead of executing twice. Retained for the job retention period (90 days for completed jobs).
JSON request body
{
"confirm_stop": true
} 202 Job accepted; execution is pending.
GET/jobs/{id}
Read a job
Returns job status, phases, timestamps and any error/reference. Only the creating API key may read it, and its current server type, scope and server access must still permit it.
Required permission: same_key_as_job_submission
idRequired- Job ID returned when creating the job, as a string.
200 Request completed successfully.
Background jobs
Power actions and backup creation return HTTP 202 with a job object. Poll GET /jobs/{id} with the same key, for example every 5 seconds, until succeeded, failed, canceled or interrupted. HTTP 202 is not a success confirmation for the action itself. job_url opens the web panel; use /jobs/{id} under the API base URL for JSON. The response example below is abbreviated.
For a new power or backup action, send a unique Idempotency-Key (up to 200 characters). Reuse it only when retrying that exact action. Retries return the original job instead of executing twice. Retained for the job retention period (90 days for completed jobs).
{
"job": {
"id": "JOB_ID",
"status": "queued",
"url": "/?member=jobs&job=JOB_ID"
},
"job_url": "/?member=jobs&job=JOB_ID"
}
queued- Queued
running- Running
succeeded- Completed
failed- Failed
canceled- Canceled
interrupted- Operator review required
Responses and errors
200- Request completed successfully.
202- Job accepted; execution is pending.
400- Invalid request or operation failed. Read the error field.
401- Missing, invalid, expired or revoked API key.
403- Server type, account permissions, key scope or CAPTCHA policy denies access.
404- The API endpoint is unknown.
409- Another operation is active for this server.
429- Rate limit reached. Respect Retry-After.
{"error":"api_disabled"}Errors use a machine-readable error field. api_disabled means the server type disallows API access; server_permission means the server or scope is unavailable; captcha requires the web panel. Job failures can include a support reference. Do not retry permission errors or destructive operations blindly.