Design DNA — API

Paste frontend source code, get the project's design system extracted.

API tokens Open the app

Extract design systems from your own code

Everything this app does goes through the SkillSafe App API — plain JSON over HTTPS, so you can wire the extraction into a pull-request check, a design-system dashboard or a docs build step that keeps DESIGN.md in sync with the code. Every code step below is shown in cURL, Python, JavaScript, Go, Java, Ruby, PHP and C#; pick a language once and the whole page follows.

Basics

Base URL: https://api.skillsafe.ai/v1/app-api. Every request sends Authorization: Bearer <token> and JSON bodies with Content-Type: application/json. Responses are wrapped in an envelope: {"data": …} on success, {"error": {"code", "message"}} on failure. The extraction itself is produced by the gpt-terra model. Estimates are free; runs are metered against your credit balance. There is a single run task — no follow-up calls, no session state to carry.

StatusMeaning
401Missing or expired token — create a new session.
402Not enough credits — top up at skillsafe.ai/account/credits.
403The token isn't allowed to do this (e.g. a guest extracting from a very large paste).
404Unknown job or record id.
5xxTransient platform error — retry with backoff.

Browsers enforce CORS for this API, so run these examples from a server, script or terminal — not from another website's frontend.

Step 0 — A tiny client

Every task below is a single HTTP call, so start with a short helper that adds the auth header, sends JSON and unwraps the data envelope. The later steps reuse it.

export API="https://api.skillsafe.ai/v1/app-api"
export TOKEN="YOUR_TOKEN"      # see step 1

# every call looks like:
#   curl -s "$API/…" -H "Authorization: Bearer $TOKEN" [-d '{json}']
# jq is used below to pull fields out of the {"data": …} envelope
import json, requests

API = "https://api.skillsafe.ai/v1/app-api"
TOKEN = "YOUR_TOKEN"  # see step 1

def api(method, path, body=None, **headers):
    res = requests.request(method, API + path, json=body,
                           headers={"Authorization": f"Bearer {TOKEN}", **headers})
    payload = res.json()
    if not res.ok:
        raise RuntimeError(payload.get("error", {}).get("message", res.reason))
    return payload["data"]
// Node 18+ (built-in fetch)
const API = "https://api.skillsafe.ai/v1/app-api";
const TOKEN = "YOUR_TOKEN"; // see step 1 — read it from your environment in real code

async function api(method, path, body, extraHeaders = {}) {
  const res = await fetch(API + path, {
    method,
    headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json", ...extraHeaders },
    body: body === undefined ? undefined : JSON.stringify(body),
  });
  const json = await res.json();
  if (!res.ok) throw new Error(json.error?.message ?? res.statusText);
  return json.data;
}
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
)

const API = "https://api.skillsafe.ai/v1/app-api"

var token = os.Getenv("SKILLSAFE_TOKEN") // see step 1

func call(method, path string, body, out any) error {
	var buf bytes.Buffer
	if body != nil {
		json.NewEncoder(&buf).Encode(body)
	}
	req, _ := http.NewRequest(method, API+path, &buf)
	req.Header.Set("Authorization", "Bearer "+token)
	req.Header.Set("Content-Type", "application/json")
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	var env struct {
		Data  json.RawMessage `json:"data"`
		Error *struct{ Message string `json:"message"` } `json:"error"`
	}
	json.NewDecoder(res.Body).Decode(&env)
	if res.StatusCode >= 400 {
		return fmt.Errorf("api %s %s: %s", method, path, env.Error.Message)
	}
	if out == nil {
		return nil
	}
	return json.Unmarshal(env.Data, out)
}
// Java 17+, no dependencies. Pair with your JSON library (Jackson, Gson…)
// to read fields out of the returned envelope.
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class SkillSafe {
    static final String API = "https://api.skillsafe.ai/v1/app-api";
    static final String TOKEN = System.getenv("SKILLSAFE_TOKEN"); // see step 1
    static final HttpClient HTTP = HttpClient.newHttpClient();

    static String api(String method, String path, String jsonBody) throws Exception {
        var req = HttpRequest.newBuilder(URI.create(API + path))
            .header("Authorization", "Bearer " + TOKEN)
            .header("Content-Type", "application/json")
            .method(method, jsonBody == null
                ? HttpRequest.BodyPublishers.noBody()
                : HttpRequest.BodyPublishers.ofString(jsonBody))
            .build();
        var res = HTTP.send(req, HttpResponse.BodyHandlers.ofString());
        if (res.statusCode() >= 400) throw new RuntimeException(res.body());
        return res.body(); // envelope: {"data": …}
    }
}
require "net/http"
require "json"

