🎃 Halloween Sale: get 10% off for life with code
Developer

ServerPrism API

Control your servers programmatically (status, power, console commands, backups) and read your invoices and support tickets from your own scripts, dashboards, and bots.

These API docs are provided in English only — the technical terms (scopes, status codes, header names) are universal across integrations.

On this page

Getting started

  1. Sign in to your ServerPrism account.
  2. Open Account → API Credentials and create a token.
  3. Pick the smallest set of scopes your integration needs.
  4. Copy the token once when it's shown — we never store it in cleartext and cannot recover it.
  5. Use the token as a Bearer credential against the endpoints below.

All requests go to https://serverprism.com. All responses are JSON. All timestamps are UTC ISO-8601.

Authentication

Pass the token in an Authorization: Bearer header. Tokens are personal — each one belongs to a single ServerPrism customer and can only act on services that customer owns.

curl https://serverprism.com/api/v1/client/servers \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Accept: application/json"

Tokens you create through the dashboard are personal access tokens. The OAuth client-credentials and authorization-code flows are not currently exposed for customer integrations.

Scopes

Each token carries one or more scopes. An endpoint requires a specific scope to be present — missing scope returns 403.

Scope Allows
servers:read View your servers (status, resources, basic info)
servers:control Send power signals (start/stop/restart/kill) and console commands to your servers
backups:create Create new backups of your servers (counts against your backup slots)
billing:read View your services' billing details and your invoices (including PDF download)
tickets:read View your support tickets and their replies
tickets:write Open new support tickets and reply to your existing tickets
account:read View your basic account details (name, email address)

Rate limits

Limits are per minute and apply twice: once per token and once across all tokens on your account (whichever runs out first). They are deliberately conservative. If you need more, open a ticket and tell us about your integration.

Bucket Limit Endpoints
read 60 per token, 120 per account All GET endpoints except the invoice PDF
control 20 per token, 30 per account Power, command, create backup, invoice PDF
tickets 5 per token, 10 per account; plus 1 new ticket per 30 seconds Open ticket, reply to ticket

Exceeding a limit returns 429 Too Many Requests with a Retry-After header. Every response carries X-RateLimit-Limit and X-RateLimit-Remaining for the token bucket. Back off and retry; never tight-loop on a 429.

Errors

Error bodies are JSON with a human-readable message and, for API-specific errors, a stable machine-readable error code such as service_not_active. Validation errors (422) also include an errors object keyed by field.

Status Meaning
401Missing or invalid token.
403Token does not include the required scope.
404Not found, or it does not belong to you (both look the same on purpose).
409The server is in a state that doesn't allow this: service_not_active (suspended, cancelled, pending), service_paused (cold storage), server_offline, server_busy, backup_limit_reached, backup_in_progress.
422Request body failed validation.
429Rate limit exceeded.
503Upstream node temporarily unavailable. Retry after a short delay.

Endpoints

Server ID in URLs is the numeric Service ID, the same one in your /services/{id} URL. All paths below are relative to https://serverprism.com/api/v1/client. List endpoints accept page and per_page (max 100) and return a meta block with total and last_page.

GET /api/v1/client/servers scope: servers:read

Lists every active or suspended service owned by the token holder. Cheap to poll: it does not contact the server.

Request

curl https://serverprism.com/api/v1/client/servers \
  -H "Authorization: Bearer YOUR_TOKEN"

Response

{
  "data": [
    {
      "id": 1234,
      "product": "Minecraft 4 GB",
      "service_status": "active",
      "name": "Fred's Minecraft",
      "paused": false,
      "game": { "slug": "minecraft", "name": "Minecraft", "runtime": "paper", "version": "1.21.4" },
      "expires_at": "2026-11-01T00:00:00+00:00"
    }
  ]
}
GET /api/v1/client/servers/{id} scope: servers:read

Everything from the list endpoint plus the connection address players use, the server's ports, its limits, and best-effort live resource usage.

Response

