Skip to content
Coritan Docs

Let customers run their servers

Build a server panel in your storefront, with power and console, files, snapshots, databases, schedules, ports, software and sharing.

View as Markdown

Your storefront's server panel runs on the portal API. It gives a customer the controls that the App Deployment guides describe for a server in the Coritan dashboard, on the servers they bought from you. Every route on this page is under /portal/servers/{uuid}/ or /portal/snapshots/, and takes the customer's token as Authorization: Bearer $CUSTOMER_TOKEN.

Most routes have the same path after {uuid} as the platform's /api/v1/client/servers/{uuid}/ routes and take the same body, so the API sections of the App Deployment guides for servers apply once you change the base path and the token. This page covers what the portal does differently, and the routes those guides do not have.

Shell
curl "https://api.coritan.com/api/v1/orgs/acme/portal/servers/$SERVER_UUID" \
  -H "Authorization: Bearer $CUSTOMER_TOKEN"

The answer is the server as the customer should see it: its name, status, plan limits such as memory_mb and disk_mb, and its join_address. On a free server, ip_address and port are empty and players use the join_address. entitlements lists what the plan includes, and one the plan leaves out has allowed: false with a reason and a detail to show in its place. legacy_backup_count says whether the server has backups worth a tab, sleep holds a free server's sleep state, and lock says whether we have locked the server.

Three fields say what this customer may do:

Field Meaning
is_owner true for the customer whose service it is, and false for a customer the owner shared it with.
permissions ["*"] for the owner. Otherwise, the permissions the owner granted.
capabilities One true or false flag per permission, named with underscores, such as file_read_content. Show or hide each control by these flags.

GET /resources returns the power state and live use of CPU, memory, disk and network, in the shape Use the console and power controls describes. Poll it while the panel is open. GET /status-ping asks a Minecraft server who is online, and never fails: reachable is false when the game does not answer.

The owner can do everything. A customer the owner shared the server with can do what their permissions allow, and a request outside them answers 403 with Insufficient permissions. GET /permissions lists every permission an owner can grant.

Permission Lets the customer
control.console Send console commands.
control.start, control.stop, control.restart Send that power signal. kill needs control.stop. Waking and keeping a free server need control.start.
websocket.connect Open the live console.
file.read, file.read-content List files, and read or download them.
file.create, file.update, file.delete, file.archive Upload, create and copy files, or download one from a URL. Edit, rename and change modes. Delete. Compress and extract.
file.sftp Connect over SFTP.
snapshot.read, snapshot.create, snapshot.restore, snapshot.download, snapshot.delete List, take, restore, download and delete snapshots. Locking one needs snapshot.delete.
backup.read, backup.restore, backup.download, backup.delete List, restore, download and delete old backups. Locking one needs backup.delete.
database.read, database.create, database.update, database.delete List databases, create them, rotate their passwords and delete them.
database.view_password See a database's password, and use the SQL editor and table browser.
schedule.read, schedule.create, schedule.update, schedule.delete See schedules and their runs, create them, change them and their tasks or run them now, and delete them.
allocation.read, allocation.create, allocation.update, allocation.delete See ports, add or request one, choose the primary port or publish one, and release one.
startup.read, startup.update See the Java memory and startup flags, and change them and the startup variables.
settings.rename Rename the server and change its join address subdomain.
settings.reinstall Reinstall the server, change its software, install and remove add-ons, and run world optimization.

Viewing the server, its resources, its sleep state, its software and its custom domain needs no particular permission. Only the owner can share the server, list it in your server directory, and link a custom domain.

Warning

Snapshots belong to the owner's account, not to one server. A customer with snapshot.restore on one server can restore any of the owner's snapshots onto it, including one taken from another server.

The owner shares a server with another customer of your organization by username or email address:

Shell
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/portal/servers/$SERVER_UUID/users" \
  -H "Authorization: Bearer $CUSTOMER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"username_or_email": "alex@example.com", "permissions": ["control.console", "control.start", "control.stop", "file.read", "file.read-content"]}'

A customer with that username or email gets access at once, and we email them. An email address with no customer behind it gets a pending invite instead, with kind set to invite and an expires_at 14 days away. The invite becomes access when a customer with that address signs in to your storefront.

  • GET /users lists who has access, each with id, kind (grant or invite), status, username, email and permissions. A shared customer sees the others by username only, without emails or invites.
  • PUT /users/{subuser_id} with permissions replaces what a customer may do.
  • DELETE /users/{subuser_id} removes a customer or cancels an invite, and we email a customer who was removed. A shared customer can remove themselves the same way, or with POST /users/leave.

Share a server with other users explains each permission in the words the Coritan dashboard uses.

Send a power signal with POST /power:

Shell
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/portal/servers/$SERVER_UUID/power" \
  -H "Authorization: Bearer $CUSTOMER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"signal": "restart"}'

signal is start, stop, restart or kill, and the answer confirms only that we sent it, so read GET /resources for the result. POST /command runs a console command, given as command in the body or in the query string, up to 1,000 characters.

For the live console, GET /websocket returns the socket's address as socket, and the customer's token as token. Open the socket with the token in the token query parameter:

JavaScript
const res = await fetch(`https://api.coritan.com/api/v1/orgs/acme/portal/servers/${uuid}/websocket`, {
  headers: { Authorization: `Bearer ${customerToken}` },
});
const { socket, token } = await res.json();
const ws = new WebSocket(`${socket}?token=${encodeURIComponent(token)}`);
ws.onopen = () => ws.send(JSON.stringify({ event: "send logs", args: [null] }));
ws.onmessage = (message) => {
  const { event, args } = JSON.parse(message.data);
  if (event === "console output") showLine(args[0]);
};