API = "https://api.skillsafe.ai/v1/app-api"
TOKEN = ENV.fetch("SKILLSAFE_TOKEN") # see step 1

def api(method, path, body = nil)
  uri = URI(API + path)
  req = Net::HTTP.const_get(method.capitalize).new(uri)
  req["Authorization"] = "Bearer #{TOKEN}"
  req["Content-Type"] = "application/json"
  req.body = body.to_json if body
  res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }
  payload = JSON.parse(res.body)
  raise (payload.dig("error", "message") || res.message) unless res.is_a?(Net::HTTPSuccess)
  payload["data"]
end
<?php
const API = "https://api.skillsafe.ai/v1/app-api";
$TOKEN = getenv("SKILLSAFE_TOKEN"); // see step 1

function api(string $method, string $path, ?array $body = null): mixed {
    global $TOKEN;
    $ch = curl_init(API . $path);
    curl_setopt_array($ch, [
        CURLOPT_CUSTOMREQUEST  => $method,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER     => [
            "Authorization: Bearer $TOKEN",
            "Content-Type: application/json",
        ],
        CURLOPT_POSTFIELDS     => $body === null ? null : json_encode($body),
    ]);
    $payload = json_decode(curl_exec($ch), true);
    $status  = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    curl_close($ch);
    if ($status >= 400) {
        throw new Exception($payload["error"]["message"] ?? "HTTP $status");
    }
    return $payload["data"];
}
// .NET 8+
using System.Net.Http.Json;
using System.Text.Json;

static class SkillSafe
{
    const string Api = "https://api.skillsafe.ai/v1/app-api";
    static readonly HttpClient Http = new();

    static SkillSafe() =>
        Http.DefaultRequestHeaders.Authorization =
            new("Bearer", Environment.GetEnvironmentVariable("SKILLSAFE_TOKEN")); // see step 1

    public static async Task<JsonElement> ApiAsync(HttpMethod method, string path, object? body = null)
    {
        var req = new HttpRequestMessage(method, Api + path);
        if (body != null) req.Content = JsonContent.Create(body);
        var res = await Http.SendAsync(req);
        var json = await res.Content.ReadFromJsonAsync<JsonElement>();
        if (!res.IsSuccessStatusCode)
            throw new Exception(json.GetProperty("error").GetProperty("message").GetString());
        return json.GetProperty("data");
    }
}

Step 1 — Get a token

POST /guest

A guest token lets you check balances and estimate costs for free. For metered extractions billed to your own account, use your personal token: open the token page, sign in with SkillSafe, and press Copy shell export — it puts export SKILLSAFE_TOKEN="…" on your clipboard, which every example below reads. Treat the token like a password: it can spend your credits. For fully headless scripts, POST /guest mints a guest token with no browser involved.

curl -s -X POST "$API/guest" \
  -H "Content-Type: application/json" \
  -d '{"slug":"design-dna"}' | jq -r '.data.token'
token = api("POST", "/guest", {"slug": "design-dna"})["token"]
const { token } = await api("POST", "/guest", { slug: "design-dna" });
var guest struct{ Token string `json:"token"` }
err := call("POST", "/guest", map[string]string{"slug": "design-dna"}, &guest)
String envelope = api("POST", "/guest", """
    {"slug":"design-dna"}""");
