Using the Kyun API
Kyun provides HTTP API access for every user. The public API is the same API that’s used for the Kyun frontend, so everything you can do through the website, you can also do directly through the API.
https://api.kyun.sh/endpoints provides a list of all API endpoints, schemas and usage examples.
There are currently no official Kyun API libraries available. If you prefer having typed helper functions instead of calling the HTTP endpoints directly, you can use openapi-generator with the OpenAPI schema (available here).
Rate Limits
There is a global 100 requests/minute limit, tracked by either the IP address (if not authenticated) or authentication token/API key.
Getting an Authentication Token
If you want to call endpoints that require being logged into an account, you need to provide an authentication token via the HTTP header x-auth-token.
There are 2 types of tokens you can use:
- The token returned by the
/user/logInendpoint, which takes your account hash + password (+ optional one-time passcode, if 2FA is enabled) and returns a temporary token that expires in 7 days, or - An API key generated through the dashboard. API keys never expire (unless you delete them).
For most usecases, using an API key is recommended.
2FA provides additional security in this case. The API key does not provide access to 2FA protected endpoints (such as logging in, generating agent tokens or changing the password) without an one-time passcode.
Node Agent
The Kyun backend has 2 parts: the main API server, which provides most functionality, and the node agent.
The node agent runs on each node (physical server) listening on port 1337, and provides public endpoints for video/text consoles, mounting ISOs and doing cloud-init (quick) installs.
All communication is done via WebSockets.
To call these endpoints, you need a one-time token associated with the VM that can be generated by calling GET /services/danbo/{id}/agentToken. This token needs to be passed as an URL query, e.g. wss://osaka.ro.kyun.network:1337/vnc?token={token}.
The node hostname (e.g. osaka.ro.kyun.network) is available in the Danbo data model, which you can get by calling GET /services/danbo/{id}.
/serial
Provides a rudimentary Serial (text) terminal.
All messages (input and output) are passed to/from the terminal without any transformations.
Compatible with xterm.js and similar TTY implementations.
/vnc
Provides raw VNC access. Compatible with noVNC and any other VNC client. The VNC password is the first 8 characters of the token.
/cloudInit
Downloads and installs a cloud-init enabled image (.img, .qcow2, any other format supported by QEMU) from an URL.
Pass the image URL as a query, e.g. wss://osaka.ro.kyun.network:1337/cloudInit?token={token}&imageUrl={encodedImageUrl}
The server will send progress/error messages.
- If the message starts with
!ERR, treat it as an error. Remove!ERRfrom the beginning and parse the rest as the error message. - If it starts with
!PR, it’s indicating progress. Remove!PRfrom the beginning and treat the rest as a number representing progress (a float from 0 to 1). - If it doesn’t start with
!ERRor!PR, extract the stage number from the start of the message, then treat the remaining part as the title of that stage.
Example parsing implementation in JavaScript:
if (data.startsWith('!ERR')) throw new Error(data.slice(4))
else if (data.startsWith('!PR'))
const progress = Number(data.slice(3))
else {
const stageNumber = data.match(/^(\d+)/)?.[1]
const stageMessage = data.slice(String(stageNumber).length)
}
/downloadIso
Downloads and mounts an ISO file from an URL. Maximum filesize is 10 GB.
Pass the ISO URL as a query, e.g. wss://osaka.ro.kyun.network:1337/uploadIso?token={token}&isoUrl={encodedIsoUrl}.
The server will send progress/error messages, in the same format as /cloudInit.
/uploadIso
Allows you to upload and mount an ISO. This is a complex endpoint that will most likely be rewritten in the future. Maximum filesize is 10 GB.
Once the WS connection is established, the server will send gib. Whenever you receive gib, you must send a 1 MB raw binary chunk of the file, sequentially. When the file is fully uploaded, send EOF.
Here is an example implementation in JavaScript:
const ws = new WebSocket(`wss://osaka.ro.kyun.network:1337/uploadIso?token=${token}`)
const chunkSize = 1024 * 1024
let offset = 0
function sendNextChunk() {
// https://developer.mozilla.org/en-US/docs/Web/API/File
if (offset >= file.size) {
ws.send('EOF')
return
}
const chunk = file.slice(offset, offset + chunkSize)
offset += chunkSize
const reader = new FileReader()
reader.onload = (e) => {
ws.send(e.target.result)
}
reader.readAsArrayBuffer(chunk)
}
await new Promise((res, rej) => {
ws.addEventListener('message', (event) => {
if (event.data === 'gib') {
sendNextChunk()
} else rej(event.data)
})
ws.addEventListener('close', (e) => {
if (e.code !== 1000) return rej()
res()
})
})