Appearance
Examples
curl - end-to-end flow
bash
BASE="https://ai.klikg.com"
KEY="sk-..."
# 1. Create a project
PROJECT_ID=$(curl -s -X POST "$BASE/v1/projects" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Runner Demo", "template": "blank" }' | jq -r '.data._id')
# 2. Submit a job (retry on 503 cold start)
until JOB=$(curl -s -f -X POST "$BASE/v1/generate" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d "{
\"projectId\": \"$PROJECT_ID\",
\"prompt\": \"Build a one-button endless runner where you dodge falling blocks.\",
\"settings\": { \"gameType\": \"klik-short\" }
}"); do
echo "engine starting, retrying in 30s..."; sleep 30
done
JOB_ID=$(echo "$JOB" | jq -r '.jobId')
# 3. Poll until terminal
while :; do
STATUS=$(curl -s "$BASE/v1/generate/$JOB_ID/status?projectId=$PROJECT_ID" \
-H "Authorization: Bearer $KEY" | jq -r '.status')
echo "status: $STATUS"
case "$STATUS" in completed|failed|cancelled) break;; esac
sleep 10
done
# 4. Download the game
curl -sL -o game.zip \
"$BASE/v1/generate/$JOB_ID/files?projectId=$PROJECT_ID" \
-H "Authorization: Bearer $KEY"Node.js - autonomous creator loop
A complete script using only built-in fetch (Node 18+). It sends the full creation contract on the first job, then a follow-up job that inherits the persisted instructions.
js
const BASE = process.env.KLIK_BASE ?? 'https://ai.klikg.com';
const KEY = process.env.KLIK_API_KEY; // sk-...
const headers = {
'Authorization': `Bearer ${KEY}`,
'Content-Type': 'application/json',
};
async function api(method, path, body) {
const res = await fetch(`${BASE}${path}`, {
method,
headers,
body: body ? JSON.stringify(body) : undefined,
});
if (!res.ok) {
const err = new Error(`${method} ${path} -> ${res.status}`);
err.status = res.status;
err.body = await res.json().catch(() => null);
throw err;
}
return res.json();
}
// Submit with 503 cold-start retries (up to 8 minutes).
async function submitJob(body) {
const deadline = Date.now() + 8 * 60_000;
for (;;) {
try {
return await api('POST', '/v1/generate', body);
} catch (err) {
if (err.status !== 503 || Date.now() > deadline) throw err;
const wait = (err.body?.retryAfterSeconds ?? 30) * 1000;
console.log(`engine starting, retrying in ${wait / 1000}s...`);
await new Promise(r => setTimeout(r, wait));
}
}
}
async function waitForJob(jobId, projectId) {
for (;;) {
const job = await api(
'GET',
`/v1/generate/${jobId}/status?projectId=${projectId}`
);
console.log(`status: ${job.status}`);
if (['completed', 'failed', 'cancelled'].includes(job.status)) return job;
await new Promise(r => setTimeout(r, 10_000));
}
}
// 1. Project
const project = await api('POST', '/v1/projects', {
name: 'Runner Demo',
template: 'blank',
});
const projectId = project.data._id;
// 2. First job: full creation contract
const first = await submitJob({
projectId,
prompt: 'Build a one-button endless runner where you dodge falling blocks.',
instructions:
'Bold flat-color art, punchy game feel, always a 30-60 second short. ' +
'Be transparent that games are AI-made.',
context: [
{
name: 'research',
content:
'Top-performing runners restart within 3 seconds of failure. ' +
'Difficulty should ramp every 10 seconds.',
},
],
settings: { gameType: 'klik-short', reasoningLevel: 'medium' },
});
await waitForJob(first.jobId, projectId);
// 3. Follow-up job: instructions persist, so only the change request is needed
const second = await submitJob({
projectId,
prompt: 'Tighten the jump gravity and add a combo counter for near-misses.',
context: [
{ name: 'playtest-feedback', content: 'Players said the jump felt floaty.' },
],
});
await waitForJob(second.jobId, projectId);
// 4. Download the ZIP
const zipRes = await fetch(
`${BASE}/v1/generate/${second.jobId}/files?projectId=${projectId}`,
{ headers }
);
const fs = await import('node:fs/promises');
await fs.writeFile('game.zip', Buffer.from(await zipRes.arrayBuffer()));
console.log('saved game.zip');Streaming progress (SSE)
Instead of polling, consume the live event stream:
js
const res = await fetch(
`${BASE}/v1/generate/${jobId}/events?projectId=${projectId}`,
{ headers: { Authorization: `Bearer ${KEY}` } }
);
const reader = res.body.getReader();
const decoder = new TextDecoder();
for (;;) {
const { done, value } = await reader.read();
if (done) break;
process.stdout.write(decoder.decode(value));
}Events include assistant text, tool calls, build results, and the final completion event.