// token is at data.token in the returned JSON
token = api("POST", "/guest", { slug: "design-dna" })["token"]
$token = api("POST", "/guest", ["slug" => "design-dna"])["token"];
var guest = await SkillSafe.ApiAsync(HttpMethod.Post, "/guest",
    new { slug = "design-dna" });
var token = guest.GetProperty("token").GetString();

The app stores this browser's token under the localStorage key skillsafe_app_token:design-dna, on the app's own origin. The token page reads and manages it for you — you never need to open developer tools.

Step 2 — Check who you are and your balance

GET /me

Returns subject_type ("user" or "guest"), subject_id and your credits balance. Check this before extracting from a large paste.

curl -s "$API/me" -H "Authorization: Bearer $TOKEN" | jq '.data'
me = api("GET", "/me")
print(me["subject_type"], me["credits"])
const me = await api("GET", "/me");
console.log(me.subject_type, me.credits);
var me struct {
	SubjectType string `json:"subject_type"`
	Credits     int64  `json:"credits"`
}
err := call("GET", "/me", nil, &me)
String envelope = api("GET", "/me", null);
// data.subject_type, data.credits
me = api("GET", "/me")
puts "#{me["subject_type"]}: #{me["credits"]} credits"
$me = api("GET", "/me");
echo "{$me['subject_type']}: {$me['credits']} credits\n";
var me = await SkillSafe.ApiAsync(HttpMethod.Get, "/me");
Console.WriteLine($"{me.GetProperty("subject_type")}: {me.GetProperty("credits")} credits");

Step 3 — Estimate the cost

POST /estimate

Send exactly the input you would send to /run; the response's hold_credits is the worst-case cost. Nothing is charged and no job is created, so estimating is free — useful when the pasted codebase is large and you want a ceiling before spending credits.

Input fieldTypeNotes
source_codestring, requiredThe frontend source: HTML, JSX/TSX, Vue SFC or Svelte. Several files may be concatenated with /* filename */ headers, and an inline <style> block is welcome.
css_textstring, optionalStylesheets, a theme/token file or a Tailwind config, when the styles do not live beside the markup.
stackstringauto | html | react | vue | svelte | tailwind. auto lets the model detect it from the code.
focusstring, optionalWhat the extraction should concentrate on, e.g. "the color palette and spacing scale".
lint_findingsarray, optionalSignals the page's client-side token scan already found, which the model must confirm or dismiss: {"id": "color-sprawl", "line": 12, "excerpt": "…"}. Each one comes back in token_check. API callers with no prescan of their own send [].
retry_notestring, optionalOnly set by the app's automatic reformat retry when a first reply was not valid JSON. Leave it out.
cat > Card.jsx <<'JSX'
export function Card({ title }) {
  return <div className="card"><h3>{title}</h3></div>;
}
JSX

