Node.js
These samples use the built-in fetch shipped with Node 18+, so they
have no third-party dependencies. Chat completion reads the API key
from the POWER_API_KEY environment variable. Both functions throw on
a non-2xx response — wrap calls in try/catch in real code.
Set the key once in your shell before calling authenticated endpoints:
export POWER_API_KEY="wpe_xxx"List models
Section titled “List models”A lightweight way to discover model identifiers you can pass to the chat endpoint. No authentication is required.
const BASE_URL = "https://api.ai.wpengine.com";
async function listModels() { const res = await fetch(`${BASE_URL}/v1/models`);
if (!res.ok) { throw new Error(`models request failed: ${res.status}`); }
return res.json();}Chat completion
Section titled “Chat completion”A standard non-streaming chat completion. The full response — including generated content and token usage — is returned as a single JSON object once the model finishes.
const BASE_URL = "https://api.ai.wpengine.com";
async function chatCompletion(prompt) { const res = await fetch(`${BASE_URL}/v1/chat/completions`, { method: "POST", headers: { Authorization: `Bearer ${process.env.POWER_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ model: "google/gemini-3.5-flash", messages: [ { role: "system", content: "You are concise." }, { role: "user", content: prompt }, ], }), });
if (!res.ok) { const body = await res.text(); throw new Error(`chat request failed: ${res.status} ${body}`); }
return res.json();}Streaming chat completion
Section titled “Streaming chat completion”Set "stream": true to receive the response as Server-Sent Events
(SSE) instead of a single JSON payload. This is the right shape when
you want to render tokens to the UI as they’re produced.
How the stream is parsed
Section titled “How the stream is parsed”SSE chunks don’t arrive aligned on event boundaries. A single TCP
read may contain several complete data: lines plus a partial line,
or just a fragment of one. The loop below handles that by:
- Decoding each chunk into text with a streaming
TextDecoder, which preserves multi-byte UTF-8 sequences across chunk boundaries. - Buffering decoded text and splitting on
\n. The final element of the split is held back as the next iteration’s prefix in case the chunk ended mid-line. - Processing each complete line: lines starting with
data:carry a JSONchat.completion.chunk. The sentineldata: [DONE]signals that the model has finished and the stream can be closed.
The onDelta callback is invoked once per parsed chunk so the caller
decides what to do with each delta (append to a buffer, write to
stdout, push to a WebSocket, etc.).
const BASE_URL = "https://api.ai.wpengine.com";
async function chatStream(prompt, onDelta) { const res = await fetch(`${BASE_URL}/v1/chat/completions`, { method: "POST", headers: { Authorization: `Bearer ${process.env.POWER_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ model: "google/gemini-3.5-flash", stream: true, messages: [{ role: "user", content: prompt }], }), });
if (!res.ok || !res.body) { throw new Error(`stream request failed: ${res.status}`); }
const reader = res.body.getReader(); const decoder = new TextDecoder(); let buffer = "";
while (true) { const { value, done } = 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 data = line.slice(6).trim(); if (data === "[DONE]") return; onDelta(JSON.parse(data)); } }}Calling it
Section titled “Calling it”Pass a prompt and a callback that handles each delta. This example streams tokens to stdout as they arrive:
await chatStream("Explain how a CDN works in about 100 words.", (chunk) => { process.stdout.write(chunk.choices?.[0]?.delta?.content ?? "");});