API Reference

Models & catalogue

Pendra exposes two model surfaces: a live models endpoint that lists what's actually serving right now across connected workers, and a catalogue endpoint that lists everything Pendra can install for you via the curated-install flow. Model weights are hosted on Pendra's own CDN (get.pendra.ai) and checksum-verified at install time.

Live models

GET /api/v1/models returns the OpenAI-shaped models list:

curl https://api.pendra.ai/api/v1/models \
  -H "Authorization: Bearer pdr_sk_..."

Response

Standard OpenAI list envelope. Each entry is what's actually serving on a connected worker right now — restart a worker and the list updates within seconds.

{
  "object": "list",
  "data": [
    {
      "id": "llama3.3:70b",
      "object": "model",
      "created": 1733519426,
      "owned_by": "pendra",
      "type": "chat",
      "capabilities": ["completion", "tools"],
      "parameter_size": "70B"
    },
    {
      "id": "qwen3.6:27b",
      "object": "model",
      "created": 1776313891,
      "owned_by": "pendra",
      "type": "chat",
      "capabilities": ["completion", "tools", "thinking"],
      "parameter_size": "27B",
      "reasoning": "hybrid"
    },
    {
      "id": "nomic-embed-text",
      "object": "model",
      "created": 1707947709,
      "owned_by": "pendra",
      "type": "embedding",
      "capabilities": ["embedding"]
    }
  ]
}

created is the model's release date, in Unix epoch seconds. It's 0 for the occasional model we don't have a date for.

What's in a live-model entry

Beyond the standard OpenAI id / object / created / owned_by, each entry carries a few Pendra fields so you can pick the right model without a second call:

  • type — the single capability this model serves: chat, image, embedding, rerank, ocr, transcription, or speech. This is the same value you filter on with ?type= below.
  • capabilities — everything the model can do, as an array: completion, vision, tools, thinking, embedding, rerank, ocr, transcription, image, speech. Check for one with includes() rather than comparing the whole array.
  • disabled_capabilities — any of the above that the worker has turned off for this model (e.g. ["vision"]). Absent when nothing is disabled.
  • parameter_size — the model's size as a human string (e.g. "70B"). Absent when it isn't known.
  • reasoningreasoning (always thinks before answering) or hybrid (thinking you can toggle per request). Absent on non-reasoning models.
  • recommended_size and recommended_steps — on image models, the default resolution (e.g. "1024x1024") and step count to start from. See image generation.
  • voices and default_voice — on speech models, the preset voices you can pass as voice, and the one used when you omit it. See text to speech.

A speech model's entry, for example, looks like this — the voices and default_voice are exactly what the text-to-speech guide points you here to read:

{
  "id": "your-speech-model",
  "object": "model",
  "created": 1748736000,
  "owned_by": "pendra",
  "type": "speech",
  "capabilities": ["speech"],
  "voices": ["ryan", "vivian", "aria"],
  "default_voice": "ryan"
}

Filter by type

Pass ?type= to narrow the list to a single capability: chat, image, embedding, rerank, ocr, transcription, or speech.

curl
curl "https://api.pendra.ai/api/v1/models?type=embedding" \
  -H "Authorization: Bearer pdr_sk_..."

Codex compatibility

OpenAI Codex sends a client_version query parameter and expects a different envelope ({"models": [...]} instead of the standard OpenAI list). Pendra detects Codex and returns the right shape automatically — no configuration needed.

The model catalogue

GET /api/v1/catalogue lists the models Pendra can install on your worker via one click in the console. You can call it without a key to see the public catalogue; if you send your API key, the response also includes any models Pendra has made available specifically to your organisation. Catalogue installs download a verified GGUF onto the worker. Every entry is vetted by Pendra before it appears in the catalogue.

curl
curl https://api.pendra.ai/api/v1/catalogue

Catalogue response

Returns a flat list of catalogue entries. Each entry describes a canonical Pendra model plus its variants (sizes and quantisations), and each variant carries the verified GGUF that Pendra installs.

{
  "data": [
    {
      "id": "gemma4",
      "name": "Gemma 4",
      "publisher": "Google DeepMind",
      "description": "...",
      "capabilities": ["completion", "vision", "thinking", "tools"],
      "context_length": 262144,
      "homepage": "https://...",
      "licence": "apache-2.0",
      "reasoning": "reasoning",
      "publishing_country": "us,gb",
      "release_quarter": "Q2 2026",
      "variants": [
        {
          "id": "gemma4:12b",
          "label": "12B",
          "parameter_size": "12B",
          "architecture": "dense",
          "architectures": ["dense"],
          "quantization": "Q4_K_M",
          "context_length": 262144,
          "disk_size": 7300000000,
          "estimated_vram_bytes": 9500000000,
          "kv_bytes_per_token": 147456,
          "bits_per_weight": 4.83,
          "gguf_url": "https://get.pendra.ai/models/...",
          "gguf_sha256": "...",
          "gguf_size_bytes": 7300000000,
          "task": "chat",
          "installable_via": ["dashboard", "cli"]
        },
        {
          "id": "gemma4:26b",
          "label": "26B",
          "parameter_size": "26B",
          "architecture": "moe",
          "architectures": ["moe"],
          "active_parameters": "4B",
          "quantization": "Q4_K_M",
          "context_length": 262144,
          "disk_size": 16000000000,
          "estimated_vram_bytes": 18400000000,
          "kv_bytes_per_token": 98304,
          "bits_per_weight": 4.80,
          "gguf_url": "https://get.pendra.ai/models/...",
          "gguf_sha256": "...",
          "gguf_size_bytes": 16000000000,
          "task": "chat",
          "installable_via": ["dashboard", "cli"]
        }
      ]
    },
    {
      "id": "nomic-embed-text",
      "name": "nomic-embed-text-v1.5",
      "publisher": "Nomic",
      "description": "...",
      "capabilities": ["embedding"],
      "context_length": 2048,
      "homepage": "https://...",
      "licence": "apache-2.0",
      "variants": [
        {
          "id": "nomic-embed-text:nomic-embed-text-v1.5",
          "label": "v1.5",
          "quantization": "Q4_K_M",
          "disk_size": 84106624,
          "gguf_url": "https://get.pendra.ai/models/...",
          "gguf_sha256": "...",
          "gguf_size_bytes": 84106624,
          "task": "embedding",
          "installable_via": ["dashboard", "cli"]
        }
      ]
    }
  ]
}