{
  "data": {
    "id": 1234,
    "name": "Fred's Minecraft",
    "service_status": "active",
    "paused": false,
    "game": { "slug": "minecraft", "name": "Minecraft", "runtime": "paper", "version": "1.21.4" },
    "expires_at": "2026-11-01T00:00:00+00:00",
    "address": "fredcraft.example.com",
    "allocations": [
      { "ip": "203.0.113.7", "port": 25565, "primary": true, "notes": null }
    ],
    "limits": {
      "memory_mb": 4096,
      "disk_mb": 25600,
      "cpu_percent": 200
    },
    "resources": {
      "current_state": "running",
      "memory_bytes": 2147483648,
      "cpu_absolute": 18.5,
      "disk_bytes": 7300000000,
      "network_rx_bytes": 12345678,
      "network_tx_bytes": 87654321,
      "uptime_ms": 3600000
    }
  }
}

The resources block may be null if the node was briefly unreachable. Retry, or fall back to the panel UI's status indicator.

POST /api/v1/client/servers/{id}/power scope: servers:control

Sends a power signal to the server. Only works while the service is active: suspended, cancelled or paused services return 409.

Request body

{
  "signal": "start"   // one of: "start", "stop", "restart", "kill"
}

kill hard-terminates the process without giving the game a chance to save. Use stop for graceful shutdowns of survival/save-state games.

Example

curl -X POST https://serverprism.com/api/v1/client/servers/1234/power \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"signal":"restart"}'

Response

{ "data": { "signal": "restart", "sent": true } }
POST /api/v1/client/servers/{id}/command scope: servers:control

Sends a single console command to the running server (e.g. say hello, stop, whitelist add Notch). The server must be running; if it isn't you get 409 server_offline.

Request body

{
  "command": "say Server restarting in 5 minutes"
}

One line, maximum 1024 characters. Newlines and other control characters are rejected with 422: send one request per command.

Response

{ "data": { "command": "say Server restarting in 5 minutes", "sent": true } }
GET /api/v1/client/servers/{id}/backups scope: servers:read

Lists the server's backups and your backup slots. Slots are shared across all your servers and scale with your plan RAM.

Response

{
  "data": [
    {
      "uuid": "6f1c0e2a-...",
      "name": "nightly",
      "status": "completed",      // "in_progress" | "completed" | "failed"
      "size_bytes": 734003200,
      "locked": false,
      "created_at": "2026-09-30T03:00:00+00:00",
      "completed_at": "2026-09-30T03:04:12+00:00"
    }
  ],
  "meta": { "quota": { "used": 2, "total": 3, "can_create_more": true, "is_trial": false } }
}
POST /api/v1/client/servers/{id}/backups scope: backups:create

Starts a backup and returns 202 straight away. Backups run in the background: poll the list endpoint until status is completed or failed. Each backup uses one slot; when you are out of slots you get 409 backup_limit_reached. Trial plans don't include backups (403). Restoring and deleting backups is only available in the dashboard.

Request body (optional)

{ "name": "before-1.21-update" }

Response (202)

{ "data": { "uuid": "9a2b...", "name": "before-1.21-update", "status": "in_progress", "size_bytes": 0, "locked": false, "created_at": "2026-10-01T12:00:00+00:00", "completed_at": null } }
GET /api/v1/client/account scope: account:read

Response

{ "data": { "id": 42, "first_name": "Fred", "last_name": "Smith", "email": "[email protected]", "email_verified": true, "created_at": "2025-03-01T10:00:00+00:00" } }
GET /api/v1/client/services scope: billing:read

All your services in every status, with billing details. Optional filter ?status= one of pending, provisioning, active, suspended, cancelled, failed.

Response

{
  "data": [
    {
      "id": 1234,
      "name": "Fred's Minecraft",
      "product": "Minecraft 4 GB",
      "status": "active",
      "paused": false,
      "plan": { "name": "Monthly", "type": "recurring", "billing_period": 1, "billing_unit": "month" },
      "quantity": 1,
      "price": { "amount": "8.00", "currency": "EUR", "formatted": "€8.00" },
      "next_due_date": "2026-11-01T00:00:00+00:00",
      "cancellation_requested": false,
      "cancellation_type": null,
      "created_at": "2026-05-01T09:12:00+00:00"
    }
  ],
  "meta": { "current_page": 1, "per_page": 25, "total": 1, "last_page": 1 }
}
GET /api/v1/client/invoices scope: billing:read

Your invoices, newest first. Optional filter ?status=pending|paid|cancelled.

Response

