Cloud API
The Colyseus Cloud API gives programmatic access to what the dashboard shows. For now the API is read-only. It returns your applications’ status, CPU, memory, CCU and room count per instance, network egress, deploy history and output, each instance’s recent logs, and your subscriptions and account balance. Use it to feed your own dashboards or monitoring tools.
Beta. The API is enabled per team on request. Email support@colyseus.io with your team name to get access.
Authentication
Once the API is enabled for your team, owners and admins can create tokens on the team’s settings page, under Create API Token. A token can read every application of the team and the team’s billing summary, and nothing else: it cannot deploy or change settings.
A token is shown only once, and never expires. It belongs to the team rather than to whoever created it, so it keeps working if that person leaves. Any owner or admin can delete it, which revokes it immediately.
Send the token as a bearer token:
curl https://cloud-prod.colyseus.io/api/v1/applications \
-H "Authorization: Bearer $COLYSEUS_CLOUD_TOKEN"All times are ISO 8601 in UTC. Applications are addressed by their slug, as returned by /applications. The slug stays the same when you rename the application.
Endpoints
List applications
GET /api/v1/applications
Your team’s applications, with their locations (region, endpoint, plan) and the instances in each location.
{
"data": [{
"id": 1234,
"slug": "1234-my-game",
"name": "My Game",
"maintenance_mode": false,
"created_at": "2026-08-01T09:30:00Z",
"locations": [{
"id": 567,
"region": { "code": "fra", "city": "Frankfurt", "country": "DE" },
"status": "ready",
"scale_strategy": "vertical",
"endpoint": "https://de-fra-1a2b3c4d.colyseus.dev",
"plan": { "vcpus": 1, "ram_mb": 1024, "transfer_gb": 1024 },
"instances": [{
"id": 890,
"endpoint": "https://de-fra-1a2b3c4d.colyseus.dev",
"status": "ready",
"deploy_status": "deployed",
"deployed_at": "2026-09-24T14:02:11Z"
}]
}]
}]
}scale_strategy is vertical (one instance) or horizontal (several instances behind a load balancer). A location’s or instance’s status is one of pending, provisioning, installing, ready, error, destroying, resizing or unpaid. An instance’s deploy_status takes the deploy values, or is null. endpoint is null until the location or instance has an address.
maintenance_mode is true while the application’s maintenance mode is on in the dashboard. plan.transfer_gb is the monthly transfer the plan includes per instance. Egress is not billed; see Egress for your usage.
Current metrics
GET /api/v1/applications/{slug}/metrics/current
Returns each instance’s latest sample (instances report once a minute) and totals per location. In the totals, CCU and rooms are summed, while CPU and memory are the busiest instance’s. An instance that hasn’t reported in the last 5 minutes has null values and is left out of the totals. A location whose instances all went quiet has null totals.
{
"application": "1234-my-game",
"window_minutes": 5,
"locations": [{
"id": 567,
"region": "fra",
"totals": { "ccu": 18, "rooms": 4, "cpu_percent": 12.5, "memory_percent": 41.2 },
"instances": [{
"id": 890,
"sampled_at": "2026-09-25T10:41:00Z",
"ccu": 18,
"rooms": 4,
"cpu_percent": 12.5,
"memory_percent": 41.2,
"processes": [{
"id": 0,
"status": "online",
"started_at": "2026-09-24T14:02:05Z",
"restarts": 0,
"cpu_percent": 12.5,
"memory_mb": 210.4,
"ccu": 18,
"rooms": 4,
"node_version": "24.1.0"
}]
}]
}]
}memory_percent is relative to the plan’s RAM (plan.ram_mb in /applications).
processes lists the instance’s server processes as they last reported, like the Stats page: status is online, launching, stopping, stopped, waiting restart or errored, and restarts is the process manager’s restart counter for it. It is empty when the instance hasn’t reported in the last 5 minutes.
Metrics history
GET /api/v1/applications/{slug}/metrics
| Parameter | Description |
|---|---|
resolution | minute (default) or day. |
from, to | ISO 8601 times. One without an offset is read as UTC. Defaults to the last 24 hours (minute) or the last 30 days (day). A minute window can span at most 24 hours. |
location_id | Only this location. |
Each point covers one location, aggregated like the current totals: CCU and rooms are summed across instances, CPU and memory are the busiest instance’s. A day point adds up each instance’s own peak of that day. Its CCU can therefore exceed what the location reached at any single moment.
With resolution=day, from and to are whole days (a time of day is ignored), and from, to and each point’s time are midnight UTC. to is inclusive at both resolutions.
Metrics are kept for 35 days. A from further back returns a 422.
{
"application": "1234-my-game",
"resolution": "minute",
"from": "2026-09-24T10:41:00Z",
"to": "2026-09-25T10:41:00Z",
"locations": [{
"id": 567,
"region": "fra",
"points": [
{ "time": "2026-09-24T10:41:00Z", "ccu": 20, "rooms": 5, "cpu_percent": 14.1, "memory_percent": 40.8 }
]
}]
}Egress
GET /api/v1/applications/{slug}/egress
Network traffic per location and per day, summed across its instances.
| Parameter | Description |
|---|---|
from, to | Dates (YYYY-MM-DD). Defaults to the last 30 days. Egress is kept for 35 days. |
{
"application": "1234-my-game",
"from": "2026-08-31",
"to": "2026-09-29",
"collected_at": "2026-09-29T15:20:04Z",
"locations": [{
"id": 567,
"region": "fra",
"outgoing_bytes": 48318382080,
"incoming_bytes": 5368709120,
"days": [
{ "date": "2026-09-28", "outgoing_bytes": 1610612736, "incoming_bytes": 178956970 }
]
}]
}We copy these figures from our infrastructure provider every hour; collected_at says when, and is null before the first copy. The latest day keeps growing until it ends. Only instances’ traffic is counted: a multi-instance location’s load balancer isn’t included. Egress is not billed.
Deploys
GET /api/v1/applications/{slug}/deploys?limit=20 lists the most recent deploys first. limit goes from 1 to 50.
{
"application": "1234-my-game",
"data": [{
"id": 4321,
"status": "deployed",
"branch": "main",
"commit": "9fceb02",
"message": "Fix matchmaking timeout",
"started_at": "2026-09-24T14:00:03Z",
"finished_at": "2026-09-24T14:02:11Z"
}]
}status is one of:
none: no instance was ready to take the deploy.enqueued: queued, not started yet.deployingdeployedfailed: this includes a deploy superseded by a newer one before it finished.
commit is the short commit hash, as the dashboard shows it. commit and message are null until the deploy has fetched the code. started_at is when the deploy was triggered. finished_at is null until the deploy is deployed or failed.
GET /api/v1/applications/{slug}/deploys/{id} returns one deploy, under data, with one more field: output, the build and deploy output as plain text.
{
"data": {
"id": 4321,
"status": "deployed",
"branch": "main",
"commit": "9fceb02",
"message": "Fix matchmaking timeout",
"started_at": "2026-09-24T14:00:03Z",
"finished_at": "2026-09-24T14:02:11Z",
"output": "[00:01] Installing dependencies...\nadded 246 packages in 7s\n[00:09] Deployed."
}
}output follows a running deploy. It is kept for 30 days, and always for the application’s 10 most recent deploys; past that, output is null. Deploys older than a year are deleted and return a 404.
Billing
GET /api/v1/billing
Your subscriptions and account balance, as on the Billing page.
{
"account": {
"currency": "usd",
"credit_balance": 25,
"balance_due": 0,
"unused_time_credit": 3.5
},
"applications": [{
"id": 1234,
"slug": "1234-my-game",
"name": "My Game",
"subscription": {
"status": "active",
"monthly_price": 18,
"current_period_end": "2026-10-01T00:00:00Z",
"cancel_at_period_end": false
}
}],
"fetched_at": "2026-09-29T15:02:11Z"
}accountis the billing account of your team’s owner, so its balance is shared with any other team they own. It isnullif the owner has no billing account yet.- Amounts are in
account.currencyunits (dollars, not cents).credit_balanceis prepaid credit that pays future invoices;balance_dueis owed and added to the next one.unused_time_creditcomes from downgrades and cancellations, and applies to the next invoice. subscription.statusisactive,past_due,unpaid,incomplete,incomplete_expired,trialingorcanceled, or the subscription isnullif the application has none.monthly_priceis the list price inaccount.currency, before discounts and taxes.
If billing information can’t be fetched, you get a 503 with code billing_unavailable.
Instance logs
GET /api/v1/applications/{slug}/instances/{id}/logs
The latest lines of an instance’s server logs, as text/plain. Errors are still JSON.
| Parameter | Description |
|---|---|
lines | Up to 500. Rounded up to 100 or 500. Default 100. |
stream | all (default), out (stdout only) or err (stderr only). |
The response keeps the newest 256 KB of output, with colour codes stripped.
This endpoint reads the logs from the instance itself, so it allows 2 requests per minute per team, one at a time per instance. For continuous log collection, send your logs from your server code to your logging service instead.
Limits and freshness
Responses are cached for as long as the data stays current, and their Cache-Control header says for how long. Polling faster than this returns the same data.
Every endpoint draws from one budget of 60 requests per minute per team, shared by all of the team’s tokens. Metrics history and instance logs have a tighter limit of their own on top, and still count toward the 60.
| Endpoint | Refreshes every | Requests per minute |
|---|---|---|
/applications | 60 s | 60, shared |
/metrics/current | 30 s | 60, shared |
/metrics | 60 s (minute), 10 min (day) | 10 |
/egress | 10 min | 60, shared |
/deploys | 15 s | 60, shared |
/billing | 10 min | 60, shared |
/instances/{id}/logs | 60 s | 2 |
Rate-limited responses carry X-RateLimit-Limit and X-RateLimit-Remaining, for the tightest limit on that endpoint. Past a limit, you get a 429 with a Retry-After header in seconds. A cached answer still counts toward the limit.
Errors
Errors have the same shape and a stable code:
{ "error": { "code": "rate_limited", "message": "Too many requests. Retry after the number of seconds in the Retry-After header." } }| Status | code | Meaning |
|---|---|---|
| 401 | unauthenticated | Missing, invalid or revoked token. |
| 403 | api_not_enabled | The API is not enabled for your team yet. |
| 404 | not_found | No such application, deploy or instance in your team. |
| 405 | method_not_allowed | The API only answers GET. |
| 409 | instance_not_ready | The instance isn’t running, so its logs can’t be read. |
| 422 | invalid_request | A parameter is invalid; error.fields maps each one to its messages. |
| 429 | rate_limited, busy | Retry after Retry-After seconds. |
| 500 | server_error | Something failed on our side. |
| 502 | instance_unreachable | The instance didn’t answer the log request. |
| 503 | timeout, busy, unavailable, billing_unavailable | Temporary; retry after Retry-After seconds. |
Under heavy load, the proxy in front of the API can answer a 429, 502 or 504 itself, as plain text rather than JSON. Treat those as temporary too.