What's in a catalogue entry

  • id — canonical Pendra ID (e.g. qwen3.5).
  • capabilities — an array describing what the model can do: completion, vision, tools, thinking, embedding, rerank, ocr, image.
  • variants — sizes and quantisations, each carrying the GGUF install metadata: gguf_url + gguf_sha256 (the model weights, served from Pendra's CDN at get.pendra.ai and checksum-verified at install time), gguf_size_bytes, disk_size (total on-disk footprint in bytes, including the vision projector and every shard where applicable), and installable_via (e.g. ["dashboard", "cli"]).
  • gguf_parts — present instead of gguf_url on very large models whose weights ship as several files (sharded GGUF, e.g. a 235B MoE or a frontier model). It's an ordered list of { url, sha256, size_bytes } parts, each served from get.pendra.ai and checksum-verified; Pendra downloads and verifies every part, then loads the model from the first one. You don't need to handle this differently — installing the variant works the same way.
  • architectures — on each chat variant, the list of architecture properties that size has: dense, moe (Mixture-of-Experts), hybrid (a state-space/attention mix), or diffusion. It's a list because a size can be more than one at once — a Mixture-of-Experts model built on a hybrid state-space stack is both, and comes back as ["hybrid", "moe"]. Check for a value with includes() rather than comparing the whole list. MoE sizes also carry active_parameters (the per-token count, e.g. "3B" for a 35B model — see the architecture guide). Embedding, transcription, and image models omit both.
  • architecture — the single value that best describes the same size, for code that wants one string to show. It's always one of the entries in architectures, so it stays safe to display — but don't test it for a specific value: a size that is both hybrid and MoE reads "hybrid" here, and a check like architecture === "moe" would miss it. Use architectures for that.
  • estimated_vram_bytes — roughly how much GPU memory this variant needs to run entirely on the GPU: the weights plus the cache Pendra holds back for your conversation context. Compare it against a card's memory to tell, before you install anything, whether a size will fit — a 24 GB card is 24 * 1024 ** 3 = 25,769,803,776 bytes, and you want comfortable headroom rather than a bare fit. It's an estimate, not a promise: it's calculated from the model's own file header using the same arithmetic the worker uses when it loads the model, so the two agree, but real usage moves with your context length and batch size. Absent on a few older catalogue entries, where disk_size is the best rough proxy.
  • kv_bytes_per_token — how much cache memory one token of context costs, so you can work out what a longer context adds: 32,768 tokens on a variant reporting 147,456 bytes/token is about 4.8 GB on top of the weights. 0 is a real answer and not an error — some models use a sliding-window attention scheme whose cache doesn't grow per token in this way, and Pendra budgets a flat allowance for them instead. Prefer estimated_vram_bytes for the "will it fit" question; this field is for reasoning about the context you plan to use.
  • bits_per_weight — the average number of bits each parameter is stored in, which is how aggressively the variant is quantised. Higher is closer to the original model. Around 8 is near-lossless, 5–6 is a common quality choice, and 4 and below trades noticeable accuracy for a much smaller download. Useful for choosing between two quantisations of the same size: the one with more bits per weight is the more faithful of the two. Absent when the model's parameter count isn't known — Pendra reports it only when it's measured, never estimated from the quantisation name.
  • reasoning — at the model level: reasoning (thinks before answering) or hybrid (thinking you can toggle on or off per request). Absent on non-reasoning models.
  • publishing_country — the publisher's country as one or two comma-separated ISO 3166-1 alpha-2 codes (e.g. "cn", or "us,gb" for a model published by an organisation spanning two countries). Absent when unknown.
  • release_quarter — when the model was publicly released, to the quarter (e.g. "Q2 2026"). Absent when unknown.
  • parameter size, context length, licence.

Curated installs

Every catalogued variant installs onto the worker — one click in the console, or pendra models install <id> from the CLI. The installable_via field on each variant tells you where it can be installed from (dashboard, cli, or both).

Naming conventions

Chat models use the name:tag convention (e.g. qwen3.5:0.8b, llama3.3:70b). Embedding models use a slug-style id (e.g. nomic-embed-text:nomic-embed-text-v1.5). The full set of names lives in the catalogue endpoint above.