{
  "data": [
    {
      "id": 5512,
      "number": "SP-2026-05512",
      "status": "pending",
      "currency": "EUR",
      "total": { "amount": "8.00", "currency": "EUR", "formatted": "€8.00" },
      "tax": { "amount": "1.60", "currency": "EUR", "formatted": "€1.60" },
      "remaining": { "amount": "8.00", "currency": "EUR", "formatted": "€8.00" },
      "due_at": "2026-10-04T00:00:00+00:00",
      "created_at": "2026-09-27T00:00:00+00:00",
      "pdf_url": "https://serverprism.com/api/v1/client/invoices/5512/pdf",
      "dashboard_url": "https://serverprism.com/invoices/SP-2026-05512"
    }
  ],
  "meta": { "current_page": 1, "per_page": 25, "total": 1, "last_page": 1 }
}

To pay an invoice, open its dashboard_url. The API never moves money.

GET /api/v1/client/invoices/{id} scope: billing:read

Same fields as the list plus the line items. {id} is the numeric id, not the invoice number.

Response (excerpt)

{
  "data": {
    "id": 5512,
    "status": "pending",
    "items": [
      { "description": "Minecraft 4 GB (Oct 01, 2026 - Nov 01, 2026)", "quantity": 1, "unit_price": "8.00", "total": "8.00", "service_id": 1234 }
    ]
  }
}
GET /api/v1/client/invoices/{id}/pdf scope: billing:read

Downloads the invoice as a PDF (application/pdf), the same document as the dashboard's download button. Counts against the control rate-limit bucket.

curl -o invoice.pdf https://serverprism.com/api/v1/client/invoices/5512/pdf \
  -H "Authorization: Bearer YOUR_TOKEN"
GET /api/v1/client/tickets scope: tickets:read

Your support tickets, most recently updated first. Optional filter ?status=open|replied|closed. replied means our team answered and is waiting for you.

Response

{
  "data": [
    {
      "id": 1301,
      "subject": "Server lagging in the evening",
      "status": "replied",
      "priority": "medium",
      "department": "Support",
      "service_id": 1234,
      "messages_count": 3,
      "last_message_at": "2026-10-01T09:30:00+00:00",
      "created_at": "2026-09-30T18:02:00+00:00",
      "updated_at": "2026-10-01T09:30:00+00:00",
      "dashboard_url": "https://serverprism.com/tickets/1301"
    }
  ],
  "meta": { "current_page": 1, "per_page": 25, "total": 1, "last_page": 1 }
}
GET /api/v1/client/tickets/{id} scope: tickets:read

The ticket plus its conversation, oldest message first. author is you or staff. Attachments are listed by name; download them from the dashboard.

Response (excerpt)

{
  "data": {
    "id": 1301,
    "status": "replied",
    "messages": [
      { "id": 9001, "author": "you", "author_name": "Fred Smith", "message": "TPS drops every evening", "attachments": [], "created_at": "2026-09-30T18:02:00+00:00" },
      { "id": 9007, "author": "staff", "author_name": "ServerPrism Support", "message": "We moved you to a quieter host...", "attachments": [], "created_at": "2026-10-01T09:30:00+00:00" }
    ]
  }
}
POST /api/v1/client/tickets scope: tickets:write

Opens a ticket. department is required and must be one of the departments shown on the dashboard's new-ticket form. priority is low (default), medium or high. service_id is optional and must be one of your services. One new ticket per 30 seconds per account. Returns 201 with the same body as Get ticket.

Request body

{
  "subject": "Server lagging in the evening",
  "message": "TPS drops to ~12 between 19:00 and 22:00 CET.",
  "department": "Support",
  "priority": "medium",
  "service_id": 1234
}
POST /api/v1/client/tickets/{id}/messages scope: tickets:write

Adds your reply to one of your tickets (up to 20,000 characters). Replying to a closed ticket reopens it, same as on the dashboard. Returns 201 with the new message.

Request body

{ "message": "Still happening tonight, see the timings report." }

Not available via the API

On purpose, the API cannot pay, cancel, upgrade or downgrade services, apply coupons, delete or restore backups, or delete files. Those actions are available in the dashboard, where you can see exactly what they will do before confirming.

Versioning

The v1 namespace is stable. Breaking changes will only happen in a new namespace (v2); we may add new fields to existing responses without warning, so write your client to ignore unknown keys.

Feature requests and bug reports: open a ticket and mention "API".