---
title: "xAI / Grok"
description: "Route Claude Code inference to xAI's Grok — either your SuperGrok / X Premium+ subscription (the grok provider, OAuth) or the xAI developer API (the xai provider, API key)."
image: "https://shunt-docs.pages.dev/og.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://shunt-docs.pages.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# xAI / Grok

Two built-in providers route Claude Code to xAI's **Grok** models. They differ only in **how they
authenticate and which xAI surface they hit** — pick one:

| Provider | Auth | Backend | Billing |
| :-- | :-- | :-- | :-- |
| **`grok`** | `xai_oauth` — your **SuperGrok / X Premium+** login | `cli-chat-proxy.grok.com/v1` (the Grok CLI chat proxy) | your subscription — no per-token charge |
| **`xai`** | `api_key` (`XAI_API_KEY`) | `api.x.ai/v1` (the developer API) | metered API credits |

Both are **`kind = "responses"`** providers speaking xAI's Responses dialect — the same translation
path as [Codex](/guides/codex/), which this page mirrors. It links out to the deeper topic pages
([Effort & Context](/guides/effort-and-context/), [Model Discovery](/guides/model-discovery/),
[Providers](/guides/providers/)) rather than repeating them.

> **The two paths are not interchangeable**
>
> A **subscription** bearer only works against the **`grok`** proxy — the developer API (`api.x.ai`)
> rejects it with a `402` (`personal-team-blocked:spending-limit`, *"…need a Grok subscription…"*).
> An **API key** only works against **`xai`**. Route your Grok slugs to whichever provider matches the
> credential you have.

## Quick start

Let a coding agent wire it up for you — `shunt add` prints the setup blueprint for either path
(offline and read-only; the agent edits the config, the command never does):

```bash
shunt add upstream grok --print | claude   # SuperGrok / X Premium+ subscription (OAuth)
shunt add upstream xai --print | claude    # xAI developer API (XAI_API_KEY)
```

Or follow the manual steps below.

## How it works

