---
title: "LLM Provider APIs"
description: "Call Groq, Cerebras, Gemini, OpenRouter, or DeepSeek directly over HTTPS with your own API keys."
canonical: "https://nuabase.com/docs/direct/"
---

> Documentation index: https://nuabase.com/llms.txt

Pass one or more provider API keys to `Nua.direct()` and Nuabase calls the provider's API directly over HTTPS, from your process. There is no CLI to install and nothing in between you and the provider.

## Configuration

```typescript
import { Nua, z } from 'nuabase';

const nua = Nua.direct({
  providers: {
    groq: { apiKey: process.env.GROQ_API_KEY! },
    cerebras: { apiKey: process.env.CEREBRAS_API_KEY! },
    gemini: { apiKey: process.env.GEMINI_API_KEY! },
    openrouter: { apiKey: process.env.OPENROUTER_API_KEY! },
    deepseek: { apiKey: process.env.DEEPSEEK_API_KEY! },
  },
  model: { alias: 'fast' }, // the default
});
```

Configure only the providers you have keys for. A single provider is enough.

## Choosing a model

Set a default `model` on the client, and override it per call. A model is either an alias or an explicit provider and model:

```typescript
// By alias: uses the first provider in the alias's list that you have a key for
await nua.get('Extract the company name', {
  input: text,
  output: { name: 'companyName', schema: z.string() },
  model: { alias: 'sonnet' },
});

// By provider and model
await nua.get('Extract the company name', {
  input: text,
  output: { name: 'companyName', schema: z.string() },
  model: { provider: 'openrouter', model: 'z-ai/glm-5.3-flash' },
});
```

With no model set anywhere, Nuabase uses `{ alias: 'fast' }`, which tries Cerebras, then Groq, then OpenRouter. If you have a key for none of an alias's providers, or name a provider you haven't configured, the call returns `success: false`.

See [Models & Providers](/docs/direct/providers.md) for every alias and provider.

## Runtimes

The main `nuabase` entry point imports no Node.js built-ins, so a client configured with `providers` runs in Node.js and in edge runtimes such as Cloudflare Workers and Vercel Edge.

Your API keys go in the request to the provider, so run these calls on a server or in an edge function, never in code shipped to a browser.

## Results

```typescript
if (result.success) {
  result.model;         // "openrouter:z-ai/glm-5.3-flash"
  result.meta.engine;   // "http"
  result.meta.provider; // "openrouter"
  result.meta.model;    // "z-ai/glm-5.3-flash"
  result.usage;         // { promptTokens, completionTokens, totalTokens, promptCacheReadTokens?, promptCacheWriteTokens? }
}
```

`promptCacheReadTokens` and `promptCacheWriteTokens` are present when the provider reports them. See [prompt caching](/docs/how-it-works.md#prompt-caching) for how to get cache hits.

## Requests and retries

Each call makes one HTTPS request to the selected provider, plus up to 2 retries on transient errors or output that fails validation. A 401, 403, or 404 response (a bad API key, no access, or an unknown model) fails at once. Rate-limit and quota responses (429) are retried like other errors, and Nuabase sets no request timeout of its own.

## Moving between engines

A client built with `providers` and one built with `localAgent` have the same `get()` and `list()` methods and return the same result shape. A common pattern is to develop against your coding agent and deploy with an API key:

```typescript
import { Nua } from 'nuabase';

const nua = process.env.OPENROUTER_API_KEY
  ? Nua.direct({ providers: { openrouter: { apiKey: process.env.OPENROUTER_API_KEY } } })
  : Nua.direct({ localAgent: await (await import('nuabase/local-agent')).findLocalAgent() });
```

The dynamic import keeps `nuabase/local-agent`, which needs Node.js, out of code paths that run in edge runtimes.

Model aliases are the one difference to watch: a per-call `model: { alias: 'sonnet' }` works on both an OpenRouter client and Claude Code, but `{ alias: 'fast' }` has no local agent equivalent, and provider models can't run on a local agent.