The socket speaks the events that Use the console and power controls lists. Send send command and set state only when the customer holds control.console or the power permission, because the socket refuses them otherwise. When the owner removes a customer's access, the socket closes with code 4003. Do not reopen a socket that closed with 4001, 4003, 4008, 4010 or 4011 until something changes: the token expired, access ended, the session ended, or the server is suspended or gone.

A free server sleeps when nobody plays on it, as How free servers work explains. GET /sleep returns its sleep state: the phase (awake, starting, queued or asleep), sleeps_at to count down from, and the customer's place in the start queue. A paid server answers with policy set to none.

  • POST /wake asks for the server to start. When sleep.challenge_required is true, show the Cloudflare Turnstile challenge first, with the site key from GET /storefront/branding, and send its answer as turnstile_token.
  • POST /keep marks a free server as still in use, which resets its count of days without activity. On a server we suspended for inactivity, it also reactivates the server and cancels its deletion. A paid server answers 409.

A free server with an active paid add-on is not suspended or deleted for inactivity. The add-on is paid for, so the server stays while it lasts, and the inactivity count starts again when the last add-on ends.

The file routes are the ones Manage server files describes, under /files/. Upload with a multipart form, one files part per file:

Shell
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/portal/servers/$SERVER_UUID/files/upload?directory=/plugins" \
  -H "Authorization: Bearer $CUSTOMER_TOKEN" \
  -F "files=@EssentialsX.jar"

Each file can be up to 10 GB, and one request up to 10 GB in all; a request over that answers 413 with {"error":"Request body too large"}. When some files of a batch fail after others have landed, the answer lists the uploaded names in files and the others in failed. POST /files/pull downloads a file from a URL onto the server, GET /files/pull/status reports on it and POST /files/pull/cancel?download_id=... stops it.

GET /sftp returns the host, port and username to connect with. The username is the customer's own email address and a short server reference, so a shared customer signs in as themselves. The password is the customer's storefront password. A customer who signed up with a social account has none until they set one; see Social sign-in. Connect to a server with SFTP covers the rest.

A snapshot saves the server's files to the account, and can be restored onto any of the owner's servers. The Snapshots guides explain how they work and what the storage allowance counts.

  1. Check that one fits with GET /snapshots/estimate. It answers estimated_bytes, remaining_bytes, fits and shortfall_bytes. The estimate is the server's disk use before compression, so the snapshot is never larger.
  2. Take it:
Shell
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/portal/servers/$SERVER_UUID/snapshots" \
  -H "Authorization: Bearer $CUSTOMER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Before the 1.21 update", "ignored_files": ["logs"], "is_locked": true}'

name is up to 191 characters, ignored_files leaves out up to 50 paths, and is_locked keeps the snapshot from being rotated away. With no body, the snapshot is called manual-snapshot.

Route What it does
GET /snapshots Lists this server's snapshots. scope=account lists every snapshot the owner holds, each marked for whether it can restore onto this server. A shared customer gets this server's list either way.
POST /snapshots/{snapshot_uuid}/restore Restores any of the owner's snapshots onto this server. truncate (default true) deletes the current files first, and allow_mismatch confirms a restore from the same game on another loader.
GET /snapshots/{snapshot_uuid}/download Returns a short-lived download url.
POST /snapshots/{snapshot_uuid}/lock Locks or unlocks a snapshot.
DELETE /snapshots/{snapshot_uuid} Deletes a snapshot.
GET /snapshots/seed For a server ordered from a snapshot, the restore it is waiting on or has finished. POST /snapshots/seed/retry runs a failed one again.

The account routes under /portal/snapshots/ do the same for the customer's own snapshots without naming a server, so they work after the server has gone. GET /portal/snapshots lists them, GET /portal/snapshots/allowance returns the storage allowance, and GET, DELETE, POST .../lock and GET .../download act on one. POST /portal/snapshots/{snapshot_uuid}/restore needs target_server_uuid, because there is no server in the path to restore onto.

With automatic backups, we take one snapshot of the server every day and keep the newest 7. Each one is named Automatic backup followed by the date, shows as taken by the platform, and the customer restores, downloads, locks and deletes it like any other snapshot. It counts toward the customer's snapshot storage, as Snapshot storage allowance explains.

A server has them only while it carries the Automatic Server Backups add-on. Your own account plan does not give them to your customers. A server has them only while it carries the add-on, a free server included. A server without the add-on gets none, and ending the add-on stops them. The backups already taken stay until the customer deletes them.

Route What it does
GET /auto-backups Answers whether the server has automatic backups, whether they run and the newest backup. Needs snapshot.read on a shared server.
PUT /auto-backups Pauses or resumes them with {"enabled": false} or {"enabled": true}, and answers as GET does. Only the server's owner can use it. A server without automatic backups answers 409 with the reason in detail.
Shell
curl "https://api.coritan.com/api/v1/orgs/acme/portal/servers/$SERVER_UUID/auto-backups" \
  -H "Authorization: Bearer $CUSTOMER_TOKEN"
JSON
{
  "available": true,
  "enabled": true,
  "paused": false,
  "source": "addon",
  "reason": null,
  "message": null,
  "frequency": "daily",
  "keep": 7,
  "last_run_at": "2026-10-01T03:07:12",
  "next_run_at": "2026-10-02T03:07:12",
  "last_backup": {
    "id": "7f1c2e0a-4b0d-4f0e-9d63-2b0f3c7c1a11",
    "created_at": "2026-10-01T03:07:12",
    "size_bytes": 1073741824
  }
}