shunt translates Claude Code's Anthropic Messages request into the OpenAI **Responses API**, sends
it to xAI, and translates the streamed reply back. The `xai` **Responses flavor** (drops params xAI
rejects, keeps tools as function tools) is selected two ways: by an **`api.x.ai` host**, or by
**`auth = "xai_oauth"`** (the `grok` proxy isn't an x.ai host, so its dialect is keyed on the auth).

| Aspect | `grok` (subscription) | `xai` (API key) |
| :-- | :-- | :-- |
| Endpoint | `cli-chat-proxy.grok.com/v1/responses` | `api.x.ai/v1/responses` |
| Auth | Grok CLI OAuth from `~/.shunt/xai-auth.json`, auto-refreshed | `Bearer $XAI_API_KEY` |
| Identity headers | Grok CLI headers (`x-xai-token-auth`, `x-grok-client-identifier`, `x-grok-client-version`) so the proxy honors the subscription | none |

> **Off-origin token guard**
>
> An `xai_oauth` provider will only send its subscription bearer to an **x.ai or grok.com host over
> HTTPS**, and only with `kind = "responses"`. Point one elsewhere and `shunt check` refuses it —
> shunt won't leak a subscription token to an arbitrary `base_url`.

## Path A — SuperGrok subscription (`grok`)

### 1. Log in

Run shunt's own device-code login (RFC 8628). It prints a URL and a code; approve in a browser on
any device — no loopback callback server:

```bash
shunt login xai
```

On success shunt writes the tokens to **`~/.shunt/xai-auth.json`** with `0600` permissions and
refreshes them automatically (a 5-minute expiry buffer; xAI rotates the refresh token on every refresh, so shunt
persists the rotated one under a single-flight lock). If the refresh token is gone or the response
omits a rotated token, shunt tells you to run `shunt login xai` again.

> **A different auth-file location**
>
> Override the path with `$SHUNT_XAI_AUTH_FILE` for CI, a sandbox, or a second account:
>
> ```bash
export SHUNT_XAI_AUTH_FILE=/etc/shunt/xai-auth.json
```

### 2. The provider block (optional)

`grok` is built in — you don't need to declare it. This is the full default; a partial table
overrides only the keys you set (config maps deep-merge):

```toml
[providers.grok]
kind = "responses"
base_url = "https://cli-chat-proxy.grok.com/v1"   # shunt appends /responses
auth = "xai_oauth"                                # read + auto-refresh ~/.shunt/xai-auth.json
# effort = "high"                                  # optional — opt in to reasoning effort (§ Reasoning effort)
```

### 3. Route a model to `grok`

```toml
[[routes]]
model = "grok-4.5"
provider = "grok"
# upstream_model = "grok-4.5"   # optional: forward a different slug upstream
```

## Path B — xAI developer API (`xai`)

### 1. Export the key

```bash
export XAI_API_KEY=xai-…
```

### 2. The provider block (optional)

```toml
[providers.xai]
kind = "responses"
base_url = "https://api.x.ai/v1"   # shunt appends /responses
auth = "api_key"
api_key_env = "XAI_API_KEY"
```

### 3. Route a model to `xai`

```toml
[[routes]]
model = "grok-4.5"
provider = "xai"
```

> **Needs API credits, not a subscription**
>
> `api.x.ai` bills against your xAI **API** credits. A SuperGrok / X Premium+ subscription does **not**
> entitle the developer API — an unfunded account returns `402 Payment Required`
> (*"You have run out of credits or need a Grok subscription…"*). Add credits at
> [console.x.ai](https://console.x.ai/), or use **Path A** to spend your subscription instead.

## Model slugs

The slug catalog is **xAI's**, not shunt's — shunt forwards whatever slug you route. Current
coding/frontier slugs are `grok-4.5`, `grok-4.3`, and `grok-build-0.1`. Use `upstream_model` in a
route to map an alias onto a live slug without touching your Claude Code env. (Model
[discovery](/guides/model-discovery/) only surfaces `claude-`named aliases you declare, so it can't
list a raw Grok slug — reach these via `ANTHROPIC_CUSTOM_MODEL_OPTION` or a tier remap below.)

## Select the model in Claude Code

Grok slugs don't start with `claude-`, so Claude Code's `/model` picker won't list them from
discovery. The mechanics are **identical to Codex** — add the id to the picker directly:

```bash
export ANTHROPIC_CUSTOM_MODEL_OPTION="grok-4.5"   # must resolve via [models.upstream_model], [[routes]], or [[route_prefixes]]
```

The same [Codex section](/guides/codex/#4-select-the-model-in-claude-code) covers the rest verbatim:
putting a **subagent** on a Grok slug via `model:` frontmatter, and remapping the **tier aliases**
(`ANTHROPIC_DEFAULT_SONNET_MODEL`, …) onto Grok slugs for a whole session.

> **Ready-made agents**
>
> The **[`shunt-xai` plugin](https://github.com/pleaseai/shunt/tree/main/plugins/shunt-xai)** ships
> subagents for `grok-4.5` / `grok-4.3` / `grok-build-0.1` — install with
> `/plugin install shunt-xai@shunt` after `/plugin marketplace add pleaseai/shunt`. Each agent pins
> its `model:`, so only that subagent diverts; the main session stays on Claude. Route the slugs to
> `grok` or `xai` in `shunt.toml` per the credential you have.

## Reasoning effort

**Unlike Codex, effort is opt-in for Grok.** Several Grok models (`grok-4*`, `grok-3`,
`grok-code-fast`, …) return `400` on a `reasoning.effort` field even though they reason natively, so
shunt sends the dial **only when you configure it** on the provider or route (or pass it per
request) — otherwise the model uses its native reasoning:

```toml
[providers.grok]
effort = "high"        # applies to all grok traffic

# …or per route
[[routes]]
model = "grok-4.5"
provider = "grok"
effort = "high"
```

`grok-4.5` accepts `reasoning.effort` (verified live). Leave `effort` unset for any slug that
`400`s on it. Full precedence and the effort table: [Effort & Context](/guides/effort-and-context/#reasoning-effort).

## Context window

Claude Code sizes its context bar at a fixed **200k** for a mapped id. If your Grok slug's real
window is larger, raise it — the value follows a non-`claude-` id automatically:

```bash
export CLAUDE_CODE_MAX_CONTEXT_TOKENS=256000   # set your slug's real window, per xAI's model docs
```

It's **global** (one value per session); set it to the smallest real window among your mapped
models, since exceeding a model's real window causes `prompt is too long` overflow churn. Details
and `count_tokens` behavior: [Effort & Context](/guides/effort-and-context/#context--usage-display-for-mapped-models).

## Web search

Claude Code's built-in **web search does not work on Grok routes.** xAI's Responses API accepts only
function tools, so shunt drops the hosted `web_search` tool on the `xai` flavor (both `grok` and
`xai`). Use a [`codex` or `openai` route](/guides/codex/#web-search) when you need hosted web search.

## Full example (subscription path)

`shunt.toml`:

```toml
[server]
bind = "127.0.0.1:3001"
default_provider = "anthropic"

[providers.grok]
effort = "high"     # optional: opt in to reasoning effort for all Grok traffic

[[routes]]
model = "grok-4.5"
provider = "grok"
```

Shell (both shunt and Claude Code run with these):

```bash
shunt login xai                                     # one-time device-code login
./target/release/shunt run                          # start the gateway

export ANTHROPIC_BASE_URL=http://127.0.0.1:3001
export ANTHROPIC_CUSTOM_MODEL_OPTION="grok-4.5"     # add to /model picker
```

Pick **grok-4.5** from `/model`. Everything else in the session still flows to Anthropic unchanged;
only the mapped model's inference is answered by your SuperGrok subscription.

## Troubleshooting

| Symptom | Cause / Fix |
| :-- | :-- |
| `run shunt login xai` on startup | No `~/.shunt/xai-auth.json` (or wrong `$SHUNT_XAI_AUTH_FILE`). Run `shunt login xai`. |
| `xAI refresh response missing refresh_token; run shunt login xai` | The stored refresh token was consumed/rotated away. Log in again. |
| `402 … personal-team-blocked:spending-limit` / *"need a Grok subscription"* | On the **`xai`** (developer API) path without API credits. Add credits at [console.x.ai](https://console.x.ai/), or route to **`grok`** to use your subscription. |
| `403 … not authorized for API access` (subscription tier gate) | On the **`grok`** path your subscription tier doesn't include API access — **re-logging in won't help**. Set `XAI_API_KEY` and use the `xai` path, or upgrade at [x.ai/grok](https://x.ai/grok). |
| `refusing to send a subscription token off-origin` (from `shunt check`) | An `xai_oauth` provider's `base_url` host isn't `x.ai`/`grok.com`, isn't HTTPS, or isn't `kind = "responses"`. Fix the block. |
| `400` when effort is set | That Grok slug rejects `reasoning.effort`. Remove `effort` from the provider/route for it. |
| `model <slug> is not enabled for this account` | Unentitled slug — confirm the slug against xAI's catalog. |
| Web search returns nothing | Not supported on Grok routes; shunt drops the tool. Use a `codex`/`openai` route. |

See the full [Troubleshooting](/reference/troubleshooting/) reference for more.

Source: https://shunt-docs.pages.dev/guides/xai/index.mdx
