Quick start
Sign in and open the API tokens card on your profile page. Create a token with the
readscope and copy it. It is shown once.Sign in to get your API key You will be asked to sign in or create a free account first.
Keep it in an environment variable rather than in your code:
export COREHOST_TOKEN="chk_..."Check the token works:
curl -s https://api.corehost.io/v1/me \ -H "Authorization: Bearer $COREHOST_TOKEN"List your apps. Each app's
idis the one in your dashboard address,corehost.io/control/app/{id}:curl -s https://api.corehost.io/v1/apps \ -H "Authorization: Bearer $COREHOST_TOKEN"Restart one (needs a token with
apps:write):curl -s -X POST https://api.corehost.io/v1/apps/$APP_ID/power \ -H "Authorization: Bearer $COREHOST_TOKEN" \ -H "Content-Type: application/json" \ -d '{"action": "restart"}'
Authentication
Every call except GET /catalog and GET /regions needs an API token in the Authorization header:
Authorization: Bearer chk_...- Tokens start with
chk_. Create, list and revoke them on your profile page, where you can also see when each was last used. We email you each time one is created. - An account can hold 2 active tokens. Revoke one to make room for another.
- A token is shown once, when you create it. We store only a fingerprint, so a lost token can't be recovered: revoke it and make a new one.
- Give each token a name and the scopes it needs, and choose an expiry of 30, 90 or 365 days, or none. Revoking takes effect within 60 seconds.
- Treat a token like a password. Keep it in an environment variable or a secrets manager, never in a repository.
- Tokens can't create other tokens and don't work on the dashboard's own endpoints.
- The API never returns app passwords, generated app secrets, SFTP passwords or console credentials. Recent console output is shown with known secrets masked. Use the dashboard for credentials.
Scopes
Give each token only the scopes it needs. A call outside the token's scopes answers 403 with the code insufficient_scope.
| Scope | Allows |
|---|---|
read | List and view apps with live resource usage, read app logs, list backups, read app settings |
apps:write | Start, stop, restart and kill apps; rebuild an app; create, restore and download backups; change app settings |
apps:delete | Delete backups; delete apps |
billing:read | Read your balance, billing ledger and invoices |
GET /me works with any scope. Downloading a backup needs apps:write because a backup holds all of an app's data.
Rate limits
Limits are per account, across all of its tokens: 120 read requests (GET) and 30 write requests (POST, PATCH and DELETE) per minute. Over the limit you get 429 with a Retry-After header giving the seconds to wait. Every response carries an X-Request-Id header.
HTTP/1.1 429 Too Many Requests
Retry-After: 23
{"error": {"code": "rate_limited", "message": "Too many requests. Wait a moment and try again.", "details": {"retry_after": 23}}, "request_id": "..."}Errors
Every error uses the same envelope. Branch on code, show message to people, and quote request_id if you contact support.
{
"error": {
"code": "insufficient_scope",
"message": "This token does not have the apps:write scope.",
"details": {"required_scope": "apps:write"}
},
"request_id": "5f0c1c9e-8d7a-4b1e-9c0d-2a3b4c5d6e7f"
}| Status | Codes | Meaning |
|---|---|---|
| 400 | invalid_requestinvalid_cursorconfirm_requiredbackup_incomplete | The request was malformed or needs confirmation. Deleting an app and restoring a backup both ask you to confirm. |
| 401 | unauthorized | Missing, malformed, expired or revoked token. |
| 403 | insufficient_scopeforbidden | The token lacks the scope, or the action is not allowed. |
| 404 | not_found | No such app, backup or invoice on your account. Apps on other accounts also answer 404. |
| 409 | app_not_readyapp_busybackup_limit_reachedbackup_lockedidempotency_in_progress | The app cannot do that right now, or an identical request is still running. |
| 429 | rate_limited | Too many requests. Wait Retry-After seconds. |
| 502 | upstream_unavailable | The app platform could not be reached. Safe to retry. |
| 500 | internal_error | Something went wrong on our side. |
A missing or invalid token is refused before it reaches the API; that 401 also carries a top-level message.
Pagination
List endpoints take limit (1 to 100, default 20) and cursor. When there is more, the response has a next_cursor; pass it back as cursor. A null next_cursor means you have everything.
curl -s "https://api.corehost.io/v1/billing/ledger?limit=50&cursor=$NEXT" \
-H "Authorization: Bearer $COREHOST_TOKEN"Idempotency
Add an Idempotency-Key header to a POST, PATCH or DELETE and it is safe to retry after a timeout. Use any unique string of 8 to 64 characters (letters, digits and _ . : -), such as a UUID.
- A repeat with the same key, method and path within 24 hours returns the first answer with
Idempotent-Replayed: trueand does not run again. - A repeat while the first request is still running gets
409 idempotency_in_progress. Wait a moment and retry. - If the first request failed with an error, the key is released and you can retry with it.
- Keys belong to your account. The same key on another account does nothing to yours.
curl -s -X POST https://api.corehost.io/v1/apps/$APP_ID/backups \
-H "Authorization: Bearer $COREHOST_TOKEN" \
-H "Idempotency-Key: $(uuidgen)"Examples
The same calls in three languages. They read the token from COREHOST_TOKEN and the app id from APP_ID. The JavaScript runs on Node 18 or newer and the Python needs pip install requests.
List your apps
Needs the read scope. Follow next_cursor to get every page.
curl -s "https://api.corehost.io/v1/apps?limit=50" \
-H "Authorization: Bearer $COREHOST_TOKEN"const BASE = "https://api.corehost.io/v1";
const headers = { Authorization: `Bearer ${process.env.COREHOST_TOKEN}` };
async function api(path, options = {}) {
const res = await fetch(BASE + path, { ...options, headers: { ...headers, ...options.headers } });
const body = await res.json();
if (!res.ok) throw new Error(`${res.status} ${body.error.code}: ${body.error.message}`);
return body;
}
let cursor = "";
do {
const page = await api("/apps?limit=50" + (cursor ? `&cursor=${cursor}` : ""));
for (const app of page.data) console.log(app.id, app.name, app.power_state);
cursor = page.next_cursor;
} while (cursor);import os, requests
BASE = "https://api.corehost.io/v1"
s = requests.Session()
s.headers["Authorization"] = "Bearer " + os.environ["COREHOST_TOKEN"]
def api(method, path, **kw):
r = s.request(method, BASE + path, timeout=30, **kw)
body = r.json()
if not r.ok:
raise RuntimeError(f"{r.status_code} {body['error']['code']}: {body['error']['message']}")
return body
cursor = None
while True:
page = api("GET", "/apps", params={"limit": 50, "cursor": cursor})
for app in page["data"]:
print(app["id"], app["name"], app["power_state"])
cursor = page["next_cursor"]
if not cursor:
breakGet an app and its live usage
Needs the read scope. The resources object is filled in while the app is running.
curl -s https://api.corehost.io/v1/apps/$APP_ID \
-H "Authorization: Bearer $COREHOST_TOKEN"const BASE = "https://api.corehost.io/v1";
const headers = { Authorization: `Bearer ${process.env.COREHOST_TOKEN}` };
async function api(path, options = {}) {
const res = await fetch(BASE + path, { ...options, headers: { ...headers, ...options.headers } });
const body = await res.json();
if (!res.ok) throw new Error(`${res.status} ${body.error.code}: ${body.error.message}`);
return body;
}
const app = await api(`/apps/${process.env.APP_ID}`);
const r = app.resources;
console.log(app.name, app.power_state);
if (r) console.log(`cpu ${r.cpu_percent}%, memory ${(r.memory_bytes / 1e6).toFixed(0)} MB, disk ${(r.disk_bytes / 1e9).toFixed(2)} GB`);import os, requests
BASE = "https://api.corehost.io/v1"
s = requests.Session()
s.headers["Authorization"] = "Bearer " + os.environ["COREHOST_TOKEN"]
def api(method, path, **kw):
r = s.request(method, BASE + path, timeout=30, **kw)
body = r.json()
if not r.ok:
raise RuntimeError(f"{r.status_code} {body['error']['code']}: {body['error']['message']}")
return body
app = api("GET", f"/apps/{os.environ['APP_ID']}")
r = app["resources"]
print(app["name"], app["power_state"])
if r:
print(f"cpu {r['cpu_percent']}%, memory {r['memory_bytes'] / 1e6:.0f} MB, disk {r['disk_bytes'] / 1e9:.2f} GB")Restart an app
Needs the apps:write scope. The call returns 202 at once; poll the app for power_state.
curl -s -X POST https://api.corehost.io/v1/apps/$APP_ID/power \
-H "Authorization: Bearer $COREHOST_TOKEN" \
-H "Content-Type: application/json" \
-d '{"action": "restart"}'const BASE = "https://api.corehost.io/v1";
const headers = { Authorization: `Bearer ${process.env.COREHOST_TOKEN}` };
async function api(path, options = {}) {
const res = await fetch(BASE + path, { ...options, headers: { ...headers, ...options.headers } });
const body = await res.json();
if (!res.ok) throw new Error(`${res.status} ${body.error.code}: ${body.error.message}`);
return body;
}
await api(`/apps/${process.env.APP_ID}/power`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ action: "restart" }),
});
console.log("restart accepted");import os, requests
BASE = "https://api.corehost.io/v1"
s = requests.Session()
s.headers["Authorization"] = "Bearer " + os.environ["COREHOST_TOKEN"]
def api(method, path, **kw):
r = s.request(method, BASE + path, timeout=30, **kw)
body = r.json()
if not r.ok:
raise RuntimeError(f"{r.status_code} {body['error']['code']}: {body['error']['message']}")
return body
api("POST", f"/apps/{os.environ['APP_ID']}/power", json={"action": "restart"})
print("restart accepted")Back up an app and get the download link
Needs the apps:write scope. A backup runs in the background, so wait for its status to be completed before you ask for the link.
# 1. start the backup and note its id
curl -s -X POST https://api.corehost.io/v1/apps/$APP_ID/backups \
-H "Authorization: Bearer $COREHOST_TOKEN"
# 2. check it until status is "completed"
curl -s https://api.corehost.io/v1/apps/$APP_ID/backups \
-H "Authorization: Bearer $COREHOST_TOKEN"
# 3. get a short-lived download link
curl -s https://api.corehost.io/v1/apps/$APP_ID/backups/$BACKUP_ID/download \
-H "Authorization: Bearer $COREHOST_TOKEN"const BASE = "https://api.corehost.io/v1";
const headers = { Authorization: `Bearer ${process.env.COREHOST_TOKEN}` };
async function api(path, options = {}) {
const res = await fetch(BASE + path, { ...options, headers: { ...headers, ...options.headers } });
const body = await res.json();
if (!res.ok) throw new Error(`${res.status} ${body.error.code}: ${body.error.message}`);
return body;
}
const app = process.env.APP_ID;
const backup = await api(`/apps/${app}/backups`, { method: "POST" });
let status = backup.status;
while (status !== "completed") {
if (status === "failed") throw new Error("backup failed");
await new Promise((r) => setTimeout(r, 10000));
const list = await api(`/apps/${app}/backups?limit=100`);
status = list.data.find((b) => b.id === backup.id)?.status;
}
const link = await api(`/apps/${app}/backups/${backup.id}/download`);
console.log(link.url);import os, requests
BASE = "https://api.corehost.io/v1"
s = requests.Session()
s.headers["Authorization"] = "Bearer " + os.environ["COREHOST_TOKEN"]
def api(method, path, **kw):
r = s.request(method, BASE + path, timeout=30, **kw)
body = r.json()
if not r.ok:
raise RuntimeError(f"{r.status_code} {body['error']['code']}: {body['error']['message']}")
return body
import time
app = os.environ["APP_ID"]
backup = api("POST", f"/apps/{app}/backups")
status = backup["status"]
while status != "completed":
if status == "failed":
raise RuntimeError("backup failed")
time.sleep(10)
page = api("GET", f"/apps/{app}/backups", params={"limit": 100})
status = next((b["status"] for b in page["data"] if b["id"] == backup["id"]), None)
link = api("GET", f"/apps/{app}/backups/{backup['id']}/download")
print(link["url"])Not yet available
This is the first public release, and it covers what most scripts need. These are not in the API yet, so use the dashboard for them:
- Deploying a new app. It needs a payment check we want to get right before it can be called by a script.
- Changing an app's environment variables and plan size.
- Custom domains and the firewall allow-list.
- Browsing and editing an app's files.
- Usage history over time. Live CPU, memory and disk are on
GET /apps/{app_id}.
If one of these would unblock you, tell us. It helps us decide what to build next.
Reference
Generated from the OpenAPI 3.1 description. Download the OpenAPI file to generate a client, or the Postman collection to try the calls by hand. Base URL https://api.corehost.io/v1.
Public
Catalog and regions. No token needed.
/catalogList the apps you can deploy
No token needed
Parameters
currencyquery | Currency Restrict prices to one currency. |
|---|
Example
curl -s https://api.corehost.io/v1/catalogResponses
- 200The app catalog and plan prices.
- 400The request was malformed (
invalid_request,confirm_required,backup_incomplete,invalid_cursor). - 429Too many requests (
rate_limited). WaitRetry-Afterseconds. - 500Something went wrong on our side (
internal_error).
Returns Catalog.
/regionsList regions
No token needed
Example
curl -s https://api.corehost.io/v1/regionsResponses
- 200Every region and whether it takes new apps.
- 429Too many requests (
rate_limited). WaitRetry-Afterseconds. - 500Something went wrong on our side (
internal_error).
Account
The token you are calling with.
/meDescribe the calling token
Any token
Any valid token may call this; no scope is needed.
Example
curl -s https://api.corehost.io/v1/me \
-H "Authorization: Bearer $COREHOST_TOKEN"Responses
- 200The token and the account it belongs to.
- 401Missing, malformed, expired or revoked token (
unauthorized). - 429Too many requests (
rate_limited). WaitRetry-Afterseconds.
Returns Me.
Apps
Your apps, their live state and power controls.
/appsList your apps
Scope read
Newest first. Deleted apps are not listed. Requires read.
Parameters
limitquery | integer |
|---|---|
cursorquery | string The next_cursor from the previous page. |
Example
curl -s https://api.corehost.io/v1/apps \
-H "Authorization: Bearer $COREHOST_TOKEN"Responses
- 200A page of apps.
- 400The request was malformed (
invalid_request,confirm_required,backup_incomplete,invalid_cursor). - 401Missing, malformed, expired or revoked token (
unauthorized). - 403The token lacks the scope this call needs (
insufficient_scope;details.required_scopenames it), or the action is not allowed (forbidden). - 429Too many requests (
rate_limited). WaitRetry-Afterseconds.
/apps/{app_id}Get one app
Scope read
Includes live resource usage when the app is running. Requires read.
Parameters
app_idpath, required | string (uuid) The app's id (a UUID), as shown in your dashboard URL. |
|---|
Example
curl -s https://api.corehost.io/v1/apps/$APP_ID \
-H "Authorization: Bearer $COREHOST_TOKEN"Responses
- 200The app.
- 401Missing, malformed, expired or revoked token (
unauthorized). - 403The token lacks the scope this call needs (
insufficient_scope;details.required_scopenames it), or the action is not allowed (forbidden). - 404No such app or backup on your account (
not_found). Apps on other accounts also answer404. - 429Too many requests (
rate_limited). WaitRetry-Afterseconds.
Returns AppDetail.
/apps/{app_id}Delete an app
Scope apps:delete
Requires apps:delete. Deletes the app and its data now. Billing for the app stops; the rest of your balance stays on the account. To go ahead you must repeat the app id in the query string as ?confirm={app_id}. Take a backup and download it first if you want to keep the data.
Parameters
app_idpath, required | string (uuid) The app's id (a UUID), as shown in your dashboard URL. |
|---|---|
confirmquery, required | string (uuid) Must equal the app id. |
Example
curl -s -X DELETE "https://api.corehost.io/v1/apps/$APP_ID?confirm=$APP_ID" \
-H "Authorization: Bearer $COREHOST_TOKEN"Responses
- 200The app was deleted.
- 400The request was malformed (
invalid_request,confirm_required,backup_incomplete,invalid_cursor). - 401Missing, malformed, expired or revoked token (
unauthorized). - 403The token lacks the scope this call needs (
insufficient_scope;details.required_scopenames it), or the action is not allowed (forbidden). - 404No such app or backup on your account (
not_found). Apps on other accounts also answer404. - 409The app can't do that right now:
app_not_ready(still being set up),app_busy(installing, restoring or updating),backup_limit_reached,backup_locked,token_limit_reached. - 429Too many requests (
rate_limited). WaitRetry-Afterseconds. - 502The app platform could not be reached (
upstream_unavailable). Safe to retry.
/apps/{app_id}/rebuildRebuild an app
Scope apps:write
Requires apps:write. Reinstalls the app's container and pulls its image again. Data on the app's volume is kept. The app restarts; poll GET /apps/{app_id} for power_state. Refused with 409 app_busy while an automatic update is running.
Parameters
app_idpath, required | string (uuid) The app's id (a UUID), as shown in your dashboard URL. |
|---|
Example
curl -s -X POST https://api.corehost.io/v1/apps/$APP_ID/rebuild \
-H "Authorization: Bearer $COREHOST_TOKEN"Responses
- 202The rebuild was started.
- 401Missing, malformed, expired or revoked token (
unauthorized). - 403The token lacks the scope this call needs (
insufficient_scope;details.required_scopenames it), or the action is not allowed (forbidden). - 404No such app or backup on your account (
not_found). Apps on other accounts also answer404. - 409The app can't do that right now:
app_not_ready(still being set up),app_busy(installing, restoring or updating),backup_limit_reached,backup_locked,token_limit_reached. - 429Too many requests (
rate_limited). WaitRetry-Afterseconds. - 502The app platform could not be reached (
upstream_unavailable). Safe to retry.
/apps/{app_id}/powerStart, stop, restart or kill an app
Scope apps:write
Requires apps:write. The action is sent to the app at once; poll GET /apps/{app_id} for power_state. A stopped app bills at the storage-only rate until it is started again. kill stops the app without a clean shutdown; prefer stop.
Parameters
app_idpath, required | string (uuid) The app's id (a UUID), as shown in your dashboard URL. |
|---|
Request body
actionrequired | start | stop | restart | kill |
|---|
Example
curl -s -X POST https://api.corehost.io/v1/apps/$APP_ID/power \
-H "Authorization: Bearer $COREHOST_TOKEN" \
-H "Content-Type: application/json" \
-d '{"action":"restart"}'Responses
- 202The action was accepted.
- 400The request was malformed (
invalid_request,confirm_required,backup_incomplete,invalid_cursor). - 401Missing, malformed, expired or revoked token (
unauthorized). - 403The token lacks the scope this call needs (
insufficient_scope;details.required_scopenames it), or the action is not allowed (forbidden). - 404No such app or backup on your account (
not_found). Apps on other accounts also answer404. - 409The app can't do that right now:
app_not_ready(still being set up),app_busy(installing, restoring or updating),backup_limit_reached,backup_locked,token_limit_reached. - 429Too many requests (
rate_limited). WaitRetry-Afterseconds. - 502The app platform could not be reached (
upstream_unavailable). Safe to retry.
/apps/{app_id}/logsRead recent console output
Scope read
A short snapshot of the app's recent console output (the same stream the dashboard console shows), with colour codes removed. At most 6000 characters, newest at the end. Requires read.
Parameters
app_idpath, required | string (uuid) The app's id (a UUID), as shown in your dashboard URL. |
|---|---|
max_charsquery | integer |
Example
curl -s https://api.corehost.io/v1/apps/$APP_ID/logs \
-H "Authorization: Bearer $COREHOST_TOKEN"Responses
- 200Recent output.
- 400The request was malformed (
invalid_request,confirm_required,backup_incomplete,invalid_cursor). - 401Missing, malformed, expired or revoked token (
unauthorized). - 403The token lacks the scope this call needs (
insufficient_scope;details.required_scopenames it), or the action is not allowed (forbidden). - 404No such app or backup on your account (
not_found). Apps on other accounts also answer404. - 409The app can't do that right now:
app_not_ready(still being set up),app_busy(installing, restoring or updating),backup_limit_reached,backup_locked,token_limit_reached. - 429Too many requests (
rate_limited). WaitRetry-Afterseconds. - 502The app platform could not be reached (
upstream_unavailable). Safe to retry.
Backups
Backups of an app's data.
/apps/{app_id}/backupsList an app's backups
Scope read
Newest first. Requires read.
Parameters
app_idpath, required | string (uuid) The app's id (a UUID), as shown in your dashboard URL. |
|---|---|
limitquery | integer |
cursorquery | string The next_cursor from the previous page. |
Example
curl -s https://api.corehost.io/v1/apps/$APP_ID/backups \
-H "Authorization: Bearer $COREHOST_TOKEN"Responses
- 200A page of backups.
- 400The request was malformed (
invalid_request,confirm_required,backup_incomplete,invalid_cursor). - 401Missing, malformed, expired or revoked token (
unauthorized). - 403The token lacks the scope this call needs (
insufficient_scope;details.required_scopenames it), or the action is not allowed (forbidden). - 404No such app or backup on your account (
not_found). Apps on other accounts also answer404. - 409The app can't do that right now:
app_not_ready(still being set up),app_busy(installing, restoring or updating),backup_limit_reached,backup_locked,token_limit_reached. - 429Too many requests (
rate_limited). WaitRetry-Afterseconds. - 502The app platform could not be reached (
upstream_unavailable). Safe to retry.
/apps/{app_id}/backupsStart a backup
Scope apps:write
Requires apps:write. The backup runs in the background; it is complete when its status is completed. Each app has a limited number of backup slots; when they are full you get 409 backup_limit_reached and should delete an old backup first.
Parameters
app_idpath, required | string (uuid) The app's id (a UUID), as shown in your dashboard URL. |
|---|
Example
curl -s -X POST https://api.corehost.io/v1/apps/$APP_ID/backups \
-H "Authorization: Bearer $COREHOST_TOKEN"Responses
- 202The backup was started.
- 401Missing, malformed, expired or revoked token (
unauthorized). - 403The token lacks the scope this call needs (
insufficient_scope;details.required_scopenames it), or the action is not allowed (forbidden). - 404No such app or backup on your account (
not_found). Apps on other accounts also answer404. - 409The app can't do that right now:
app_not_ready(still being set up),app_busy(installing, restoring or updating),backup_limit_reached,backup_locked,token_limit_reached. - 429Too many requests (
rate_limited). WaitRetry-Afterseconds. - 502The app platform could not be reached (
upstream_unavailable). Safe to retry.
Returns Backup.
/apps/{app_id}/backups/{backup_id}Delete a backup
Scope apps:delete
Requires apps:delete. Locked backups cannot be deleted (409).
Parameters
app_idpath, required | string (uuid) The app's id (a UUID), as shown in your dashboard URL. |
|---|---|
backup_idpath, required | string (uuid) |
Example
curl -s -X DELETE https://api.corehost.io/v1/apps/$APP_ID/backups/$BACKUP_ID \
-H "Authorization: Bearer $COREHOST_TOKEN"Responses
- 200The backup was deleted.
- 401Missing, malformed, expired or revoked token (
unauthorized). - 403The token lacks the scope this call needs (
insufficient_scope;details.required_scopenames it), or the action is not allowed (forbidden). - 404No such app or backup on your account (
not_found). Apps on other accounts also answer404. - 409The app can't do that right now:
app_not_ready(still being set up),app_busy(installing, restoring or updating),backup_limit_reached,backup_locked,token_limit_reached. - 429Too many requests (
rate_limited). WaitRetry-Afterseconds. - 502The app platform could not be reached (
upstream_unavailable). Safe to retry.
/apps/{app_id}/backups/{backup_id}/downloadGet a backup download link
Scope apps:write
Requires apps:write, because a backup holds all of the app's data, including anything secret inside it. Returns a short-lived link. Fetch it soon after you get it and do not share it. Only finished backups can be downloaded.
Parameters
app_idpath, required | string (uuid) The app's id (a UUID), as shown in your dashboard URL. |
|---|---|
backup_idpath, required | string (uuid) |
Example
curl -s https://api.corehost.io/v1/apps/$APP_ID/backups/$BACKUP_ID/download \
-H "Authorization: Bearer $COREHOST_TOKEN"Responses
- 200A download link.
- 401Missing, malformed, expired or revoked token (
unauthorized). - 403The token lacks the scope this call needs (
insufficient_scope;details.required_scopenames it), or the action is not allowed (forbidden). - 404No such app or backup on your account (
not_found). Apps on other accounts also answer404. - 409The app can't do that right now:
app_not_ready(still being set up),app_busy(installing, restoring or updating),backup_limit_reached,backup_locked,token_limit_reached. - 429Too many requests (
rate_limited). WaitRetry-Afterseconds. - 502The app platform could not be reached (
upstream_unavailable). Safe to retry.
/apps/{app_id}/backups/{backup_id}/restoreRestore a backup
Scope apps:write
Requires apps:write. Replaces the app's current data with the backup. You must send {"confirm": true}. Incomplete or near-empty backups are refused (400 backup_incomplete) so a bad archive can't wipe your app. The restore runs in the background.
Parameters
app_idpath, required | string (uuid) The app's id (a UUID), as shown in your dashboard URL. |
|---|---|
backup_idpath, required | string (uuid) |
Request body
confirmrequired | true |
|---|
Example
curl -s -X POST https://api.corehost.io/v1/apps/$APP_ID/backups/$BACKUP_ID/restore \
-H "Authorization: Bearer $COREHOST_TOKEN" \
-H "Content-Type: application/json" \
-d '{"confirm":true}'Responses
- 202The restore started.
- 400The request was malformed (
invalid_request,confirm_required,backup_incomplete,invalid_cursor). - 401Missing, malformed, expired or revoked token (
unauthorized). - 403The token lacks the scope this call needs (
insufficient_scope;details.required_scopenames it), or the action is not allowed (forbidden). - 404No such app or backup on your account (
not_found). Apps on other accounts also answer404. - 409The app can't do that right now:
app_not_ready(still being set up),app_busy(installing, restoring or updating),backup_limit_reached,backup_locked,token_limit_reached. - 429Too many requests (
rate_limited). WaitRetry-Afterseconds. - 502The app platform could not be reached (
upstream_unavailable). Safe to retry.
Settings
Per-app preferences such as update behaviour.
/apps/{app_id}/settingsRead app settings
Scope read
Requires read.
Parameters
app_idpath, required | string (uuid) The app's id (a UUID), as shown in your dashboard URL. |
|---|
Example
curl -s https://api.corehost.io/v1/apps/$APP_ID/settings \
-H "Authorization: Bearer $COREHOST_TOKEN"Responses
- 200The app's settings.
- 401Missing, malformed, expired or revoked token (
unauthorized). - 403The token lacks the scope this call needs (
insufficient_scope;details.required_scopenames it), or the action is not allowed (forbidden). - 404No such app or backup on your account (
not_found). Apps on other accounts also answer404. - 429Too many requests (
rate_limited). WaitRetry-Afterseconds.
Returns AppSettings.
/apps/{app_id}/settingsChange app settings
Scope apps:write
Requires apps:write. Send only the fields you want to change. auto_update can only be turned on for apps that support automatic updates (otherwise 400). Environment variables and the firewall are not available through the API yet.
Parameters
app_idpath, required | string (uuid) The app's id (a UUID), as shown in your dashboard URL. |
|---|
Request body
auto_update | boolean |
|---|---|
notify_on_updates | boolean |
update_window_start_utc | integer, nullable UTC hour that opens the 3 hour update window. Null restores the default. |
Example
curl -s -X PATCH https://api.corehost.io/v1/apps/$APP_ID/settings \
-H "Authorization: Bearer $COREHOST_TOKEN" \
-H "Content-Type: application/json" \
-d '{"notify_on_updates":true,"update_window_start_utc":3}'Responses
- 200The settings after the change.
- 400The request was malformed (
invalid_request,confirm_required,backup_incomplete,invalid_cursor). - 401Missing, malformed, expired or revoked token (
unauthorized). - 403The token lacks the scope this call needs (
insufficient_scope;details.required_scopenames it), or the action is not allowed (forbidden). - 404No such app or backup on your account (
not_found). Apps on other accounts also answer404. - 429Too many requests (
rate_limited). WaitRetry-Afterseconds. - 502The app platform could not be reached (
upstream_unavailable). Safe to retry.
Returns AppSettings.
Billing
Your prepaid balance, its ledger and your invoices.
/billingBalance and burn rate
Scope billing:read
Requires billing:read.
Example
curl -s https://api.corehost.io/v1/billing \
-H "Authorization: Bearer $COREHOST_TOKEN"Responses
- 200Your balance.
- 401Missing, malformed, expired or revoked token (
unauthorized). - 403The token lacks the scope this call needs (
insufficient_scope;details.required_scopenames it), or the action is not allowed (forbidden). - 429Too many requests (
rate_limited). WaitRetry-Afterseconds.
Returns Billing.
/billing/ledgerBalance ledger
Scope billing:read
Every change to your balance, newest first: top-ups, hourly usage draws, credits and refunds. Requires billing:read.
Parameters
limitquery | integer |
|---|---|
cursorquery | string The next_cursor from the previous page. |
Example
curl -s https://api.corehost.io/v1/billing/ledger \
-H "Authorization: Bearer $COREHOST_TOKEN"Responses
- 200A page of ledger entries.
- 400The request was malformed (
invalid_request,confirm_required,backup_incomplete,invalid_cursor). - 401Missing, malformed, expired or revoked token (
unauthorized). - 403The token lacks the scope this call needs (
insufficient_scope;details.required_scopenames it), or the action is not allowed (forbidden). - 429Too many requests (
rate_limited). WaitRetry-Afterseconds.
/invoicesList invoices
Scope billing:read
One invoice per paid top-up, newest first. Invoice numbers look like CHIO- followed by random characters. Requires billing:read.
Example
curl -s https://api.corehost.io/v1/invoices \
-H "Authorization: Bearer $COREHOST_TOKEN"Responses
- 200Your invoices.
- 401Missing, malformed, expired or revoked token (
unauthorized). - 403The token lacks the scope this call needs (
insufficient_scope;details.required_scopenames it), or the action is not allowed (forbidden). - 429Too many requests (
rate_limited). WaitRetry-Afterseconds. - 502The app platform could not be reached (
upstream_unavailable). Safe to retry.
/invoices/{number}Get an invoice PDF link
Scope billing:read
Returns a short-lived link to the invoice PDF. Requires billing:read.
Parameters
numberpath, required | string An invoice number from GET /invoices. |
|---|
Example
curl -s https://api.corehost.io/v1/invoices/$INVOICE_NUMBER \
-H "Authorization: Bearer $COREHOST_TOKEN"Responses
- 200A link to the PDF.
- 401Missing, malformed, expired or revoked token (
unauthorized). - 403The token lacks the scope this call needs (
insufficient_scope;details.required_scopenames it), or the action is not allowed (forbidden). - 404No such app or backup on your account (
not_found). Apps on other accounts also answer404. - 429Too many requests (
rate_limited). WaitRetry-Afterseconds. - 502The app platform could not be reached (
upstream_unavailable). Safe to retry.
Objects
App
id | string (uuid) The app's public id. |
|---|---|
name | string Your label for the app. |
app | object |
region | string, nullable |
plan | object |
status | provisioning | active | suspended | deleted Lifecycle. provisioning: ordered, still being placed or set up. active: provisioned. suspended: paused for an unpaid balance. deleted: gone. |
power_state | running | starting | stopping | offline | installing | provisioning | unknown Live state of the app's container. unknown when the platform did not answer in time. |
billing_mode | active | paused paused while stopped: only storage is billed. |
url | string, nullable (uri) |
hostname | string, nullable |
created_at | string, nullable (date-time) |
AppDetail
id | string (uuid) The app's public id. |
|---|---|
name | string Your label for the app. |
app | object |
region | string, nullable |
plan | object |
status | provisioning | active | suspended | deleted Lifecycle. provisioning: ordered, still being placed or set up. active: provisioned. suspended: paused for an unpaid balance. deleted: gone. |
power_state | running | starting | stopping | offline | installing | provisioning | unknown Live state of the app's container. unknown when the platform did not answer in time. |
billing_mode | active | paused paused while stopped: only storage is billed. |
url | string, nullable (uri) |
hostname | string, nullable |
created_at | string, nullable (date-time) |
resources | object, nullable Live usage; null when unavailable. |
note | string, nullable Human hint when the state is not plain running/offline. |
AppSettings
id | string (uuid) |
|---|---|
auto_update | boolean |
notify_on_updates | boolean |
update_window_start_utc | integer, nullable |
Backup
id | string (uuid) |
|---|---|
name | string, nullable |
status | in_progress | completed | failed |
size_bytes | integer, nullable |
locked | boolean |
sha256 | string, nullable |
created_at | string, nullable (date-time) |
completed_at | string, nullable (date-time) |
Billing
balance | number May be negative while an unpaid balance is in grace. |
|---|---|
currency | Currency |
monthly_burn | number Sum of every running app's monthly rate. |
days_remaining | integer, nullable Days the balance lasts at the current burn; null when nothing is drawing. |
low_balance_since | string, nullable (date-time) |
grace_days | integer |
apps | object |
auto_topup | object |
LedgerEntry
id | string |
|---|---|
type | string e.g. topup, draw, welcome, admin_credit, refund, adjustment. |
amount | number Positive for money in |
balance_after | number |
currency | Currency |
description | string, nullable |
created_at | string (date-time) |
apps | object, nullable For usage draws, the amount drawn per app id. |
Invoice
number | string |
|---|---|
doc_type | string, nullable |
title | string, nullable |
issued_at | string, nullable (date-time) |
paid_at | string, nullable (date-time) |
currency | string, nullable |
total | number |
tax_amount | number |
tax_treatment | string, nullable |
description | string, nullable |
status | string |
refunded | boolean |
Me
token | object |
|---|---|
account | object |
Region
id | string |
|---|---|
name | string |
country | string, nullable |
status | available | waitlist |
CatalogApp
id | string |
|---|---|
name | string |
tagline | string, nullable |
description | string, nullable |
category | string, nullable |
min_plan | string, nullable |
regions | array of string |
docs_url | string, nullable (uri) |
website | string, nullable (uri) |
icon | string, nullable |
auto_update_available | boolean |
Plan
name | string |
|---|---|
vcpu | number |
memory_mb | integer |
disk_gb | integer |
prices | object Monthly price per currency. |
Error
error | object |
|---|---|
request_id | string |
Questions or something missing? Open a support ticket. Building on an open-source app we host? See the revenue share for developers.