available is true when the server has automatic backups. enabled is true while the daily run is on, and paused is true when the customer switched it off. Pausing does not end the add-on or its billing. source is addon, or null when the server has none. last_backup is the newest finished backup, or null, and its id is the snapshot's uuid. The times are in UTC.

reason says in one word why there are none, or why the last run took none, and message says it in a sentence to show the customer:

reason Meaning
not_included The server has no automatic backups. They are an add-on the customer can buy for it, on a free server too.
snapshots_off Snapshots are switched off on the platform, so no backup runs.
no_room The last run did not fit in the customer's snapshot storage. We try again six hours later.

When a new backup does not fit, we first delete the server's own oldest automatic backups, but only when that makes enough room. We never delete a snapshot the customer or a schedule took, a locked backup, or the server's newest backup. When that is not enough we take none and reason is no_room. The customer deletes a snapshot or adds snapshot storage, and the next run takes the backup.

Your storefront can sell three add-ons for a server: extra CPU, automatic backups and Server Management. A customer buys one for one of their own servers, and you bill it on your invoice, in your currency, at your price. Nothing is charged to your Coritan account, and the add-on is a service of its own that the customer cancels like any other (Cancel a service). Set up products and pricing explains how you sell them. A customer who has not ordered yet can buy the same add-ons at checkout: Offer add-ons with a server shows how.

Add-on kind What it gives Most per server
Extra CPU container_cpu One more vCPU for each unit. We raise the server's CPU limit by 100 percent of one core for each unit. 8
Automatic backups container_auto_backups A snapshot every day. See Automatic backups. 1
Server Management server_management The customer asks your team by ticket to install and set up plugins, mods and modpacks. We mark the ticket, as Server Management explains. 1

Only the server's owner can use these routes. A customer the server was shared with gets 403. A free server takes add-ons too, on billing of their own (Add-ons on a free server).

Route What it does
GET /addons Lists what the store sells for this server, with prices, and the add-ons the server has.
POST /addons/preview Prices an order without placing it. Takes kind, quantity and, on a free server, billing_cycle.
POST /addons Places the order. Takes kind, quantity and, on a free server, billing_cycle. It answers as POST /storefront/order does: service_id, invoice_id, requires_payment, total, currency and due_date, with billing, billing_cycle and renewal_amount added.
Shell
curl "https://api.coritan.com/api/v1/orgs/acme/portal/servers/$SERVER_UUID/addons" \
  -H "Authorization: Bearer $CUSTOMER_TOKEN"
JSON
{
  "server": {"uuid": "9f3c0a52-...", "name": "survival", "billing_cycle": "monthly", "next_due_date": "2026-11-05T12:00:00Z", "free": false, "plan_name": "CX2"},
  "offers": [
    {
      "kind": "container_cpu",
      "org_product_id": 41,
      "name": "Extra CPU",
      "description": "One more vCPU on one App Deployment server.",
      "adds": "+1 vCPU",
      "unit_label": "vCPU",
      "max_quantity": 8,
      "attached_quantity": 0,
      "billing": "server",
      "price": {"org_pricing_id": 118, "billing_cycle": "monthly", "amount": "1.99", "currency": "USD"},
      "prices": [{"org_pricing_id": 118, "billing_cycle": "monthly", "amount": "1.99", "currency": "USD"}],
      "orderable": true,
      "reason": null,
      "message": null,
      "applies": "now",
      "notes": ["The server is running. We send the new limit to it as soon as the invoice is paid. If it does not show the extra CPU, restart it."]
    }
  ],
  "attached": []
}

billing says how the add-on is billed. It is server on a paid server: the add-on uses the plan of the server's billing period, so a customer on an annual server sees the annual price, and prices holds that one price. It is own on a free server (Add-ons on a free server), and prices then lists every price you sell for the add-on, one for each billing period. price is the price the order uses when billing_cycle is left out, and price.amount is for one unit. max_quantity is how many more the server takes now, counting orders that wait for payment. When orderable is false, reason says why and message is a sentence to show the customer:

reason Meaning
snapshots_disabled Automatic backups save snapshots, and snapshots are off on the platform.
max_reached The server has the most of this add-on it takes.
unpaid_order An order for this add-on waits for payment. The customer pays it or cancels it first.
no_price_for_cycle You have no price for the server's billing period. Add one under Set up products and pricing.
server_not_ready The server is not active, is still installing, is set to end, is due for renewal, or has no renewal date.
not_available The server's plan has no CPU limit to add to, or the add-on is sold only for other games than the server's. Server Management is sold for Minecraft servers by default.

applies says when the effect reaches the server. For extra CPU it is now while the server is running: we queue a push of the new limit to the server's host when the order is paid, and the host is told to update the running server. A restart makes sure the server uses it. It is after_restart for a stopped server, which uses the new limit from its next start. Automatic backups and Server Management are now. attached lists the add-ons already on the server: org_service_id, kind, quantity, status, the amount it renews at, next_due_date, and cancel_at_end once the customer set it to end with the term.

POST /addons/preview answers with what the order costs:

JSON
{
  "kind": "container_cpu",
  "quantity": 2,
  "billing": "server",
  "billing_cycle": "monthly",
  "unit_price": "1.99",
  "due_now": "2.70",
  "tax": "0.00",
  "renewal_amount": "3.98",
  "renews_at": "2026-11-05T12:00:00Z",
  "days_remaining": 21,
  "days_in_cycle": 31,
  "currency": "USD",
  "adds": "+2 vCPU",
  "applies": "now"
}

