Authentication
All Builder API requests require a Builder API key passed as a Bearer token:
Authorization: Bearer wlk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Keys start with wlk_ and are generated in your dashboard under Builder API. Each key is tied to your account — builds and AI credits run against your plan.
Get a key: Dashboard → Builder API → Create key → copy the full key (shown once) → optionally download a pre-configured index.html.
Security scope: Builder keys are hard-limited to the 7 endpoints on this page. A key cannot list your projects, read files, access secrets, or delete anything. Revoke anytime from the dashboard.
Base URL & CORS
https://api.aicodesit.com
All 7 builder endpoints return Access-Control-Allow-Origin: *, so your page can be hosted on any domain — static hosting, file://, or localhost. No proxy or server needed.
The build flow
Every build follows three steps:
1. POST /projects → create a workspace (do this once, persist the ID)
2. POST /pipeline/:id/run → start an AI build → returns { runId }
3. GET /pipeline/:id/run/:runId/stream → stream live events until "complete"
After the stream completes, poll GET /projects/:id/preview every 2–3 seconds until the preview is live, then render the URL in an <iframe>.
1. Create a project
Creates a new isolated project workspace. Call this once per user session and store the returned id in localStorage.
Request body
| Field | Type | Description | |
|---|---|---|---|
| name | string | required | Human-readable project name. |
| subdomain | string | required | Globally unique subdomain for the preview URL. Lowercase alphanumeric and hyphens only. Safe pattern: yourprefix- + 6 random digits. |
| template_repo | string | optional | Starter template id from GET /projects/templates. The project is created with the template's files — a working site before any prompt is sent. Omit for the minimal default. Unknown ids return 400. |
POST /projects
Authorization: Bearer wlk_...
Content-Type: application/json
{
"name": "my-app-123456",
"subdomain": "my-app-123456"
}
Response 200
{
"id": "3af2cfcb-7127-4aff-ab63-257372d810d9",
"subdomain": "my-app-123456",
"status": "pending",
...
}
Persist the id — it is required by all subsequent calls.
2. Start an AI build run
Starts an AI build in the background and immediately returns a runId. Connect to the stream endpoint to receive live events.
Request body
| Field | Type | Description | |
|---|---|---|---|
| userMessage | string | required | The current user prompt. |
| conversationHistory | array | required | Full conversation array including the current message. Each item: { role: "user"|"assistant", content: "..." }. Must include the current message — see note below. |
| model | string | optional | Model id from GET /pipeline/models. Overrides the AI model for the whole run. Omit to use the platform default. Unknown ids return 400. |
userMessage and inside conversationHistory. The AI engine reads the task from conversation history. Omitting it from history causes the model to respond as if no task was given.
First turn
{
"userMessage": "Build me a landing page for a coffee shop",
"conversationHistory": [
{ "role": "user", "content": "Build me a landing page for a coffee shop" }
]
}
Follow-up turn (include previous turns)
{
"userMessage": "Now make the header dark",
"conversationHistory": [
{ "role": "user", "content": "Build me a landing page for a coffee shop" },
{ "role": "assistant", "content": "I've created a landing page with a warm color scheme..." },
{ "role": "user", "content": "Now make the header dark" }
]
}
Include the last 6–8 turns max. Older history can be trimmed without affecting quality.
Response 200
{ "runId": "c284d4a9-2708-4f7e-956c-35e49da0d834" }
3. Stream build events (SSE)
Returns a Server-Sent Events stream. Each line is:
data: { ...event object... }
Event types
| event | Description | Key fields |
|---|---|---|
| start | A pipeline step started | stepId |
| log | Activity line — file ops, status | data (string) |
| chunk | Fragment of the AI text response | data (string) |
| messages | Internal message array snapshot | — |
| done | A step completed | stepId, output |
| error | A step error | error (string) |
| loop_iter | Loop iteration counter | — |
| complete | Run finished — close the stream | — |
Log event markers
log events contain human-readable status and file markers you can parse:
[wrote: src/index.html] → file created
[edited: src/pages/Home.tsx] → file modified
[deleted: src/old.js] → file removed
Chunk events
Strip internal AI working tags before displaying chunk text: <think>, <file>, <edit>, <gather>, <cmd>.
Stream parsing (JavaScript)
const stream = await fetch(
`https://api.aicodesit.com/pipeline/${projectId}/run/${runId}/stream`,
{ headers: { Authorization: 'Bearer ' + KEY } }
);
const reader = stream.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
outer: while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop() || '';
for (const line of lines) {
if (!line.startsWith('data: ')) continue;
const evt = JSON.parse(line.slice(6));
if (evt.event === 'complete') { reader.cancel(); break outer; }
if (evt.event === 'log') console.log('[log]', evt.data?.trim());
if (evt.event === 'chunk') appendToChat(evt.data || '');
if (evt.event === 'error') console.error('[error]', evt.error);
}
}
4. Stop a running build
Aborts the AI run immediately. File changes made before the stop are kept.
Response 200: { "ok": true }
5. Get preview status
Starts the live preview server on first call. Poll every 2–3 seconds until status === "ready", then load the previewUrl in an <iframe>.
Response 200
{
"status": "ready",
"previewUrl": "https://my-app-123456.aicodesit.app/"
}
| status | Meaning |
|---|---|
| building | Preview server is starting up — keep polling |
| ready | Preview is live — render the previewUrl in an iframe |
| error | Server error — retry or call POST /projects/:id/rebuild |
async function waitForPreview(projectId) {
const API = 'https://api.aicodesit.com';
const headers = { Authorization: 'Bearer ' + KEY };
while (true) {
const { status, previewUrl } = await fetch(
`${API}/projects/${projectId}/preview`, { headers }
).then(r => r.json());
if (status === 'ready') return previewUrl;
if (status === 'error') throw new Error('Preview failed');
await new Promise(r => setTimeout(r, 2500));
}
}
const url = await waitForPreview(projectId);
document.querySelector('#preview').src = url;
6. List selectable models
Returns the AI models a build run can use — pass one of the ids as the optional model field when starting a run. The list only contains models the platform has enabled for building (image/video models are excluded).
Response 200
{
"models": [
{ "id": "qwen/qwen3.7-plus", "label": "Aicodesit", "free": false },
{ "id": "deepseek/deepseek-v4-flash", "label": "DeepSeek V4", "free": false }
]
}
Model picker (JavaScript)
const { models } = await fetch('https://api.aicodesit.com/pipeline/models', {
headers: { Authorization: 'Bearer ' + KEY },
}).then(r => r.json());
// render a <select> and send the chosen id with the run:
await fetch(`${API}/pipeline/${projectId}/run`, {
method: 'POST',
headers: { ...headers, 'Content-Type': 'application/json' },
body: JSON.stringify({
userMessage: msg,
conversationHistory: [{ role: 'user', content: msg }],
model: select.value || undefined, // omit for the default model
}),
});
7. List starter templates
Returns the platform's starter templates. Pass an id as template_repo when creating a project — the project starts as a complete working site built from the template, no first prompt required. Call GET /projects/:id/preview right after creation to show it live.
Response 200
{
"templates": [
{ "id": "starter-template", "label": "Starter Template", "description": "Simple starter template" },
{ "id": "template-2", "label": "Template 2", "description": "Modern landing page template" },
{ "id": "react-starter", "label": "React Starter", "description": "Vite + React + Tailwind starter" },
{ "id": "nextjs-starter", "label": "Nextjs Starter", "description": "Next.js full-stack starter" }
]
}
Create a project from a template (JavaScript)
const { templates } = await fetch(API + '/projects/templates', { headers }).then(r => r.json());
// let the visitor pick, then:
const project = await fetch(API + '/projects', {
method: 'POST',
headers: { ...headers, 'Content-Type': 'application/json' },
body: JSON.stringify({
name: 'my-app-123456',
subdomain: 'my-app-123456',
template_repo: picked.id, // e.g. "react-starter"
}),
}).then(r => r.json());
// the template is already a working site — show it immediately:
const previewUrl = await waitForPreview(project.id);
The list is fully dynamic — templates added to the platform appear here automatically.
Key management
These endpoints require a regular user session token (not a builder key) — they are for dashboard use, not embedded in a public page.
| Method | Path | Description |
|---|---|---|
| GET | /builder-keys | List your active keys |
| POST | /builder-keys | Create a new key |
| DELETE | /builder-keys/:id | Revoke a key |
Create a key
POST /builder-keys
Authorization: Bearer <supabase_session_token>
Content-Type: application/json
{ "name": "My builder" }
The response includes the full key string exactly once — store it securely. It is never returned again.
{
"key": "wlk_4c10b5aba81f868a64949b3a894cbbe1726324be",
"id": "...",
"name": "My builder",
"key_prefix": "wlk_4c10b5ab",
"created_at": "2026-07-10T..."
}
Error responses
| Status | Meaning |
|---|---|
| 401 | Invalid or revoked builder key |
| 403 | Endpoint not available to builder keys, or project belongs to a different account |
| 404 | Project or run not found |
| 400 | Missing required fields (e.g. conversationHistory omitted) |
| 402 | AI credit limit reached for the billing cycle — the key owner must upgrade or top up credits before new runs can start |
| 429 | Rate limit reached — slow down requests |
Limits
- 10 active keys per account — revoke old ones to create new ones.
- Projects and AI credits run on the key owner's account — bill your customers separately if needed.
- Each build run consumes your plan's AI credit allowance.
- Concurrent builds share your plan's limits.
Full working example
A complete single-file AI website builder in plain JavaScript — no dependencies, no build step, no server. Paste your key, host the file anywhere.
<!DOCTYPE html>
<html>
<head>
<title>My AI Builder</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
</head>
<body>
<script>
// ─── CONFIG ──────────────────────────────────────────
var KEY = 'wlk_your_key_here';
var API = 'https://api.aicodesit.com';
var history = []; // conversation history
var projectId = localStorage.getItem('projectId');
// ─── HELPERS ─────────────────────────────────────────
var call = (path, opts) => fetch(API + path, {
...opts,
headers: { Authorization: 'Bearer ' + KEY, ...(opts?.headers || {}) }
});
// ─── STEP 1: ensure we have a project ────────────────
async function ensureProject() {
if (projectId) return;
var sub = 'builder-' + Math.random().toString(36).slice(2, 8);
var res = await call('/projects', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: sub, subdomain: sub }),
}).then(r => r.json());
projectId = res.id;
localStorage.setItem('projectId', projectId);
}
// ─── STEP 2 + 3: send a message and stream ───────────
async function send(msg) {
await ensureProject();
history = [...history.slice(-7), { role: 'user', content: msg }];
// Start run
var { runId } = await call(`/pipeline/${projectId}/run`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ userMessage: msg, conversationHistory: history }),
}).then(r => r.json());
// Stream events
var stream = await call(`/pipeline/${projectId}/run/${runId}/stream`);
var reader = stream.body.getReader();
var decoder = new TextDecoder();
var buf = '', aiText = '';
outer: while (true) {
var { done, value } = await reader.read();
if (done) break;
buf += decoder.decode(value, { stream: true });
var lines = buf.split('\n'); buf = lines.pop() || '';
for (var line of lines) {
if (!line.startsWith('data: ')) continue;
var evt = JSON.parse(line.slice(6));
if (evt.event === 'complete') { reader.cancel(); break outer; }
if (evt.event === 'chunk') aiText += evt.data || '';
}
}
history.push({ role: 'assistant', content: aiText });
// Step 4: wait for preview
while (true) {
var { status, previewUrl } = await call(`/projects/${projectId}/preview`).then(r => r.json());
if (status === 'ready') { document.querySelector('iframe').src = previewUrl; break; }
if (status === 'error') break;
await new Promise(r => setTimeout(r, 2500));
}
}
// ─── MINIMAL UI ──────────────────────────────────────
document.write(`
<style>
body { margin:0; font-family:sans-serif; display:flex; flex-direction:column; height:100vh }
textarea { flex:none; padding:10px; border:1px solid #ddd; border-top:none;
resize:none; font:14px sans-serif; outline:none }
button { padding:8px 18px; background:#000; color:#fff; border:none;
font-size:14px; cursor:pointer }
iframe { flex:1; border:none }
.bar { display:flex; gap:6px; padding:8px; border-bottom:1px solid #eee }
</style>
<div class="bar">
<textarea id="q" rows="2" style="flex:1" placeholder="Describe a website..."></textarea>
<button onclick="send(document.getElementById('q').value)">Build</button>
</div>
<iframe id="p"></iframe>
`);
</script>
</body>
</html>
The quickest way to ship without writing any UI is to download a pre-configured index.html from the dashboard — Dashboard → Builder API → Create key → Download index.html. It includes a full chat panel, live preview, aurora build animation, device-frame switching, and your brand and key already baked in. Host it on GitHub Pages, Netlify, Cloudflare Pages, or just email the file to a partner — no server required.
Related: Edge Functions · Getting Started · How to automate your workflow with Pipeline Builder