Console Client
Documentation
Dashboard
API

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.

Need a hand?

Check the troubleshooting guide or return to all guides.