On a paid server, due_now is the price for the rest of the server's current billing period, with your tax rate added. The add-on then renews on the server's renewal date, renews_at, at the full renewal_amount, so both are invoiced together. An order for the last day of a period costs nothing now and starts at once.

A paid server takes the add-on in its own billing period only. A billing_cycle that is not the server's answers 422 and names the period to use, so leave it out.

The order refuses with 409 and a reason from the table for a server that cannot take it, and with 422 for a kind your store does not sell or a quantity the server cannot take, such as This server takes 1 more vCPU of Extra CPU. Set quantity to 1. A store with its orders held answers 403. POST /addons/preview and POST /addons share one limit for each customer and server, 20 requests in 10 minutes, and answer 429 past it. The generic POST /storefront/order, your staff's POST /orgs/{org_slug}/services and the admin order route refuse an add-on product with 422 and Order add-ons from the server's page., and the catalogue leaves add-on products out, so no one buys one without a server.

The effect starts when the customer pays the invoice. Extra CPU raises the server's limit to the plan's own CPU plus the add-ons, and a plan change on the server keeps the add-ons on top of the new plan. The effect ends when the customer cancels the add-on (at once, or with the term), when its renewal goes unpaid and we suspend it, and when the server ends. A server that is cancelled or deleted ends its add-ons the same way: now, or at the end of the term the server is cancelled for. A server that moves to your free plan ends its add-ons too, except the ones the customer keeps (Keep add-ons when a server moves to free). POST /portal/services/{id}/keep on the server also withdraws the end date of the add-ons that were set to end with it.

An add-on is never moved to another plan. POST /portal/services/{id}/change-plan, GET /portal/services/{id}/plan-preview and the staff plan change on an add-on answer 409 with Add-ons cannot be moved to another plan. Cancel it and order the one you want., and GET /portal/services/{id}/plans answers an empty list. The customer cancels the add-on and orders the one they want from the server's page.

An add-on renews with the server. When the customer pays the first invoice after the server has already renewed, the add-on takes the server's new renewal date, so the customer is not charged again for time that invoice covered. When your team applies a new price to the subscriptions already on a plan, an add-on renews at the new price for each unit it holds, and the customer's notice and the audit log say that total.

When the server is cancelled now and your storefront credits the unused days of a cancellation, each add-on's unused days are credited the same way, up to what the customer paid for that add-on. A server that ends without a credit, such as a staff termination, gives its add-ons none.

A free server takes the same add-ons as a paid one. It has no price and no renewal date to line up with, so each add-on is billed on its own: billing is own on its offers, its preview and its order.

  • The customer chooses the billing period. GET /addons lists every price you sell in prices, and the order's billing_cycle picks one of them, such as monthly, quarterly or annually. Leave billing_cycle out and the order uses monthly. When you have no monthly price, it uses the first price in prices. A period you have no price for answers 422 with reason set to no_price_for_cycle.
  • The first invoice charges the full price for one period, counted from the day the customer pays. It is never prorated, so days_remaining and days_in_cycle are null on the preview.
  • The add-on renews on that date and never moves to the server's date. It keeps its own date when the server later moves to a paid plan, and the server's renewal does not change it.
  • The effect is the same as on a paid server. Extra CPU adds to the free plan's CPU once the invoice is paid, automatic backups take a snapshot every day, and Server Management works as Add-ons describes.
Shell
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/portal/servers/$SERVER_UUID/addons" \
  -H "Authorization: Bearer $CUSTOMER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"kind": "container_auto_backups", "quantity": 1, "billing_cycle": "annually"}'

Keep add-ons when a server moves to free

Section titled Keep add-ons when a server moves to free

When your organization sells a free plan, cancelling a paid server moves it to the free plan instead of ending it. The customer can keep some of its add-ons on the free server, on billing of their own.

GET /portal/services/{service_id}/cancel-preview lists the server's add-ons in addons, so the cancel page can ask which to keep. Each entry has org_service_id, name, kind, quantity, amount, billing_cycle and next_due_date. The list is empty for a server with none, and an add-on that waits for payment is on it too.

POST /portal/services/{service_id}/cancel takes keep_addon_ids, a list of those org_service_id values:

Shell
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/portal/services/41/cancel" \
  -H "Authorization: Bearer $CUSTOMER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"immediate": true, "keep_addon_ids": [88]}'
  • When the server moves to free, the add-ons named stay active. Each one changes to billing own, loses any end date and renews on its own date at its own price. Every other add-on ends with the server.
  • Leave keep_addon_ids out, or send an empty list, to end every add-on.
  • When the server is deleted, keep_addon_ids is ignored and every add-on ends. That is the case when the customer sets delete_server, and when your organization sells no free plan.
  • An id that is not one of this server's add-ons answers 422, and nothing is cancelled.
  • An end-of-term cancellation takes the same field. The add-ons named are not set to end, and the rest end with the term.

The sweep that moves a server to free for an unpaid renewal keeps its add-ons that are paid for and active, the same way. An add-on that still waits for payment ends.

Snapshots have replaced backups, so POST /backups answers 410 with reason set to replaced_by_snapshots. A server that took backups before keeps them: GET /backups lists them, and restore, download, lock and delete work as Manage server backups describes.

POST /databases creates a database on the server's database host. name_suffix names it with lowercase letters, digits and underscores, up to 48 characters (default db), and remote limits where it accepts connections from (default %, anywhere). Send an Idempotency-Key header so a retry does not create two.

