← All SDKs

Now Available

Pendra Node.js SDK

TypeScript-first client for sovereign UK inference. Streaming support, zero runtime dependencies. Node.js 18+.

Installation

Terminal
$ npm install pendra

Zero runtime dependencies. View on npm

Quick Start

typescript
import Pendra from 'pendra';

const client = new Pendra({
  apiKey: 'pdr_sk_...', // or set PENDRA_API_KEY env var
});

const response = await client.chat.completions.create({
  model: 'llama3.2',
  messages: [{ role: 'user', content: 'Hello!' }],
});

console.log(response.choices[0].message.content);

Streaming

Stream responses token by token using async iteration.

typescript
const stream = await client.chat.completions.create({
  model: 'llama3.2',
  messages: [{ role: 'user', content: 'Write a poem' }],
  stream: true,
});

for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content ?? '');
}

Image Generation

Generate images from a text prompt. Returns base64-encoded PNGs by default — decode with Buffer.from(b64, 'base64') and write to disk, or set response_format: 'url' when supported by the model.

typescript
import { writeFileSync } from 'node:fs';

const response = await client.images.generations.create({
  model: 'x/z-image-turbo',
  prompt: 'A red London double-decker bus at sunset',
  size: '1024x1024',
});

const b64 = response.data[0].b64_json;
if (b64) {
  writeFileSync('bus.png', Buffer.from(b64, 'base64'));
}

Image generation is non-streaming — the endpoint returns a single JSON response once the worker finishes.

Embeddings

Generate vector embeddings for retrieval, search, and RAG pipelines. OpenAI-compatible — pass a string or array of strings and get back a CreateEmbeddingResponse with one embedding per input.

typescript
const response = await client.embeddings.create({
  model: 'nomic-embed-text:latest',
  input: ['The quick brown fox', 'jumps over the lazy dog'],
});

for (const item of response.data) {
  console.log(item.index, (item.embedding as number[]).length, 'dims');
}

console.log(response.usage.prompt_tokens);

Any embedding model in the Pendra model catalogue works — nomic-embed-text, mxbai-embed-large, bge-m3, qwen3-embedding, all-minilm.

List Models

typescript
const models = await client.models.list();
models.forEach((m) => console.log(m.id));

Migrating from OpenAI

The Pendra SDK mirrors the OpenAI interface. Two lines to switch — your existing code just works.

typescript
// Before
import OpenAI from 'openai';
const client = new OpenAI({ apiKey: 'sk-...' });

// After
import Pendra from 'pendra';
const client = new Pendra({ apiKey: 'pdr_sk_...' });

API Reference

client.chat.completions.create()

Create a chat completion. Returns ChatCompletion or Stream.

ParameterTypeDescription
modelstringModel ID (e.g. "llama3.2")
messagesArrayChat messages with role and content
streamboolean?Enable streaming (default false)
temperaturenumber?Sampling temperature (0–2)
max_tokensnumber?Maximum tokens to generate
top_pnumber?Top-p sampling value
stopstring | string[]?Stop sequence(s)

client.images.generations.create()

Generate images from a text prompt. Returns Promise<ImageResponse>.

ParameterTypeDescription
modelstringImage model ID (e.g. "x/z-image-turbo")
promptstringText description of the image to generate
nnumber?Number of images, 1–4 (default 1)
sizestring?Dimensions as WIDTHxHEIGHT (default "1024x1024")
response_formatstring?"b64_json" (default) or "url"
num_inference_stepsnumber?Diffusion steps (model-dependent)
seednumber?Random seed for reproducibility
negative_promptstring?Text to avoid in the generated image

client.embeddings.create()

Create embeddings. Returns Promise<CreateEmbeddingResponse>.

ParameterTypeDescription
modelstringEmbedding model ID (e.g. "nomic-embed-text:latest")
inputstring | string[]Text to embed. Accepts a single string or a batch.
encoding_format"float" | "base64"?Defaults to float
dimensionsnumber?Output dimensionality (Matryoshka models like nomic-embed-text)
userstring?Optional end-user identifier

client.models.list()

Returns an array of Model objects. Each model has id, object, created, and owned_by fields.

Configuration

OptionEnv varDefault
apiKeyPENDRA_API_KEY
baseURLhttps://api.pendra.ai
timeout120000 (ms)

Error Handling

All exceptions extend APIError.

ExceptionStatusWhen
AuthenticationError401Invalid or missing API key
RateLimitError429Too many requests
APIStatusError4xx/5xxAny other non-2xx response
APIConnectionErrorNetwork or connection failure