Appearance
Open endpoints
Public endpoints under /open/*. No authentication required. They are rate-limited per IP at 5 requests per second, so please do not use the status page as a heartbeat monitor with a one-second interval.
Config options
http
GET /open/config-optionsReturns everything the console needs to build the "create a pod" and "create a network" forms: the workloads, sizes, regions, and schedule choices. If you are building your own UI or picking values for an API call, start here so you never hardcode a name that later changes.
Response keys:
| Key | What it is |
|---|---|
podOptions | Workloads you can run, each with its selectable versions, default username, and type (instance or database) |
computeOptions | Compute sizes (name, cpu, ramInMb, description) |
storageOptions | Storage sizes (name, sizeInGb, description) |
servers | Regions you can deploy into - the id is what you pass as serverId when creating a pod |
emailServers | Mail regions available for email hosting, same shape as servers |
scheduleOptions | Auto-schedule choices for snapshots and backups (value, label, description) |
servers lists only regions that can host pods. Ingress-only locations never appear, so anything in this array is a valid serverId.
Response (rates omitted - see below):
json
{
"podOptions": [
{
"id": "6a4d5b83b7006ccae6391900",
"name": "ubuntu",
"description": "Ubuntu",
"versions": ["22.04", "24.04"],
"image": "ubuntu",
"servicePort": 22,
"username": "ubuntu",
"type": "instance"
},
{
"id": "6a4d5b83b7006ccae6391901",
"name": "mysql",
"description": "MySQL",
"versions": ["5.7", "8.0"],
"image": "mysql",
"servicePort": 3306,
"username": "root",
"type": "database"
}
],
"computeOptions": [
{ "id": "6a4d5b83b7006ccae6391910", "name": "tiny", "cpu": 1, "ramInMb": 512, "description": "1 vCPU, 0.5GB RAM" },
{ "id": "6a4d5b83b7006ccae6391911", "name": "small", "cpu": 1, "ramInMb": 1024, "description": "1 vCPU, 1GB RAM" },
{ "id": "6a4d5b83b7006ccae6391912", "name": "medium", "cpu": 1, "ramInMb": 2048, "description": "1 vCPU, 2GB RAM" }
],
"storageOptions": [
{ "id": "6a4d5b83b7006ccae6391920", "name": "tiny", "sizeInGb": 5, "description": "5GB" },
{ "id": "6a4d5b83b7006ccae6391921", "name": "small", "sizeInGb": 10, "description": "10GB" },
{ "id": "6a4d5b83b7006ccae6391922", "name": "medium", "sizeInGb": 20, "description": "20GB" },
{ "id": "6a4d5b83b7006ccae6391923", "name": "large", "sizeInGb": 40, "description": "40GB" }
],
"servers": [
{ "id": "6a4d5b83b7006ccae6391930", "name": "Amsterdam", "region": "eu-west", "publicDnsName": "ams1.microapps.io" }
],
"emailServers": [
{ "id": "6a4d5b83b7006ccae6391940", "name": "Amsterdam Mail", "region": "eu-west", "publicDnsName": "mail1.microapps.io" }
],
"scheduleOptions": [
{ "value": "", "label": "Disabled", "description": "No automatic runs" },
{ "value": "daily", "label": "Daily", "description": "Every day at 3:00 AM UTC" },
{ "value": "weekly", "label": "Weekly", "description": "Every Sunday at 3:00 AM UTC" },
{ "value": "monthly", "label": "Monthly", "description": "On the 1st of every month at 3:00 AM UTC" }
]
}Each compute and storage option also carries an hourlyRate field - the current hourly rate the console uses to price it. It is left out above so nothing here goes stale; for the authoritative numbers, see the pricing page, or GET /open/pricing from code.
Pricing
http
GET /open/pricingThe public price list: compute and storage sizes with their hourly rates, the top-up range, and the backup rate with its start date. It is the same data the pricing page shows, so if you want to estimate a bill in code, start here instead of scraping a web page. Responses carry Cache-Control: public, max-age=300, so you can cache one for five minutes.
Response keys:
| Key | What it is |
|---|---|
compute | Compute sizes (name, description, cpu, ramInMb, hourlyRate), smallest first |
storage | Storage sizes (name, description, sizeInGb, hourlyRate), smallest first |
topUp | The smallest and largest top-up, in whole US dollars (min, max) |
backup | gbHourlyRate (the backup rate per GB-hour), billingStartsAt (when paid backups start, as an RFC 3339 timestamp, or null while no start date has been announced) and freeRetentionDays (how many days free backups last before they are deleted) |
Rates are US dollars per hour, and per GB-hour for backups. The pricing page shows the backup rate per GB a month, which is gbHourlyRate times 730 hours.
Response (numbers are illustrative; current prices are on microapps.io/pricing):
json
{
"compute": [
{ "name": "tiny", "description": "1 vCPU, 0.5GB RAM", "cpu": 1, "ramInMb": 512, "hourlyRate": 0.01 },
{ "name": "small", "description": "1 vCPU, 1GB RAM", "cpu": 1, "ramInMb": 1024, "hourlyRate": 0.02 },
{ "name": "medium", "description": "1 vCPU, 2GB RAM", "cpu": 1, "ramInMb": 2048, "hourlyRate": 0.04 }
],
"storage": [
{ "name": "tiny", "description": "5GB", "sizeInGb": 5, "hourlyRate": 0.001 },
{ "name": "small", "description": "10GB", "sizeInGb": 10, "hourlyRate": 0.002 },
{ "name": "medium", "description": "20GB", "sizeInGb": 20, "hourlyRate": 0.004 },
{ "name": "large", "description": "40GB", "sizeInGb": 40, "hourlyRate": 0.008 }
],
"topUp": { "min": 3, "max": 10000 },
"backup": { "gbHourlyRate": 0.0001, "billingStartsAt": null, "freeRetentionDays": 60 }
}billingStartsAt is null above because that is how it reads until a start date is announced. Once it is set, it is the moment backups start being billed, and backups taken before it stay free for freeRetentionDays days after it.
Legal version
http
GET /open/legalThe current version of the Terms of Service, Acceptable Use Policy, and Privacy Policy, as a date string:
json
{ "termsVersion": "2026-07-22" }Compare it against the acceptedTermsVersion on your profile. If yours is behind, the documents have moved on and you need to accept them again with POST /api/user/accept-terms. The console does this check on every load.
Health
http
GET /open/healthjson
{ "status": "ok" }A liveness check. If this returns anything other than 200, it is us, not you.
Platform status
http
GET /open/statusReturns the public platform status shown at the status page: an overall state and a per-component breakdown. Handy if you want to surface our status inside your own dashboard.
json
{
"status": "operational",
"updatedAt": "2026-09-16T10:14:02Z",
"components": [
{ "name": "Web Hosting & Domains", "status": "operational", "detail": "128 healthy, 0 degraded, 0 down" },
{ "name": "Compute", "status": "degraded", "detail": "2 resource alerts active" }
]
}status on both the whole platform and each component is operational, degraded, or down. The top-level status is the worst of the components, so you can alert on that one field alone.
Email unsubscribe
http
GET /open/unsubscribe/:sessionId
POST /open/unsubscribe/:sessionIdBacks the one-click unsubscribe link in mail sent through MicroApps. The :sessionId is the signed token from the message's List-Unsubscribe header, so there is nothing to construct by hand. Both verbs do the same thing, because some mail clients send one and some the other.
json
{ "message": "You have been unsubscribed successfully" }A forged or expired token returns 400 with "Invalid unsubscribe link" - the same answer either way, so the endpoint cannot be used to probe for valid ids.
Example
bash
curl https://cloud-api.microapps.io/open/statusPull the region ids you can deploy into:
bash
curl -s https://cloud-api.microapps.io/open/config-options \
| jq '.servers[] | {serverId: .id, region, name}'Work out the backup price per GB a month, and whether paid backups have a start date yet:
bash
curl -s https://cloud-api.microapps.io/open/pricing \
| jq '.backup | {perGbMonth: (.gbHourlyRate * 730), startsAt: .billingStartsAt}'