Shell
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/portal/servers/$SERVER_UUID/databases" \
  -H "Authorization: Bearer $CUSTOMER_TOKEN" \
  -H "Idempotency-Key: 1f9e6c2a-luckperms" \
  -H "Content-Type: application/json" \
  -d '{"name_suffix": "luckperms"}'
Route What it does
GET /databases Lists the server's databases.
GET /databases/{database_id}/credentials Returns the password and connection details.
POST /databases/{database_id}/rotate-password Sets a new password.
POST /databases/{database_id}/retry Tries a failed creation again.
DELETE /databases/{database_id} Deletes the database.
POST /databases/{database_id}/query Runs the SQL in sql, up to 65,536 characters, as the database's own user.
GET /databases/{database_id}/tables Lists tables. .../tables/{table}/columns describes one.
GET /databases/{database_id}/tables/{table}/rows Reads rows: limit (1–100, default 50), offset, search, sort and direction.
POST, PATCH /databases/{database_id}/tables/{table}/rows Inserts a row from values, or changes the row whose primary key is key.
POST /databases/{database_id}/tables/{table}/rows/delete Deletes the row whose primary key is key.
GET /databases/{database_id}/tables/{table}/export.csv Downloads the table as CSV. X-Export-Truncated: 1 means it holds only part of the table.
POST .../tables/{table}/truncate, DELETE .../tables/{table} Empties or drops a table.

Create and manage server databases explains the database host and the connection details.

Schedules run tasks on a timetable, as Schedule server tasks describes, with the same body under /schedules/:

Shell
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/portal/servers/$SERVER_UUID/schedules" \
  -H "Authorization: Bearer $CUSTOMER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Nightly restart", "cron_minute": "0", "cron_hour": "4", "cron_day_of_month": "*", "cron_month": "*", "cron_day_of_week": "*", "timezone": "Europe/London", "tasks": [{"action": "command", "payload": {"command": "say Restarting in 60 seconds"}}, {"action": "power", "payload": {"signal": "restart"}, "time_offset": 60}]}'

A shared customer needs schedule.update to change tasks, and also the permission each task's action needs by hand: control.console for a command, the power permission for a power task, and snapshot.create for a snapshot. That way a schedule never does what the customer could not do themselves. GET /schedules/{schedule_uuid}/runs lists recent runs, newest first, and POST /schedules/{schedule_uuid}/execute runs a schedule now.

GET /allocations lists the server's ports and how many it may have, and GET /allocations/available-ports lists free ones. POST /allocations adds a port, with an optional port, notes, and on_dedicated_ip to open it on the server's Floating IP. POST /allocations/{allocation_id}/primary makes a port the one players connect to, POST /allocations/{allocation_id}/publish-port publishes one on the game's default port of a Floating IP, and DELETE /allocations/{allocation_id} releases it. Manage server ports explains each.

Your organization can decide that extra ports on free servers go through a request to your staff instead. GET /allocations/request then answers required: true, with the customer's open_request if they have one, and POST /allocations answers 403 with reason set to request_required. Send the request with a note that says what the port is for:

Shell
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/portal/servers/$SERVER_UUID/allocations/request" \
  -H "Authorization: Bearer $CUSTOMER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"note": "A second port for the web map plugin"}'

note is 3–500 characters. The request opens a conversation in your support inbox tagged port-request, and a second request while one is open returns the first. Your staff add the port as Manage customer servers in the staff console describes.

The software routes are the ones Change the server software and the guides after it describe, under /software/. Reading them needs only access to the server. Changing what the server runs, installing, updating and removing add-ons, resource packs, safe mode and Bedrock packs need settings.reinstall, and the Java memory and startup flags at GET and PATCH /software/jvm need startup.read and startup.update.

  • GET /software/context says what the server runs now. GET /software/catalog, .../catalog/{key}/versions and .../versions/{version}/builds list what it can change to, and POST /software/change changes it. A change that wipes the server needs confirm_server_name.
  • POST /software/search finds add-ons, GET /software/versions/{source_uuid}/{identifier} lists an add-on's versions and GET /software/dependencies/{source_uuid}/{identifier} what one needs. POST /software/install installs one; mode set to replace wipes the server first and needs confirm_server_name.
  • GET /software lists what we installed, GET /software/addons every add-on on disk, and GET /software/updates newer builds. GET /software/installs follows install jobs, which .../cancel and .../retry act on.
  • POST /software/bedrock with enabled turns Bedrock crossplay on or off for a Java server. PUT /software/bedrock/channel with channel set to release or development chooses where Geyser comes from, as Use Geyser development builds describes.
  • POST /software/via with enabled turns ViaVersion and ViaBackwards on or off. Every plugin server has them unless the customer turns them off, as Let players on other Minecraft versions join describes; GET /software/context reports them under via_plugins.

Import files from another host

Section titled Import files from another host

POST /import/test-connection and POST /import/start take the body Import a server from another host describes. Testing needs file.read and starting needs file.create. truncate set to true wipes the server first, so it also needs file.delete and confirm_server_name: the server's name, compared without regard to case. A missing or wrong name answers 400 with Type the server name to confirm a wipe and import, before the rate limit counts the request. start ignores the name without truncate, test-connection ignores it, and a server whose install never finished needs none. start also takes skip_existing, which leaves out files already on the server with the same size, and host_key_fingerprint, the SFTP key the customer confirmed from the host_key that test-connection returns. The import refuses a host that shows another key before it sends any password. The wipe keeps every entry whose name starts with a dot or with backups, and on a free server the server executable the panel installed. GET /import/current returns the running import, GET /import/status/{import_id} reports on one, and DELETE /import/{import_id} stops it. The status has errors for files that could not be copied and skipped for entries left out on purpose (symbolic links, devices, sockets, pipes and the free server's executable), each as file and reason, which never count towards the 200 failed files. While an import is pending, in_progress or cancelling, POST /power with start or restart and POST /wake answer 409 with A file import is running on this server. Start it again when the import finishes. stop and kill still work.

