Back to docs

Providers & API

Zod has no backend of its own. It talks directly from your browser to any OpenAI-compatible endpoint, giving you hub-first chat UI on top of the provider you choose — and full control over streaming, retries, rate limits, and timeouts.

Any OpenAI-compatible endpoint

Zod works with anything that speaks the OpenAI /v1/chat/completions format. Configure as many providers as you like and pick a default and a fallback.

OpenAI OpenRouter Together Groq Ollama LM Studio Anything that speaks /v1/chat/completions

Provider configuration

Providers are edited as live YAML in Settings → Providers. Each provider has a name, base URL, API key, model, and an enabled flag:

providers:
  - name        : OpenRouter
    baseUrl     : https://openrouter.ai/api/v1
    apiKey      : sk-or-v1-REPLACE-ME-00000000000000
    model       : openrouter/free
    enabled     : true

Default & fallback

Pick a default provider in Settings → General. Optionally choose a fallback provider: if the primary provider fails, Zod transparently retries on the fallback so a failed provider never stops the conversation.

Streaming & resilience

The provider engine is built for real-world use, with each behavior configurable from Settings.

Streaming (SSE)

Server-sent events are parsed token by token with onToken callbacks.

Retries with exponential backoff

Retries wait 500ms * attempt and only trigger on retryable failures (429, 5xx, timeouts, network).

Rate limiting (RPM)

A sliding 60-second window honors your configured requests-per-minute limit.

Timeout (AbortController)

An AbortController aborts after the configured timeout and converts it into a friendly error.

Request tuning

All request behavior is tuned from Settings → General:

Setting Options Default
Timeout 30s – 300s 120s
Retries 0 – 10 3
Rate limit (RPM) Unlimited / 60 / 120 / 300 Unlimited
Request logging On / off Off

Model autocomplete

The Providers editor fetches real models from each provider's /models endpoint and autocompletes the model field — so you never have to guess model IDs.

How requests are built

buildMessagesForChat flattens a session's user and assistant messages into the OpenAI message shape. Attached files are embedded as ### File: blocks inside the user content:

[
  { "role": "user",      "content": "Summarize the attached file." },
  { "role": "assistant", "content": "Sure — here is the summary." },
  {
    "role": "user",
    "content": "Here is the file you need:\n\n### File: report.md\n# Q3 results\nRevenue was up 12%...",
  }
]

The request is sent with all built-in tool schemas (plus custom and MCP tools), and tool calls are parsed from both normal and streaming responses — accumulating streamed function arguments across chunks.