cat > theme.css <<'CSS'
.card { background: #ffffff; border: 1px solid #e5e7eb; border-radius: 12px; padding: 16px; }
.btn  { background: #2563EB; border-radius: 10px; padding: 9px 14px; }
CSS

jq -n --rawfile src Card.jsx --rawfile css theme.css \
  '{source_code: $src, css_text: $css, stack: "react",
    focus: "the color palette and spacing scale", lint_findings: []}' > input.json

curl -s -X POST "$API/estimate" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d @input.json | jq '.data.hold_credits'
SOURCE = """export function Card({ title }) {
  return <div className="card"><h3>{title}</h3></div>;
}"""

CSS = """.card { background: #ffffff; border: 1px solid #e5e7eb; border-radius: 12px; padding: 16px; }
.btn  { background: #2563EB; border-radius: 10px; padding: 9px 14px; }"""

payload = {
    "source_code": SOURCE,
    "css_text": CSS,
    "stack": "react",
    "focus": "the color palette and spacing scale",
    "lint_findings": [],
}

est = api("POST", "/estimate", payload)
print("worst case:", est.get("hold_credits", est.get("credits")), "credits")
const source = `export function Card({ title }) {
  return <div className="card"><h3>{title}</h3></div>;
}`;

const css = `.card { background: #ffffff; border: 1px solid #e5e7eb; border-radius: 12px; padding: 16px; }
.btn  { background: #2563EB; border-radius: 10px; padding: 9px 14px; }`;

const payload = {
  source_code: source,
  css_text: css,
  stack: "react",
  focus: "the color palette and spacing scale",
  lint_findings: [],
};

const est = await api("POST", "/estimate", payload);
console.log("worst case:", est.hold_credits ?? est.credits, "credits");
const source = `export function Card({ title }) {
  return <div className="card"><h3>{title}</h3></div>;
}`

const css = `.card { background: #ffffff; border: 1px solid #e5e7eb; border-radius: 12px; padding: 16px; }
.btn  { background: #2563EB; border-radius: 10px; padding: 9px 14px; }`

payload := map[string]any{
	"source_code":   source,
	"css_text":      css,
	"stack":         "react",
	"focus":         "the color palette and spacing scale",
	"lint_findings": []any{},
}

var est struct{ HoldCredits int64 `json:"hold_credits"` }
err := call("POST", "/estimate", payload, &est)
String source = """
    export function Card({ title }) {
      return <div className="card"><h3>{title}</h3></div>;
    }""";

String css = """
    .card { background: #ffffff; border: 1px solid #e5e7eb; border-radius: 12px; padding: 16px; }
    .btn  { background: #2563EB; border-radius: 10px; padding: 9px 14px; }""";

String jsonPayload = """
    {"source_code": %s, "css_text": %s, "stack": "react",
     "focus": "the color palette and spacing scale", "lint_findings": []}
    """.formatted(toJsonString(source), toJsonString(css));

String envelope = api("POST", "/estimate", jsonPayload);
// worst-case cost is at data.hold_credits
SOURCE = <<~JSX
  export function Card({ title }) {
    return <div className="card"><h3>{title}</h3></div>;
  }
JSX

CSS = <<~STYLES
  .card { background: #ffffff; border: 1px solid #e5e7eb; border-radius: 12px; padding: 16px; }
  .btn  { background: #2563EB; border-radius: 10px; padding: 9px 14px; }
STYLES

payload = { source_code: SOURCE, css_text: CSS, stack: "react",
            focus: "the color palette and spacing scale", lint_findings: [] }

est = api("POST", "/estimate", payload)
puts "worst case: #{est["hold_credits"] || est["credits"]} credits"
$source = <<<'JSX'
export function Card({ title }) {
  return <div className="card"><h3>{title}</h3></div>;
}
JSX;

$css = <<<'CSS'
.card { background: #ffffff; border: 1px solid #e5e7eb; border-radius: 12px; padding: 16px; }
.btn  { background: #2563EB; border-radius: 10px; padding: 9px 14px; }
CSS;

$payload = [
    "source_code"   => $source,
    "css_text"      => $css,
    "stack"         => "react",
    "focus"         => "the color palette and spacing scale",
    "lint_findings" => [],
];

$est = api("POST", "/estimate", $payload);
echo "worst case: " . ($est["hold_credits"] ?? $est["credits"]) . " credits\n";
var source = """
    export function Card({ title }) {
      return <div className="card"><h3>{title}</h3></div>;
    }
    """;

var css = """
    .card { background: #ffffff; border: 1px solid #e5e7eb; border-radius: 12px; padding: 16px; }
    .btn  { background: #2563EB; border-radius: 10px; padding: 9px 14px; }
    """;

var payload = new {
    source_code = source,
    css_text = css,
    stack = "react",
    focus = "the color palette and spacing scale",
    lint_findings = Array.Empty<object>(),
};

var est = await SkillSafe.ApiAsync(HttpMethod.Post, "/estimate", payload);
Console.WriteLine($"worst case: {est.GetProperty("hold_credits")} credits");

Step 4 — Run the extraction and wait for the result

POST /run
GET /jobs/{job_id}

/run takes the same input as /estimate, places a credit hold and returns a job_id. Poll /jobs/{job_id} every 1–2 seconds until status is succeeded or failed (a run typically takes 20–60 s). Always send an Idempotency-Key header so a network retry can't start a second, double-charged run. The extracted design system is in output — usually nested as output.output, and as a JSON string, so parse defensively.

JOB_ID=$(curl -s -X POST "$API/run" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -H "Idempotency-Key: extract-$(date +%s)" \
  -d @input.json | jq -r '.data.job_id')

while :; do
  JOB=$(curl -s "$API/jobs/$JOB_ID" -H "Authorization: Bearer $TOKEN")
  STATUS=$(echo "$JOB" | jq -r '.data.status')
  [ "$STATUS" = "succeeded" ] || [ "$STATUS" = "failed" ] && break
  sleep 2
done

# unwrap the design system and add up the six scores
echo "$JOB" | jq -r '.data.output.output' | jq '{system_name, verdict, total: ([.scores[].score] | add)}'

# and write the document straight to the repo
echo "$JOB" | jq -r '.data.output.output' | jq -r '.design_md' > DESIGN.md
import time

job_id = api("POST", "/run", payload,
             **{"Idempotency-Key": "extract-001"})["job_id"]

while True:
    job = api("GET", f"/jobs/{job_id}")
    if job["status"] in ("succeeded", "failed"):
        break
    time.sleep(1.5)

if job["status"] == "failed":
    raise RuntimeError(job.get("error", "run failed"))

raw = job["output"]
if isinstance(raw, dict) and "output" in raw:
    raw = raw["output"]
design = json.loads(raw) if isinstance(raw, str) else raw

total = sum(s["score"] for s in design["scores"])
print(f'{design["system_name"]} ({design["stack"]}): {total}/60 — {design["verdict"]}')
for issue in design["issues"]:
    print(f'  [{issue["severity"]}] {issue["category"]} — {issue["title"]}')

open("DESIGN.md", "w", encoding="utf-8").write(design["design_md"])
import { writeFileSync } from "node:fs";

const { job_id } = await api("POST", "/run", payload,
  { "Idempotency-Key": crypto.randomUUID() });

let job;
do {
  await new Promise((r) => setTimeout(r, 1500));
  job = await api("GET", `/jobs/${job_id}`);
} while (job.status !== "succeeded" && job.status !== "failed");

if (job.status === "failed") throw new Error(job.error ?? "run failed");

const raw = job.output?.output ?? job.output;
const design = typeof raw === "string" ? JSON.parse(raw) : raw;

const total = design.scores.reduce((n, s) => n + s.score, 0);
console.log(`${design.system_name} (${design.stack}): ${total}/60 — ${design.verdict}`);
for (const issue of design.issues) {
  console.log(`  [${issue.severity}] ${issue.category} — ${issue.title}`);
}

writeFileSync("DESIGN.md", design.design_md);
var started struct{ JobID string `json:"job_id"` }
if err := call("POST", "/run", payload, &started); err != nil {
	log.Fatal(err)
}

var job struct {
	Status string          `json:"status"`
	Error  string          `json:"error"`
	Output json.RawMessage `json:"output"`
}
for {
	if err := call("GET", "/jobs/"+started.JobID, nil, &job); err != nil {
		log.Fatal(err)
	}
	if job.Status == "succeeded" || job.Status == "failed" {
		break
	}
	time.Sleep(1500 * time.Millisecond)
}
// job.Output is {"output": "<json string>"} — unwrap, unquote, then unmarshal
// into your own struct (SystemName, Stack, Scores, Issues, DesignMD…).
String envelope = api("POST", "/run", jsonPayload);
String jobId = /* data.job_id via your JSON library */;

while (true) {
    String job = api("GET", "/jobs/" + jobId, null);
    String status = /* data.status */;
    if (status.equals("succeeded") || status.equals("failed")) break;
    Thread.sleep(1500);
}
// the design system is at data.output.output as a JSON string — parse it again,
// then read system_name, stack, scores[], issues[], priority_fixes[], design_md…
started = api("POST", "/run", payload)

job = nil
loop do
  job = api("GET", "/jobs/#{started["job_id"]}")
  break if %w[succeeded failed].include?(job["status"])
  sleep 1.5
end
raise (job["error"] || "run failed") if job["status"] == "failed"

raw = job["output"].is_a?(Hash) ? job["output"].fetch("output", job["output"]) : job["output"]
design = raw.is_a?(String) ? JSON.parse(raw) : raw

total = design["scores"].sum { |s| s["score"] }
puts "#{design["system_name"]} (#{design["stack"]}): #{total}/60 — #{design["verdict"]}"
File.write("DESIGN.md", design["design_md"])
$started = api("POST", "/run", $payload);

do {
    sleep(2);
    $job = api("GET", "/jobs/" . $started["job_id"]);
} while (!in_array($job["status"], ["succeeded", "failed"]));

if ($job["status"] === "failed") {
    throw new Exception($job["error"] ?? "run failed");
}

$raw = is_array($job["output"]) ? ($job["output"]["output"] ?? $job["output"]) : $job["output"];
$design = is_string($raw) ? json_decode($raw, true) : $raw;

$total = array_sum(array_column($design["scores"], "score"));
echo "{$design['system_name']} ({$design['stack']}): {$total}/60 — {$design['verdict']}\n";
file_put_contents("DESIGN.md", $design["design_md"]);
var started = await SkillSafe.ApiAsync(HttpMethod.Post, "/run", payload);
var jobId = started.GetProperty("job_id").GetString();

JsonElement job;
while (true)
{
    job = await SkillSafe.ApiAsync(HttpMethod.Get, $"/jobs/{jobId}");
    var status = job.GetProperty("status").GetString();
    if (status is "succeeded" or "failed") break;
    await Task.Delay(1500);
}

var rawText = job.GetProperty("output").GetProperty("output").GetString();
using var design = JsonDocument.Parse(rawText!);
var total = design.RootElement.GetProperty("scores").EnumerateArray()
    .Sum(s => s.GetProperty("score").GetInt32());
Console.WriteLine($"{total}/60 — {design.RootElement.GetProperty("verdict")}");
await File.WriteAllTextAsync("DESIGN.md",
    design.RootElement.GetProperty("design_md").GetString());

The parsed design-system object has this shape:

FieldTypeNotes
system_namestringA short name for the design system, taken from the code's own naming or its dominant component.
stackstringThe stack the model detected, e.g. "React + Tailwind".
verdictstringOne sentence: how codified the system is and the single biggest gap.
scoresarray of 6{id, score, note}, score 0–10. Always all six ids below. The app renders the sum as a total out of 60.
issuesarray{title, category, severity, location, excerpt, problem, fix}; severity is high | medium | low, excerpt quotes the offending code verbatim.
priority_fixesstring[]3–6 ordered strings — the changes that most consolidate the system.
rewriteobject or null{location, before, after, note} — scattered values before, the consolidated token block after.
token_checkarray{id, agree, note} — one entry per lint_findings item you sent, confirming or dismissing it.
design_mdstringA complete DESIGN.md markdown document: palette table, typography, spacing, shape & depth, components, layout principles and known inconsistencies.
summarystring2–4 sentences.

The six score dimensions, in order:

idlabel
colorColor
typographyTypography
spacingSpacing & layout
shapeShape & depth
componentsComponents
consistencyConsistency

Each issue's category is one of Color, Typography, Spacing & layout, Shape & depth, Components or Consistency — the same six dimensions, spelled exactly like this. The model is asked for one JSON object and nothing else, but a stray code fence or preamble is always possible. Strip a leading ```json fence, take the text between the first { and the last }, and only then parse — that is what the app does before it falls back to a retry_note reformat run.

Step 5 — Stream the extraction as it is written

POST /run-stream

/run-stream takes exactly the same body as /run but answers with server-sent events, so you can show progress instead of a spinner — this app's own progress panel is this endpoint. Events are separated by a blank line; each has an event: line and a data: line carrying JSON.

EventPayloadMeaning
job{job_id, status}Sent once, when the job is accepted — show "starting".
delta{text}A chunk of the reply, in order. Append it; the accumulated length is your only progress signal (the total is not known in advance).
done{job_id, status, charged_credits, output}The final, authoritative result — read the design system from output.output rather than trusting concatenated deltas, and the settled price from charged_credits.
error{code, message}Replaces done when the run fails.
# -N disables buffering so events print as they arrive
curl -N -s -X POST "$API/run-stream" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -H "Idempotency-Key: extract-$(date +%s)" \
  -d @input.json

# event: job
# data: {"job_id":"job_…","status":"running"}
#
# event: delta
# data: {"text":"{\"system_name\":\"Card"}
# …
# event: done
# data: {"job_id":"job_…","status":"succeeded","charged_credits":412,"output":{"output":"{…}"}}
import json, requests

result = None
with requests.post(
    API + "/run-stream",
    headers={"Authorization": f"Bearer {TOKEN}",
             "Idempotency-Key": "extract-001"},
    json=payload,
    stream=True,
) as r:
    r.raise_for_status()
    event = None
    for line in r.iter_lines(decode_unicode=True):
        if not line:
            continue
        if line.startswith("event:"):
            event = line[len("event:"):].strip()
        elif line.startswith("data:"):
            data = json.loads(line[len("data:"):].strip())
            if event == "delta":
                print(".", end="", flush=True)          # live progress
            elif event == "done":
                result = data
            elif event == "error":
                raise RuntimeError(data.get("message", "run failed"))

design = json.loads(result["output"]["output"])         # authoritative
print("charged:", result["charged_credits"], "—", design["verdict"])
const res = await fetch(API + "/run-stream", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${TOKEN}`,
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: JSON.stringify(payload),
});

const reader = res.body.getReader();
const decoder = new TextDecoder();
let buf = "", done = null;

for (;;) {
  const chunk = await reader.read();
  if (chunk.done) break;
  buf += decoder.decode(chunk.value, { stream: true });
  const frames = buf.split("\n\n");
  buf = frames.pop();
  for (const frame of frames) {
    const name = /^event:\s*(.+)$/m.exec(frame)?.[1];
    const body = /^data:\s*(.+)$/m.exec(frame)?.[1];
    if (!name || !body) continue;
    const data = JSON.parse(body);
    if (name === "delta") process.stdout.write(".");   // live progress
    if (name === "done") done = data;
    if (name === "error") throw new Error(data.message ?? "run failed");
  }
}

const design = JSON.parse(done.output.output);
console.log(`\n${done.charged_credits} credits — ${design.verdict}`);
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", API+"/run-stream", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", "extract-001")

res, err := http.DefaultClient.Do(req)
if err != nil {
	log.Fatal(err)
}
defer res.Body.Close()

var event string
var final map[string]any
sc := bufio.NewScanner(res.Body)
sc.Buffer(make([]byte, 0, 64*1024), 4*1024*1024)
for sc.Scan() {
	line := sc.Text()
	switch {
	case strings.HasPrefix(line, "event:"):
		event = strings.TrimSpace(strings.TrimPrefix(line, "event:"))
	case strings.HasPrefix(line, "data:"):
		var data map[string]any
		json.Unmarshal([]byte(strings.TrimPrefix(line, "data:")), &data)
		switch event {
		case "delta":
			fmt.Print(".") // live progress
		case "done":
			final = data
		case "error":
			log.Fatal(data["message"])
		}
	}
}
// final["output"].(map[string]any)["output"].(string) is the design-system JSON
// Java 17+ — read the stream line by line instead of buffering the body.
var req = HttpRequest.newBuilder(URI.create(API + "/run-stream"))
    .header("Authorization", "Bearer " + TOKEN)
    .header("Content-Type", "application/json")
    .header("Idempotency-Key", "extract-001")
    .POST(HttpRequest.BodyPublishers.ofString(jsonPayload))
    .build();

var res = HTTP.send(req, HttpResponse.BodyHandlers.ofLines());
String event = null, done = null;
for (String line : (Iterable<String>) res.body()::iterator) {
    if (line.startsWith("event:")) {
        event = line.substring(6).trim();
    } else if (line.startsWith("data:")) {
        String data = line.substring(5).trim();
        if ("delta".equals(event)) System.out.print(".");   // live progress
        else if ("done".equals(event)) done = data;
        else if ("error".equals(event)) throw new RuntimeException(data);
    }
}
// parse `done`, then parse data.output.output again — it is a JSON string
require "net/http"
require "json"

uri = URI(API + "/run-stream")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{TOKEN}"
req["Content-Type"] = "application/json"
req["Idempotency-Key"] = "extract-001"
req.body = payload.to_json

event = nil
done = nil
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request(req) do |res|
    res.read_body do |chunk|
      chunk.each_line do |line|
        line = line.strip
        if line.start_with?("event:")
          event = line.delete_prefix("event:").strip
        elsif line.start_with?("data:")
          data = JSON.parse(line.delete_prefix("data:").strip)
          case event
          when "delta" then print "."           # live progress
          when "done"  then done = data
          when "error" then raise (data["message"] || "run failed")
          end
        end
      end
    end
  end
end

design = JSON.parse(done["output"]["output"])
puts "\n#{done["charged_credits"]} credits — #{design["verdict"]}"
$event = null;
$done  = null;

$ch = curl_init(API . "/run-stream");
curl_setopt_array($ch, [
    CURLOPT_POST       => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer $TOKEN",
        "Content-Type: application/json",
        "Idempotency-Key: extract-001",
    ],
    CURLOPT_POSTFIELDS => json_encode($payload),
    CURLOPT_WRITEFUNCTION => function ($ch, $chunk) use (&$event, &$done) {
        foreach (explode("\n", $chunk) as $line) {
            $line = trim($line);
            if (str_starts_with($line, "event:")) {
                $event = trim(substr($line, 6));
            } elseif (str_starts_with($line, "data:")) {
                $data = json_decode(trim(substr($line, 5)), true);
                if ($event === "delta") { echo "."; }        // live progress
                elseif ($event === "done") { $done = $data; }
                elseif ($event === "error") { throw new Exception($data["message"] ?? "run failed"); }
            }
        }
        return strlen($chunk);
    },
]);
curl_exec($ch);
curl_close($ch);

$design = json_decode($done["output"]["output"], true);
echo "\n{$done['charged_credits']} credits — {$design['verdict']}\n";
var req = new HttpRequestMessage(HttpMethod.Post, Api + "/run-stream") {
    Content = JsonContent.Create(payload),
};
req.Headers.Add("Idempotency-Key", "extract-001");

using var res = await Http.SendAsync(req, HttpCompletionOption.ResponseHeadersRead);
using var reader = new StreamReader(await res.Content.ReadAsStreamAsync());

string? evt = null, done = null;
while (await reader.ReadLineAsync() is { } line)
{
    if (line.StartsWith("event:")) evt = line[6..].Trim();
    else if (line.StartsWith("data:"))
    {
        var data = line[5..].Trim();
        if (evt == "delta") Console.Write(".");            // live progress
        else if (evt == "done") done = data;
        else if (evt == "error") throw new Exception(data);
    }
}

using var final = JsonDocument.Parse(done!);
var text = final.RootElement.GetProperty("output").GetProperty("output").GetString();
using var design = JsonDocument.Parse(text!);
Console.WriteLine(design.RootElement.GetProperty("verdict"));

In a browser, the native EventSource only speaks GET, and this endpoint is a POST — read the fetch response body incrementally, as the JavaScript sample above does. On an idempotent replay the server may answer with a plain JSON envelope instead of an event stream; check the Content-Type before you start parsing frames.