Route What it does
PATCH /settings name renames the server: 2–48 characters with at least one letter or number. world_optimization_enabled turns world optimization on or off. A free server can turn it on but not off.
PATCH /subdomain Changes the first part of the join address: 3–28 lowercase letters, digits and hyphens, not only digits.
GET /startup-variables Every startup variable the server runs with and what its owner may do with each, as the client API answers it (Read startup variables). Needs startup.read.
PATCH /startup-variables Changes or adds startup variables, as variables, and removes the names in remove_variables, under the rule Change startup variables describes: every variable but the platform's own, the Java settings', safe mode's and, on a free server, the one naming the program it runs. They apply at the next restart. Needs startup.update.
POST /reinstall Deletes every file and installs the server again. Send the server's name as confirm_server_name; case does not matter. A server whose install never finished needs no name.
GET /world-optimization What removing unused chunks has done to the world, with its recent runs.
POST /world-optimization Runs world optimization now, once a day, on a stopped server with the setting on.
GET /server-icon The Minecraft server icon, server-icon.png: present, valid (Minecraft shows only a 64×64 PNG), icon as a data URI, and problems for a file the game ignores. support.supported is false on Bedrock and other games. Needs file.read.
POST /server-icon/preview Takes a picture as the multipart field file, up to 10 MB, and answers with a 64×64 PNG for each fit in variants, without saving. SVG is refused, so draw it as a PNG in the browser first. Needs file.create.
POST /server-icon Takes file and a fit of cover, contain or stretch, and saves the icon as server-icon.png. It shows after the next restart. Needs file.create. A file that is not a picture answers 400, and one over 10 MB answers 413.
DELETE /server-icon Removes the icon. Needs file.delete.

The owner can give the join address a name on their own domain, such as play.example.com.

  1. Read GET /custom-domain. expected_cname_target is the address the customer's DNS record must point at.
  2. Ask the customer to add a CNAME record for their name, pointing at that address. For a domain's root, use a DNS provider that flattens CNAME records or offers ALIAS records.
  3. Link it:
Shell
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/portal/servers/$SERVER_UUID/custom-domain" \
  -H "Authorization: Bearer $CUSTOMER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"domain": "example.com", "subdomain": "play", "include_in_list": true}'

subdomain defaults to @, the domain itself. The answer has verification_status: verified when we can see the record, or pending until we can. We keep checking, and POST /custom-domain/verify checks now. When the record stays missing across several checks, the status becomes failed, the name stops working and we email the owner once. It works again by itself when the record returns.

include_in_list shows the custom name in your server directory in place of the join address; change it later with PATCH /custom-domain. DELETE /custom-domain unlinks the name. Changing the server's subdomain moves the address the record must point at, so we email the owner the new one and the name waits as pending until the record moves.

List the server in your directory

Section titled List the server in your directory

When your organization runs a public server directory, the owner decides whether their server appears in it. GET /listing returns hidden, the chosen tags, the available_tags and max_tags, and feature_enabled. PATCH /listing with hidden and tags changes them. Listing a server needs at least one of your tags and a join address. Run a community with a server list, forum and guides covers the directory itself.

Your storefront shows each server with the controls its customer may use, and every request is checked against the owner's grant, so a control your panel shows by mistake still cannot do more than the grant allows.

401 on every call
The customer token is missing, expired or belongs to another organization. See Troubleshooting for customer sign-in.
403 with Access denied
The customer neither owns the server nor has it shared with them. Check the uuid against their services.
403 with Insufficient permissions
The owner has not granted the permission this route needs. Hide the control when its capabilities flag is false.
Only the server owner can manage subusers
A shared customer tried to share the server or change its directory listing. Only the owner can.
409 with reason set to server_deleting
The server is being deleted. Every route refuses it from then on.
423 with reason set to server_locked
We locked the server while we review activity that broke our acceptable use policy. Its files stay. Show the message.
Type the server name to confirm a wipe and reinstall
confirm_server_name is missing or does not match the server's name.
409 with reason set to world_optimization_running
We are removing unused chunks and the server cannot start until that ends. Try again after retry_after_seconds.
File exceeds maximum upload size of 10 GB
Upload the file over SFTP, or download it onto the server from a URL.
Downloading a snapshot is not included on the free plan. …
Free plans leave out snapshot downloads. The customer can still restore the snapshot, or download files one by one from the file routes.
403 with reason set to request_required
Your organization asks for port requests on free servers. Send one with POST /allocations/request.
Extra ports on this server are added from the Network tab, not requested
Port requests are off for this server. Add the port with POST /allocations.
No matching account in this organization
No customer has that username. Use their email address instead, which sends an invite when they have no account yet.
409 with Please try again in a moment.
Adding a user on POST /users met another change to the same records and gave up after three tries. Nothing was added. Send the request again.
This server does not sleep; use the power action to start it.
The server is on a paid plan. Start it with POST /power.

API operations on this page

