> ## Documentation Index
> Fetch the complete documentation index at: https://docs.circuit.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Reference client

> A TypeScript client for the partner API with no dependencies, and a small server example that uses it.

Download [`circuit.ts`](https://circuit.org/partners/circuit.ts) into your app. It runs in browsers, Node 22+ and Bun, and uses only `fetch` and WebCrypto (X25519, AES-GCM and SHA-256). [Pinewood](https://circuit.org/partners/demo), Circuit's demo partner app, uses the same file; you can link your account there to try the full integration.

```typescript theme={"theme":{"light":"nord","dark":"nord"}}
import { circuit, link } from "./circuit";

const { url, permit } = await link("<your app id>");
// Open `url` in a real browser for the user to approve, then store the permit like an access token.
const user = circuit(await permit);
const trend = (await user.agents()).find((agent) => agent.name === "Macro Trend")!;
const session = await user.start({ agent: trend.id, wallet: null, amount: "1000" }); // runs now
```

### A server-side demo

Pinewood keeps the permit in the browser. `server.ts` below keeps it on the server instead and serves a page for one user, with a link button, balances, a chat with Approve and Decline on Ask's proposals, and Stop on running agents. Run it with `bun server.ts <your app id>` and open `http://localhost:4455`.

```typescript server.ts theme={"theme":{"light":"nord","dark":"nord"}}
import { circuit, link } from "./circuit";

const app = process.argv[2];
const api = "https://api.circuit.org";
let permit: string | undefined;
let chat: string | null = null;
const json = (body: unknown, status = 200) => Response.json(body, { status });

const page = `<!doctype html><meta charset="utf-8"><title>Partner demo</title>
<style>body{font:15px system-ui;max-width:640px;margin:40px auto}button{margin:2px}li{margin:6px 0}</style>
<button id="connect">Link Circuit</button><pre id="account"></pre>
<form id="ask"><input id="text" size="60" placeholder="Long $10 of BTC, start an agent on paper…"><button>Send</button></form>
<ul id="turns"></ul>
<script>
const post = (path, body) => fetch(path, { method: "POST", body: JSON.stringify(body ?? {}) }).then((r) => r.json());
const button = (label, run) => Object.assign(document.createElement("button"), { textContent: label, onclick: run });
async function refresh() {
  const account = await fetch("/account").then((r) => r.json());
  document.getElementById("account").textContent = account.error ?? account.wallets.map((w) => w.name + " $" + (w.value_usd ?? "?")).join("\\n") +
    "\\n" + account.sessions.map((s) => s.name + ": " + s.status).join("\\n");
  for (const session of account.sessions ?? []) if (session.status !== "stopped") document.getElementById("account").append(button("Stop " + session.name, () => post("/stop", { id: session.id }).then(refresh)));
}
function show(message) {
  const item = document.createElement("li");
  item.textContent = (message.text ?? "") + " → " + (message.reply ?? message.status);
  for (const proposal of message.proposals) {
    const row = document.createElement("div");
    row.textContent = proposal.title + " (" + proposal.status + ") ";
    if (proposal.status === "review") row.append(button("Decline", () => post("/decide", { id: proposal.id, decision: "decline" })), button("Approve", () => post("/decide", { id: proposal.id, decision: "approve" }).then(refresh)));
    item.append(row);
  }
  document.getElementById("turns").append(item);
}
document.getElementById("connect").onclick = async () => { window.open((await post("/connect")).url); };
document.getElementById("ask").onsubmit = async (event) => { event.preventDefault(); show(await post("/ask", { text: document.getElementById("text").value })); refresh(); };
refresh();
</script>`;

Bun.serve({
  port: 4455,
  async fetch(request) {
    const path = new URL(request.url).pathname;
    if (path === "/") return new Response(page, { headers: { "content-type": "text/html" } });
    if (path === "/connect") {
      const started = await link(app, api);
      started.permit.then((approved) => (permit = approved));
      return json({ url: started.url });
    }
    if (!permit) return json({ error: "Connect first" }, 401);
    const user = circuit(permit, api);
    const body = request.method === "POST" ? await request.json() : {};
    try {
      if (path === "/account") return json(await user.account());
      if (path === "/ask") {
        const sent = await user.send(chat, body.text);
        chat = sent.chat;
        return json(await user.reply(sent));
      }
      if (path === "/decide") {
        return json(await user.decide(body.id, body.decision));
      }
      if (path === "/stop") return json(await user.stop(body.id));
    } catch (error) {
      return json({ error: error instanceof Error ? error.message : String(error) }, 502);
    }
    return json({ error: "Not found" }, 404);
  },
});
console.log("Partner demo on http://localhost:4455");
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.