API code examples
Working curl, Python, and Node.js examples: a small client, a chat listener, and a keep-online watchdog.
Set up
Every example reads the key from the CC_API_KEY environment variable, so the key never appears in your code. Set it once in the shell that runs your script:
export CC_API_KEY="cc-api-YOUR_KEY_HERE"On Windows PowerShell use $env:CC_API_KEY = "cc-api-YOUR_KEY_HERE". The Python examples need the requests package (pip install requests). The Node.js examples need Node 18 or newer and no packages.
curl
BASE="https://dashboard.consoleclient.com/api/v1"
curl "$BASE/accounts" -H "Authorization: Bearer $CC_API_KEY"
curl -X POST "$BASE/accounts/[email protected]/connect" \
-H "Authorization: Bearer $CC_API_KEY"
curl -X POST "$BASE/chat/send" \
-H "Authorization: Bearer $CC_API_KEY" \
-H "Content-Type: application/json" \
-d '{"accountId": "[email protected]", "message": "/balance"}'
curl -X PATCH "$BASE/settings" \
-H "Authorization: Bearer $CC_API_KEY" \
-H "Content-Type: application/json" \
-d '{"serverHost": "mc.example.org"}'Python: a small client
One function that adds the key, raises a clear error, and waits when the API says to slow down.
import os
import time
import requests
BASE = "https://dashboard.consoleclient.com/api/v1"
session = requests.Session()
session.headers["Authorization"] = "Bearer " + os.environ["CC_API_KEY"]
class ApiError(Exception):
def __init__(self, status, body):
super().__init__(f"{status} {body.get('error')}")
self.status = status
self.code = body.get("error")
self.body = body
def api(method, path, body=None, params=None, timeout=35):
for attempt in range(4):
r = session.request(method, BASE + path, json=body, params=params, timeout=timeout)
if r.status_code == 200:
return r.json()
data = r.json() if r.headers.get("content-type", "").startswith("application/json") else {}
if r.status_code == 429 and data.get("error") == "rate_limited":
time.sleep(int(r.headers.get("Retry-After", "5")))
continue
if r.status_code in (500, 503, 504):
time.sleep(2 ** attempt)
continue
raise ApiError(r.status_code, data)
raise ApiError(r.status_code, data)
for account in api("GET", "/accounts")["accounts"]:
print(account["id"], account["username"], account["status"])Python: keep accounts online
Reconnects any account that has been offline with nothing scheduled. Console Client already reconnects accounts on its own, so this is for accounts you want back even after a kick that stops the automatic reconnect. It uses the client above.
WATCH = {"[email protected]", "[email protected]"}
DOWN = {"disconnected", "kicked", "error"}
while True:
for account in api("GET", "/accounts")["accounts"]:
if account["id"] not in WATCH:
continue
if account["status"] in DOWN and not account["reconnectPending"]:
try:
api("POST", f"/accounts/{account['id']}/connect")
print("connecting", account["id"])
except ApiError as e:
print("could not connect", account["id"], e.code)
time.sleep(5)
time.sleep(30)Python: react to chat
Follows chat for every account with one long poll and answers a trigger word. It uses the client above.
cursor = api("GET", "/chat", params={"limit": 1})["cursor"]
while True:
page = api("GET", "/chat", params={"since": cursor, "wait": 25000})
cursor = page["cursor"]
for line in page["messages"]:
print(line["accountId"], line["text"])
if "!where" in line["text"]:
me = api("GET", f"/accounts/{line['accountId']}")["account"]
pos = me["position"]
if pos:
api("POST", "/chat/send", {
"accountId": line["accountId"],
"message": f"I am at {int(pos['x'])} {int(pos['y'])} {int(pos['z'])}",
})Node.js: a small client
const BASE = "https://dashboard.consoleclient.com/api/v1";
const KEY = process.env.CC_API_KEY;
async function api(method, path, body) {
for (let attempt = 0; attempt < 4; attempt++) {
const res = await fetch(BASE + path, {
method,
headers: {
Authorization: "Bearer " + KEY,
...(body ? { "Content-Type": "application/json" } : {})
},
body: body ? JSON.stringify(body) : undefined
});
const data = await res.json().catch(() => ({}));
if (res.ok) return data;
if (res.status === 429 && data.error === "rate_limited") {
await new Promise((r) => setTimeout(r, Number(res.headers.get("retry-after") || 5) * 1000));
continue;
}
if ([500, 503, 504].includes(res.status)) {
await new Promise((r) => setTimeout(r, 1000 * 2 ** attempt));
continue;
}
throw Object.assign(new Error(res.status + " " + data.error), { status: res.status, code: data.error, body: data });
}
throw new Error("gave up after 4 attempts");
}
const { accounts } = await api("GET", "/accounts");
for (const a of accounts) console.log(a.id, a.username, a.status);Save it as an .mjs file so the top-level await works.
Node.js: run a macro and wait for it
Starts a saved macro on an account and waits until it is no longer in the active list. It uses the client above.
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function runMacroAndWait(macroName, accountId) {
const { macros } = await api("GET", "/macros");
const macro = macros.find((m) => m.name === macroName);
if (!macro) throw new Error("no macro called " + macroName);
const { runId } = await api("POST", "/macros/" + macro.id + "/run", { accountId });
for (;;) {
await sleep(3000);
const { runs } = await api("GET", "/macros/active");
if (!runs.some((r) => r.runId === runId)) return;
}
}
await runMacroAndWait("Sell loop", "[email protected]");
console.log("macro finished");A note on Discord bots
A common use of the API is your own Discord bot with commands such as “connect all” or “say”. Keep the API key in the bot’s environment on your server, never in a slash command option or a message, and whitelist that server’s IP. Check who is allowed to use each command inside your bot: the API cannot tell your Discord users apart, because every request arrives with your one key.
Check the troubleshooting guide or return to all guides.