MethodPathWhat it does
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}Get server
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/addonsThe add-ons this store sells for one of your servers, and the ones the server has
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/addonsBuy an add-on for one of your servers
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/addons/previewWhat buying an add-on charges, before you buy it
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/allocationsList allocations
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/allocationsAdd a port
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/allocations/available-portsAvailable ports
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/allocations/requestGet port request
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/allocations/requestAsk staff for an extra port on a free server whose brand requires it
DELETE/api/v1/orgs/{org_slug}/portal/servers/{uuid}/allocations/{allocation_id}Release a port
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/allocations/{allocation_id}/primaryMake one of the server's ports the one players type
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/allocations/{allocation_id}/publish-portPublish a port on the game's default port of the attached floating IP
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/auto-backupsThis server's automatic backups: whether it has them, whether they run and the last backup
PUT/api/v1/orgs/{org_slug}/portal/servers/{uuid}/auto-backupsPause or resume this server's automatic backups, and answer as GET does
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/backupsList backups
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/backupsCreate backup
DELETE/api/v1/orgs/{org_slug}/portal/servers/{uuid}/backups/{backup_uuid}Delete backup
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/backups/{backup_uuid}/downloadA short-lived signed URL the browser fetches the archive from directly
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/backups/{backup_uuid}/lockKeep a backup, or release it
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/backups/{backup_uuid}/restoreRestore backup
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/commandCommand
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/consoleConsole lines
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/custom-domainVanity CNAME state for this server's join address
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/custom-domainLink a customer hostname
PATCH/api/v1/orgs/{org_slug}/portal/servers/{uuid}/custom-domainShow the vanity hostname, or the hosted one, in the public server list
DELETE/api/v1/orgs/{org_slug}/portal/servers/{uuid}/custom-domainUnlink custom domain
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/custom-domain/verifyCheck the CNAME now rather than waiting for the next maintenance pass
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/databasesList databases
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/databasesCreate database
DELETE/api/v1/orgs/{org_slug}/portal/servers/{uuid}/databases/{database_id}Delete database
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/databases/{database_id}/credentialsGet database credentials
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/databases/{database_id}/queryQuery database
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/databases/{database_id}/retryRetry database
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/databases/{database_id}/rotate-passwordRotate database password
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/databases/{database_id}/tablesList database tables
DELETE/api/v1/orgs/{org_slug}/portal/servers/{uuid}/databases/{database_id}/tables/{table}Drop database table
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/databases/{database_id}/tables/{table}/columnsDescribe database table
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/databases/{database_id}/tables/{table}/export.csvExport database table
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/databases/{database_id}/tables/{table}/rowsRead database rows
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/databases/{database_id}/tables/{table}/rowsInsert database row
PATCH/api/v1/orgs/{org_slug}/portal/servers/{uuid}/databases/{database_id}/tables/{table}/rowsUpdate database row
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/databases/{database_id}/tables/{table}/rows/deleteDelete database row
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/databases/{database_id}/tables/{table}/truncateTruncate database table
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/files/chmodChmod files
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/files/compressCompress files
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/files/contentsFile contents
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/files/copyCopy file
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/files/decompressDecompress file
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/files/deleteDelete files
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/files/downloadDownload file
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/files/listList files
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/files/mkdirMkdir
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/files/pullPull file
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/files/pull/cancelCancel pull
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/files/pull/statusPull status
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/files/renameRename files
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/files/uploadUpload files
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/files/writeWrite file
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/import/currentGet the current server import
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/import/startStart a server import
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/import/status/{import_id}Get the status of a server import
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/import/test-connectionTest the connection to another host
DELETE/api/v1/orgs/{org_slug}/portal/servers/{uuid}/import/{import_id}Stop a server import
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/keepTell us this world is still wanted, and lift a hold if one is on
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/listingPublic-list visibility and tags for the Server Settings tab
PATCH/api/v1/orgs/{org_slug}/portal/servers/{uuid}/listingToggle public-list visibility and replace the listing tags
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/permissionsList grantable permissions
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/powerPower
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/reinstallWipe server files and re-run the template install script + verify
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/resourcesGet resources
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/schedulesList schedules
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/schedulesCreate schedule
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/schedules/{schedule_uuid}Get schedule
PUT/api/v1/orgs/{org_slug}/portal/servers/{uuid}/schedules/{schedule_uuid}Update schedule
DELETE/api/v1/orgs/{org_slug}/portal/servers/{uuid}/schedules/{schedule_uuid}Delete schedule
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/schedules/{schedule_uuid}/executeQueue a run now
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/schedules/{schedule_uuid}/runsRecent runs of a schedule, newest first, with the outcome of every step
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/schedules/{schedule_uuid}/tasksAdd schedule task
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/schedules/{schedule_uuid}/tasks/reorderReorder schedule tasks
PUT/api/v1/orgs/{org_slug}/portal/servers/{uuid}/schedules/{schedule_uuid}/tasks/{task_id}Update schedule task
DELETE/api/v1/orgs/{org_slug}/portal/servers/{uuid}/schedules/{schedule_uuid}/tasks/{task_id}Delete schedule task
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/server-iconThe server's Minecraft server icon, server-icon.png in the server root
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/server-iconConvert a picture to the 64×64 PNG Minecraft accepts and save it as /server-icon.png
DELETE/api/v1/orgs/{org_slug}/portal/servers/{uuid}/server-iconDelete /server-icon.png
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/server-icon/previewRender a picture as a server icon in every fit mode, without saving it
PATCH/api/v1/orgs/{org_slug}/portal/servers/{uuid}/settingsPatch settings
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/sftpConnection details for this server's SFTP login
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/sleepSleep and start-queue state for a free server
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/snapshotsList snapshots
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/snapshotsCreate snapshot
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/snapshots/estimateHow much of the allowance a snapshot of this server would use
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/snapshots/seedThe restore a server ordered from a snapshot is waiting on, or got
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/snapshots/seed/retryRun a failed seed again
DELETE/api/v1/orgs/{org_slug}/portal/servers/{uuid}/snapshots/{snapshot_uuid}Delete snapshot
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/snapshots/{snapshot_uuid}/cancelCancel a snapshot of this server that is still being taken
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/snapshots/{snapshot_uuid}/downloadDownload snapshot
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/snapshots/{snapshot_uuid}/lockKeep a snapshot, or release it
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/snapshots/{snapshot_uuid}/restoreRestore onto this server, from any snapshot this customer owns
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/softwareList installed software
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/addonsEvery addon in the folders the server loads from, tracked or hand-uploaded
DELETE/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/addons/records/{record_uuid}Drop a tracking record whose files are gone, without touching the disk
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/addons/removeDelete one addon from disk, through the tracked uninstall when it has a record
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/addons/toggleSwitch one addon file on or off (Foo.jar <- Foo.jar.disabled)
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/bedrockTurn Bedrock crossplay on or off for one of the customer's Java servers
PUT/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/bedrock/channelChoose where Bedrock crossplay takes Geyser from: release or development
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/bedrock/packsBehavior and resource packs on disk, which are active in the world, and importable uploads
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/bedrock/packs/disable-allEmpty the world's activation lists so it boots on vanilla content; folders stay
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/bedrock/packs/importQueue an import of an uploaded .mcaddon / .mcpack / .zip already on the server
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/bedrock/packs/{pack_uuid}/activeAdd a pack to, or drop it from, the world's activation list
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/bedrock/packs/{pack_uuid}/removeDeactivate a pack, delete its folder, and drop its tracking row
PUT/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/bedrock/texturepack-requiredTexturepack-required: players must accept the resource packs to join
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/catalogSoftware catalog
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/catalog/{key}/versionsSoftware catalog versions
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/catalog/{key}/versions/{version}/buildsPublisher builds of one game version: the loader versions for Fabric/Forge
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/changeChange server software
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/contextSoftware context
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/dependencies/{source_uuid}/{identifier}What a version requires, named, with what is already installed marked
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/game-settingsThe server's game settings in server.properties words, whatever file holds them
PATCH/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/game-settingsChange game settings: {"values": {"difficulty": "hard", "max-players": 20}}
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/installInstall software
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/installsList software installs
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/installs/{install_uuid}Get software install
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/installs/{install_uuid}/cancelCancel software install
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/installs/{install_uuid}/retryRetry software install
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/jvmThe heap slider and the allowlisted startup flags, as the panel shows them
PATCH/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/jvmMove the heap, pick startup flags from the catalog, or reset both
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/resource-packThe server resource pack as server.properties declares it
PUT/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/resource-packPoint players at a pack, from a URL or a marketplace resource pack version
DELETE/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/resource-packStop offering a server resource pack
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/safe-modeArm a one-shot --safeMode start (vanilla datapack only), optionally starting now
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/searchSearch software
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/sourcesSoftware sources
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/updatesNewer compatible builds for the addons the marketplace installed
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/versions/{source_uuid}/{identifier}Software versions
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/viaTurn ViaVersion and ViaBackwards on or off for one of the customer's Java servers
DELETE/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/{record_uuid}Uninstall software
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/software/{record_uuid}/updateQueue an in-place update: the old file is removed, the new build installed
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/startup-variablesEvery startup variable the server runs with, and what its owner may do with each
PATCH/api/v1/orgs/{org_slug}/portal/servers/{uuid}/startup-variablesChange, add or remove the server's startup variables
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/status-pingAsk the game itself who is online
PATCH/api/v1/orgs/{org_slug}/portal/servers/{uuid}/subdomainRename the gameproxy join-address subdomain for this server
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/usersList org subusers
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/usersAdd org subuser
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/users/leaveA subuser drops their own grant
PUT/api/v1/orgs/{org_slug}/portal/servers/{uuid}/users/{subuser_id}Update org subuser
DELETE/api/v1/orgs/{org_slug}/portal/servers/{uuid}/users/{subuser_id}Delete org subuser
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/wakeAsk for a sleeping free server to be started
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/websocketReturn panel WS URL + the caller's bearer token for WS query auth
GET/api/v1/orgs/{org_slug}/portal/servers/{uuid}/world-optimizationWhat unused-chunk cleanup has done to this world, and when
POST/api/v1/orgs/{org_slug}/portal/servers/{uuid}/world-optimizationQueue an unused-chunk trim now, once per minintervalhours
GET/api/v1/orgs/{org_slug}/portal/snapshotsEvery snapshot this customer holds, across every server they have had
GET/api/v1/orgs/{org_slug}/portal/snapshots/allowanceThe account's snapshot meter, read without writing
GET/api/v1/orgs/{org_slug}/portal/snapshots/{snapshot_uuid}One snapshot, for the order form that was handed its uuid in a link
DELETE/api/v1/orgs/{org_slug}/portal/snapshots/{snapshot_uuid}Delete a snapshot the account owns, with or without its source server
POST/api/v1/orgs/{org_slug}/portal/snapshots/{snapshot_uuid}/cancelCancel a snapshot the account owns that is still being taken
GET/api/v1/orgs/{org_slug}/portal/snapshots/{snapshot_uuid}/downloadA signed URL for an archive whose server may no longer exist
POST/api/v1/orgs/{org_slug}/portal/snapshots/{snapshot_uuid}/lockKeep or release a snapshot the account owns, with or without its server
POST/api/v1/orgs/{org_slug}/portal/snapshots/{snapshot_uuid}/restoreRestore an account snapshot onto one of the customer's servers