@cueno/sdk

Pull a prompt into your app in one call.

The official SDK for the Cueno runtime API. Resolve a prompt by slug, render it with variables, or pin a specific version - from any JavaScript/TypeScript runtime with fetch (Node 18+, edge, Deno, browsers). Fully typed, zero runtime dependencies.

Install

The package is published as @cueno/sdkwith no runtime dependencies - it's a thin, typed wrapper over global fetch.

terminal
npm install @cueno/sdk

Quick start

Construct the client once with your API key and reuse it. The most common path is render- it resolves the version deployed to your key's environment, validates your variables server-side, and returns the interpolated string.

app/route.ts
import { Cueno } from "@cueno/sdk";

const cueno = new Cueno({
  apiKey: process.env.CUENO_API_KEY!, // cueno_live_… or cueno_test_…
  // baseUrl defaults to https://cueno.dev; set http://localhost:3000 for local dev
});

// the key's env picks the live version - the server renders it
const { prompt } = await cueno.prompts.render("welcome-support", {
  company: "Acme",
  customer: "Lee",
});

const reply = await model.run(prompt);
Keep the API key server-side. The key's environment is authoritative, so the secret is enough to read your production prompts - never ship it in a browser bundle or mobile client.

Authentication

Every request authenticates with a Cueno API key, sent automatically as a bearer token. Keys are minted in the web app under Settings → API keys; the full secret is shown once at creation.

  • The key's environment is authoritative. There is no envparameter - a key only ever resolves what's deployed to its environment. To read a different environment, use a key minted for it.
  • Keys are workspace-scoped. A slug in another workspace returns 404, not 403.
Key prefixEnvironment
cueno_live_…production
cueno_test_…staging

API reference

All prompt operations hang off cueno.prompts. Every method returns a typed response (the exported types mirror the server contract) and sets Authorization and Content-Type for you.

cueno.prompts.list()ListPromptsResponse

Every prompt with a version deployed to the key's environment, each carrying its live version label and declared variables. Bodies are omitted.

cueno.prompts.get(slug)ResolvedPrompt

Resolve a slug to its deployed version and return the raw, un-rendered body plus declared variables - render it yourself.

cueno.prompts.render(slug, vars?)RenderResponse

Resolve + interpolate. The server validates vars against the declared variables and returns the rendered prompt string. Throws on invalid input - see Errors.

cueno.prompts.versions(slug)VersionsResponse

The full version history for a prompt, newest first, so you can discover labels to pin to. Bodies omitted.

cueno.prompts.version(slug, label)VersionResponse

Fetch one specific version by label - regardless of what's deployed - including its body. The reproducibility path: pin to v3 and always get the same prompt back.

render accepts a Record<string, string | number | boolean>. Unknown keys are ignored; a declared-but-optional variable left out is rendered verbatim as its {{token}} rather than blanked.

Errors

Any non-2xx response throws a CuenoApiError. Branch on code (stable), not message (human text that may change). For a failed render, the issues getter exposes the per-variable reasons.

error-handling.ts
import { CuenoApiError } from "@cueno/sdk";

try {
  await cueno.prompts.render("welcome-support", { company: 123 });
} catch (e) {
  if (e instanceof CuenoApiError) {
    e.code;    // "validation_failed" - branch on this
    e.status;  // 422
    e.issues;  // [{ variable: "company", message: "Expected a string value." }]
  }
}
codestatusMeaning
unauthorized401Missing, malformed, or unknown API key
not_found404Unknown slug, nothing deployed to the env, or unknown version label
invalid_request400Malformed JSON or a wrong-shaped variables payload
validation_failed422Variable values failed validation - see .issues
method_not_allowed405Wrong HTTP method for the route

Configuration

The constructor takes a single options object: new Cueno(options).

OptionDefaultNotes
apiKey-Required. Your cueno_live_… / cueno_test_… secret.
baseUrlhttps://cueno.devAPI origin, without the /api/v1 suffix. Use http://localhost:3000 for local dev.
fetchglobalThis.fetchInject a custom fetch (Node <18, or for tests).

That's the whole SDK surface. Prefer to skip the client and call the endpoints yourself? See the REST API below - every method maps one-to-one onto /api/v1.

REST API

The SDK is a thin wrapper - every method maps one-to-one onto an HTTP endpoint under /api/v1. If you're not on JavaScript, or just prefer raw fetch/curl, call the API directly. Same bearer auth, same environment semantics, and the same error envelope.

It's JSON in, JSON out. Authenticate with your key on every request; the v1 path segment is the contract version.

auth-header
Authorization: Bearer cueno_live_8Kd2_xxxxxxxxxxxx

Endpoints

GET/prompts
GET/prompts/{slug}
POST/prompts/{slug}/render
GET/prompts/{slug}/versions
GET/prompts/{slug}/versions/{label}

Resolve a prompt

The main read path - resolve a slug to the body deployed in your key's environment:

terminal
curl https://cueno.dev/api/v1/prompts/welcome-support \
  -H "Authorization: Bearer $CUENO_API_KEY"
200 - application/json
{
  "slug": "welcome-support",
  "title": "Welcome Support",
  "description": "Opening line for support chats.",
  "environment": "production",
  "version": { "label": "v3", "author": "kit", "createdAt": "2026-05-28T00:00:00.000Z" },
  "body": "You are {{agent_name}} for {{company}}. Greet {{customer}}.",
  "variables": [
    { "name": "company", "type": "string", "required": true, "note": null }
  ]
}

Render with variables

POST the values and let the server validate and interpolate. An empty body (or no variables) is treated as {}; unknown keys are ignored, and an optional token left unprovided stays verbatim.

terminal
curl https://cueno.dev/api/v1/prompts/welcome-support/render \
  -H "Authorization: Bearer $CUENO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "variables": { "company": "Acme", "customer": "Lee", "agent_name": "Ada" } }'
200 - application/json
{
  "slug": "welcome-support",
  "environment": "production",
  "version": "v3",
  "prompt": "You are Ada for Acme. Greet Lee."
}
Same key, same rules: the environment comes from the key, not the request, so there's no ?env= override. Errors use the shared envelope { "error": { "code", "message", "details"? } } - branch on error.code.