---
title: "Five-minute quick start · AGI Plan"
url: https://agiplan.dev/en/docs
description: "Pick your OS and the tool you use, then follow the steps. Each step says which file, what to paste and how to tell it worked; no account needed to read it."
language: en
markdown: https://agiplan.dev/en/docs.md
---

[← Back to home](https://agiplan.dev/en)

Documentation

# Five-minute quick start

Pick your OS and the tool you use, then follow the steps. Each step says which file, what to paste and how to tell it worked; no account needed to read it.

**Last updated**

2026-10-17

## Follow along: pick your OS and your tool

Every step below is copy and paste. One-click setup isn't ready yet, so for now you edit one config by hand — in order, under ten minutes.

Your computer runs

The tool you want to use

Anthropic's command-line coding assistant. **No Claude account needed** — once configured it runs on your quota here, with Prism picking the model.

Paste your key here and every command below fills itself in (optional)The key is only used on this page to fill in the placeholders below. It isn't saved or sent anywhere and is gone when you close the page. You can skip this and replace the placeholder yourself after copying.

1. ### Step 1：Before you start: get a key

   Sign in to the console, pick a plan, then click New on the Keys page. **The key is shown only once** — copy it right away and paste it into the box above. Then open **PowerShell**: press the Windows key, type `PowerShell`, press Enter. Paste every command below into that window (right-click pastes) and press Enter.
2. ### Step 2：Install Claude Code

   Already installed? Skip this. Otherwise copy the line below, paste it and press Enter, then wait for it to finish.

   PowerShell

   ```
   irm https://claude.ai/install.ps1 | iex
   ```

   Success looks like:Type `claude --version` and press Enter; you see a version number. If it says the command isn't found, **close the window and open a new one** — newly installed programs only show up in new windows.
3. ### Step 3：Write the config

   Copy the whole block (the Copy button, top right), paste it and press Enter. It writes `%USERPROFILE%\.claude\settings.json`; if that file already exists, the old one is backed up first with a `.bak` suffix. `auto` hands model choice to Prism, by task difficulty. The last line turns off a few Claude Code experiments that other vendors' models reject with a 400.

   PowerShell

   This block contains a key placeholder. Paste your key at the top of the page before copying, or replace the placeholder yourself afterwards.

   ```
   New-Item -ItemType Directory -Force "$HOME\.claude" | Out-Null
   if (Test-Path "$HOME\.claude\settings.json") { Copy-Item "$HOME\.claude\settings.json" "$HOME\.claude\settings.json.bak" -Force }
   [IO.File]::WriteAllText("$HOME\.claude\settings.json", @'
   {
     "env": {
       "ANTHROPIC_BASE_URL": "https://agiplan.dev",
       "ANTHROPIC_AUTH_TOKEN": "ap_live_replace_with_your_key",
       "ANTHROPIC_MODEL": "auto",
       "ANTHROPIC_DEFAULT_OPUS_MODEL": "auto",
       "ANTHROPIC_DEFAULT_SONNET_MODEL": "auto",
       "ANTHROPIC_DEFAULT_HAIKU_MODEL": "auto",
       "CLAUDE_CODE_SUBAGENT_MODEL": "auto",
       "CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS": "1"
     }
   }
   '@)
   ```

   **Rather not use a command? Create the file by hand**

   Run the first block; it opens `%USERPROFILE%\.claude\settings.json` in Notepad (click Yes when it asks to create the file). Paste the second block into Notepad and save with `Ctrl + S`. **Don't use Save As** — Notepad will quietly add `.txt`.

   PowerShell

   ```
   New-Item -ItemType Directory -Force "$HOME\.claude" | Out-Null
   notepad "$HOME\.claude\settings.json"
   ```

   %USERPROFILE%\.claude\settings.json

   This block contains a key placeholder. Paste your key at the top of the page before copying, or replace the placeholder yourself afterwards.

   ```
   {
     "env": {
       "ANTHROPIC_BASE_URL": "https://agiplan.dev",
       "ANTHROPIC_AUTH_TOKEN": "ap_live_replace_with_your_key",
       "ANTHROPIC_MODEL": "auto",
       "ANTHROPIC_DEFAULT_OPUS_MODEL": "auto",
       "ANTHROPIC_DEFAULT_SONNET_MODEL": "auto",
       "ANTHROPIC_DEFAULT_HAIKU_MODEL": "auto",
       "CLAUDE_CODE_SUBAGENT_MODEL": "auto",
       "CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS": "1"
     }
   }
   ```
4. ### Step 4：Start it and say something

   **Go to your project folder first** (e.g. `cd path/to/project`), then type `claude` and press Enter. The first time it asks whether you trust the folder — say yes. Then say anything.

   PowerShell

   ```
   claude
   ```

   **Getting an error? First check the key and the network**

   Paste this line and press Enter. A list of models with `"id"` fields means the key and network are fine and the tool's config is off — go back and paste the previous step again. `401` means the key is wrong or deleted; nothing at all or a connection error means a network problem.

   PowerShell

   This block contains a key placeholder. Paste your key at the top of the page before copying, or replace the placeholder yourself afterwards.

   ```
   curl.exe -s https://agiplan.dev/v1/models -H "Authorization: Bearer ap_live_replace_with_your_key"
   ```

   Success looks like:It answers normally. Type `/status` and the `Anthropic base URL` line shows our address — so it's running on us, not on an official account.

### If it doesn't work

- **Asked to choose a sign-in method on launch?** Run `claude update` first — older versions ignore the config file and stop at the first-run welcome screen. If it still happens after updating, the config file isn't where it should be; rerun the whole Write the config block.
- **401:** the key is mistyped or you deleted it in the console. Paste the key into the box above again and rerun the whole Write the config block.
- **404:** you edited the address by hand and it now ends in `/v1`. Claude Code's address has **no** `/v1`.
- **Using the Claude Code extension in VS Code?** The extension doesn't take its sign-in from this file. Add `claudeCode.environmentVariables` to your VS Code settings (JSON) with the `ANTHROPIC_BASE_URL` and `ANTHROPIC_AUTH_TOKEN` entries from the config above.
- **Set**`ANTHROPIC_*` variables in `.bashrc` / `.zshrc` or system environment variables before?**Remove them so they don't fight with this file.**
- **Don't name the model**`xxx[1m]` to unlock a 1M context.**Contexts beyond 400K are far more likely to be throttled or cut off upstream, and cost much more; letting it auto-compact around 200K is steadier for long tasks.**

Followed every step and it still fails? Open a ticket under Support in the console with **your OS, your tool and the exact error text** (never the key). A person answers.

## Writing your own code: two things

The guide above is for ready-made tools. For your own code or an official SDK you need exactly two things, the **endpoint** and the **key**; write the rest the way your SDK expects.

Change two things: point the base URL at us and swap in your key. Nothing else in your program changes.

```
# OpenAI-style SDKs take this (with /v1)
https://agiplan.dev/v1

# Anthropic-style SDKs take this (no /v1 — the SDK appends it)
https://agiplan.dev
```

Check both with one curl first. A list of models means it works; `401` means the key is wrong; a connection error means the address is mistyped.

```
curl -s https://agiplan.dev/v1/models -H "Authorization: Bearer ap_live_your_key"
```

**About the `/setup` script.** The home page used to recommend `curl …/setup | sh`. All it does is write those two values to `~/.config/agiplan/env` (mode 600), plus `OPENAI_BASE_URL` / `OPENAI_API_KEY` in the same file — once sourced, anything that reads those names routes through us. And Claude Code, Codex and OpenCode don't read that file, so you still had to edit each tool's config afterwards. We no longer recommend it; for tools, follow the guide above. The script is still there (open https://agiplan.dev/setup in a browser to read all of it) if you want it to manage env vars for your own code.

## Authentication

Every `/v1/*` endpoint takes a bearer token; `/v1/messages` also accepts the `x-api-key` header the Anthropic SDK sends, but **every other endpoint accepts only `Authorization: Bearer`**. Keys are created in the console and the **plaintext is shown exactly once** — we store only a SHA-256 hash, so a key can't be recovered, only rotated.

```
Authorization: Bearer ap_live_xxxxxxxxxxxx
```

Keys can be scoped, bound to a custom model, IP-restricted and given an expiry. When rotating, the old key can keep a grace period rather than being cut off instantly.

Each key also has a **routing preference** (chosen at creation, changeable any time): Auto (default, balances per request type), Speed (fastest first token, unit price may be slightly higher), Cost (slower responses for a lower unit price — when a model is served by several routes, CU is billed at the rate of the route that actually served you), or Cache (keep one route per conversation to reduce cache rewrites). The preference only affects how routes are chosen; failover and circuit breaking behave the same.

**Signing in to the console** is separate from calling the API: the API only takes keys, while the console uses an emailed code — or a **passkey** (fingerprint, face or phone unlock) you add under [Account & security](https://agiplan.dev/en/app/account), after which tapping the email field on the sign-in page is enough. Email codes always keep working; adding or removing a passkey asks you to confirm it's you first, and every change sends you a notification email.

## Which protocols

The same base URL serves compatible endpoints for three mainstream protocols. Which one you use depends on your SDK — you don't have to tell us.

Three doors into the same room: whichever dialect your SDK speaks, behind it is one key, one quota and one set of models.

| Endpoint | Protocol | Notes |
| --- | --- | --- |
| /v1/chat/completions | OpenAI-style | stream, tools, response_format |
| /v1/messages | Anthropic-style | stream, tools, system |
| /v1/responses | OpenAI Responses | stream, tools, `reasoning`; Codex's `custom_tool_call` / `compaction` / encrypted reasoning pass through untouched; `previous_response_id` avoids resending context. **Naming Claude in Codex runs Claude**: `apply_patch` and namespace tools are converted automatically; OpenAI-hosted tools such as web search aren't available on Claude. Only when the history holds items Claude can't take (`compaction` compacted history, `web_search_call` search results, `local_shell_call`) does it switch to an equally capable GPT model, and `x-agiplan-model-actual` plus the call record say which item triggered it |
| /v1/models | Any | Returns the names you can put in `model` right now: `auto`, `auto-fast`, every model you can call by name, and the image, video and audio models. Your own custom models are not listed; see “Custom models” in the console |
| /v1/quota | Any | Read the three windows without making a call; needs usage:read |
| /v1/images/{generations,edits} | OpenAI-style | Generate / edit images, billed per image; see [Advanced](https://agiplan.dev/en/docs/advanced#images) |
| /v1/videos | Async jobs | Submit a video job, poll, fetch the clip; billed per second; see [Advanced](https://agiplan.dev/en/docs/advanced#videos) |
| /v1/assets | AGI Plan extension | Asset library: upload reference images and audio once, reuse them; see [Advanced](https://agiplan.dev/en/docs/advanced#assets) |
| /v1/media/{id} | AGI Plan extension | Links to generated results; no key needed, kept 7 days; see [Advanced](https://agiplan.dev/en/docs/advanced#media-links) |

**Any tool that lets you change its endpoint works directly**, with no plugin and no code changes. Differences between the request formats are handled inside the gateway, so use whichever protocol you already know.

`/v1/responses` is the only stateful one: **on every call (with or without `previous_response_id`), that turn's input and output are stored on our side for at most 5 hours** so your next turn can continue with `previous_response_id`; a scheduled job deletes them when they expire. If you don't want this storage, use `/v1/chat/completions` or `/v1/messages` instead. The privacy policy states the same.

A few endpoints are deliberately not in the table: `/v1/device/code`, `/v1/device/token` and `/v1/keys/current` are the CLI's transport (used by `agiplan login` and `agiplan use`), not something you call directly. `/v1/traces/{id}` is covered under tracing below.

**Images work as inline `data:` URLs (base64) only — remote `http(s)` image links are not built yet.** A remote link is currently replaced with a text placeholder. **When that happens the response carries `x-agiplan-dropped-params: content[].image_url`**, so you won't assume the model saw the image. Audio and file parts behave the same way — currently dropped, and listed in the same header.

**For the fine print** (request and response headers, strict output caps, capability flags, the full image and video APIs, exact billing) see [Advanced usage & API reference](https://agiplan.dev/en/docs/advanced).

## Name a model, or hand it to Prism

One `model` field, several ways to use it: a **model's real name** pins that model — it fails over among that model's own lines, but never switches to a different model; a **capability tier name** routes and fails over among that tier's equivalent models; `auto` or your own custom model name hands it to Prism, which routes by task difficulty; `auto-fast` is **speed first, then cost** — same rules and failover as `auto`, which first sets the minimum tier the task needs, then picks the fastest tier at or above it right now (time to first token plus output speed), taking the cheaper one when two are within 20% of each other. You pay the chosen tier's price.

```
"model": "glm-5.3"         // real model name: pinned (fails over among its own lines), Prism stays out
"model": "domestic"        // tier name: routed among that tier's equivalent models, with failover
"model": "auto"            // handed to Prism
"model": "auto-fast"       // speed first, then cost (never below auto's tier)
"model": "my-coding-model" // your own custom model
```

One field, three meanings. When in doubt, send auto.

`glm-5.3` above is only an example: **the real model names you can use are whatever `GET /v1/models` returns** (the console's “Models & pricing” shows the same list). The tier names are `frontier`, `balanced`, `domestic` and `fast`. Names like `frontier-a` or `domestic-a` seen in older docs are aliases for a tier — they behave exactly like the tier name, **do not pin a single model**, and are not listed by `/v1/models`.

To override the difficulty judgement on a single request, add a header: `X-AGIPlan-Difficulty: 0.9`. Tier coefficients are listed at /models.

## Streaming

All three protocols stream SSE in their own native format, behaving exactly as you'd expect. The one thing to know: **billing settles when the stream ends**.

Timeline of one streaming call. The hold happens first, settlement last; an interrupted stream settles the same way.

On arrival we reserve quota: **the input side from the tokens already countable in the request**, the output side from the `max_tokens` you declared, capped at 16k. A normal finish, a client abort and a model-service error all run the same teardown, reconciling against actual usage and returning the difference, so disconnecting midway never bills you the worst case. Output beyond the reservation is billed as used, so a window can go slightly over its limit: **all in-flight requests together can exceed the 5-hour window by at most 10%**. To guarantee that, when `max_tokens` is above 16k the cap sent to the model may be lowered. Once over, the window shows 0 remaining and new requests wait for the reset. When a window is nearly used up and what is left cannot cover 16k of output, the request still goes through as long as it covers the input plus 4k of output: output is reserved from what remains and the cap sent to the model is lowered to match. Only below that do you get a 429.

## Reading the quota response

Every response from the three text-protocol endpoints carries the **remaining percentage** and reset time for all three windows (image and video endpoints don't; see [Advanced](https://agiplan.dev/en/docs/advanced#response-headers)). Absolute usage is in the console usage detail and the monthly statement. On rate limiting you get a 429 that says which window is full and when it recovers — **the 429 carries the same three headers**. An invalid key (401) carries none of them, because the account can't be identified at that point.

Three windows count at once; every call lands in all three. The 5-hour window is the confusing one: it is not a fixed slot. It starts at your first call after a break and resets 5 hours later, so after a 5-hour pause it is always full. The Max plan has no 5-hour window; only the week and billing month apply.

```
X-AGIPlan-Quota-Session: remaining=68%; resets=2026-08-15T09:00:00.000Z
X-AGIPlan-Quota-Week:    remaining=34%; resets=2026-08-18T00:00:00.000Z
X-AGIPlan-Quota-Month:   remaining=81%; resets=2026-09-05T00:00:00.000Z
Retry-After: 1740        // seconds, only on 429: time to the window reset, or 2 when concurrency is full
```

The size of the three windows follows your plan. You change plans in the console's Plans panel, with two choices of timing for an upgrade: **now**, where the difference for the remaining days is charged and the new quota applies immediately; or **from next period**, where this period's quota and price stay as they are, nothing is charged or refunded, and the subscription renews as the plan you picked at its price on that day, with the new quota starting then. **Downgrades are from next period only**: you keep your current plan for this period and nothing is refunded. The billing page shows which plan renews next and how much it will charge.

## Errors and retries

Use the status code to decide whether to retry, then the code in the table below to decide what to do.

| Status | Error code | Meaning | What to do |
| --- | --- | --- | --- |
| 401 | invalid_api_key | Key invalid or revoked | Use a different key; do not retry |
| 404 | model_not_found | Images endpoint: no such image model | See the entries with kind image in /v1/models |
| 410 | model_retired | The model you named has been retired. The message gives the retirement date and suggested replacements | **Retrying will not help.** Change model to the replacement in the message (for example auto-fast); retired models are also listed at the bottom of Models & prices in the console |
| 503 | size_unavailable | Images endpoint: no route supports that size right now | Try another size or retry later. Failed calls are not billed |
| 400 | quality_unavailable | Images endpoint: none of this model's routes for that size accept the `quality` you sent | **Retrying will not change the result.** Use one of the values listed in the error, or `auto` |
| 404 | unknown_model | `model` is not a real model name, a tier name, or one of your custom models | Check `GET /v1/models`, or create a custom model in the console first |
| 404 | session_expired | `/v1/responses`: the session behind `previous_response_id` is past its 5-hour retention | Drop `previous_response_id` and resend the full context |
| 404 | session_not_found | `/v1/responses`: no such `previous_response_id`, or it isn't yours | Check the id came from a response on the same account |
| 404 | trace_expired | `/v1/traces/{id}`: the trace is past its 30-day retention | The trace has been deleted and can't be fetched |
| 404 | trace_not_found | `/v1/traces/{id}`: no such trace, or it isn't yours (a key without the `usage:read` scope gets 403 `insufficient_scope` first and never reaches this) | Check the trace id and the key |
| 401 | key_rotation_required | Key is older than the org's rotation policy | Rotate a new one in the console |
| 400 | capability_unavailable | No connected model supports a capability the request declares (vision, tools…). If the named model lacks it but another model has it, the gateway switches to that model and says so in the headers and usage log instead of failing | **Retrying will not help.** Drop the requirement, or wait for a model that supports it to be connected |
| 400 | context_too_small | The model you named by its raw ID has a smaller context window than this request's `min_context_k` | **Retrying will not change the result.** Shorten the context, or pick a model with a larger window — /models lists the window for every model |
| 400 | upstream_rejected_request | The model service rejected the request itself (parameters or content), or the input exceeds the context window of every available line (when one line cannot fit it, the gateway first moves to a line that can) | **Another model gives the same answer.** Check the request (shorten the context if it is too long); if you believe it is valid, send us the trace id |
| 400 | upstream_rejected | Images / video: the model service rejected this generation (prompt or reference assets not allowed, or size / parameters not accepted) | **Another route gives the same answer.** Change the prompt or size and retry; failed calls are not billed |
| 400 | request_exceeds_mix_cap | Worst-case estimate exceeds the `max_cu_per_request` set in your custom model | **This is your own cap.** Lower max_tokens, shorten the context, or raise the value |
| 403 | insufficient_scope | Key lacks the required scope | Use a key that has it |
| 403 | plan_excludes_model | Your custom plan doesn't include this model or group | Use a model in your plan, or contact us to change it |
| 400 | strict_max_tokens_unavailable | You sent `X-AGIPlan-Strict-Max-Tokens`, and every route that could serve the request does not guarantee `max_tokens` | **Retrying will not change the result.** Drop the header (output beyond the cap is billed at actual usage), or use `auto` / another tier |
| 403 | no_subscription | No active subscription, and pay-as-you-go is off (or the balance is empty) | Subscribe in the console, or enable pay-as-you-go and top up |
| 429 | quota_exceeded | A window's quota is exhausted | Wait per Retry-After, or move to a cheaper capability tier. If you hold a quota reset for that window, the error says so; use it from the console overview to restore the quota at once |
| 429 | concurrency_exceeded | In-flight requests hit your plan's ceiling | Wait for an in-flight request to finish before sending another. **Upgrading resolves this; topping up does not**, since it is not a quota problem |
| 429 | upstream_busy | Every model service that can take this request is full right now (rate-limited or at its concurrency limit); the gateway already waited a moment for a free slot | Retry after `Retry-After` (the shortest wait the model services gave, or 10 seconds). Not your quota or concurrency; failed attempts are not billed |
| 429 | rate_limited | Too many requests from the same source: CLI device-code requests and signing of result links are capped | Wait for Retry-After and try again. Normal use never hits this; looping scripts do |
| 451 | region_not_available | No model in that tier is offered in your region | **Retrying will not change the result.** Pick another tier, or see the region column at /models. If you picked the wrong region, change it under [Account & security](https://agiplan.dev/en/app/account#region); it takes effect immediately |
| 503 | no_supply_configured | No model service is currently available for that capability tier | **Retrying will not change the result.** Pick another tier, or use auto — /models shows how many lines each tier has right now |
| 503 | policy_unavailable | The custom model you called no longer compiles, usually because a model it pins was withdrawn | The error message names the pool and the model. In the console under Custom models, point that pool at another model or a tier; it takes effect as soon as you save |
| 503 | model_unavailable | The model you named by its raw ID has no working route right now | **The gateway will not substitute another model.** Retry later, or use a capability tier name (e.g. `domestic`) so the gateway can switch between equivalent models |
| 503 | all_upstreams_failed | Every model in the tier was tried and none worked | The body carries the full record of attempts. Failed attempts are not billed |
| mid-stream | upstream_interrupted | The model service dropped after output had started. The status is already 200, so this arrives as an error event inside the stream, **with no normal end marker after it** | **Output already sent is billed by actual tokens; a stream that drops before producing anything is not billed.** Switching models mid-answer would make it inconsistent, so the gateway does not fail over here; resend the request |

**Long waits on a stream start with comment lines.** Failover or a long prompt can delay the first event; if nothing has arrived after 20 seconds, the gateway sends 200 with the streaming headers, then an SSE comment `: keepalive` every 15 seconds (ignored by clients per the SSE spec) so idle timeouts in clients or proxies do not cut the connection. If such a request then fails, the error comes as an in-stream error event (codes as in the table above), and the response headers carry no quota or trace headers — the trace id is in a `: trace tr_…` comment line.

**You don't need to retry 5xx yourself.** Failover already ran inside the gateway — a 503 means every model in the tier was tried.

**This table lists the codes the gateway really returns.** Running out of quota is still a 429; with pay-as-you-go on, the request draws from your balance instead of being refused. If the balance can't cover it either, it is still a 429 and the message says which gate failed (not enabled, ceiling reached, insufficient balance).

**Branch on `code`, not on `message`.** `code` is the stable contract and changes are announced; `message` is a sentence for a human and its wording will change. **`message` is currently Chinese only**; `code` and the HTTP status are unaffected.

## Trace IDs

**Successful responses** carry a trace ID and the model that actually ran. If failover happened, that's marked too. **Refused responses carry no trace ID**, because the call never became a usage record. On a 503 the chain is in the response body as `attempts`; send that along when you report the problem.

```
X-AGIPlan-Trace: tr_01J8FQ3M7X
X-AGIPlan-Model-Actual: deepseek-v4-pro
X-AGIPlan-Failover: true
```

Reporting a problem takes one thing: the trace ID. You can also use it yourself to see which route the call took.

Fetch the full trace with your own key: `GET /v1/traces/{id}`, structured JSON, retained 30 days. Include the trace ID when reporting a problem.

## Docs for AI agents

When an agent such as Claude Code or Codex does the integration for you, hand it any of these. It gets Markdown without navigation or scripts, with the same numbers as the web page:

| URL | What you get |
| --- | --- |
| https://agiplan.dev/llms.txt | Site index: base URL, the three protocols, a Markdown link for every public page |
| https://agiplan.dev/llms-full.txt | Every public page as one Markdown file |
| Any public page + `.md` | e.g. `/en/docs.md`, `/en/pricing.md`, `/en/models.md`; home is `/en.md` |
| Header `Accept: text/markdown` | The page URL itself returns Markdown |

## Command line

**The CLI has no distribution channel yet**: it is not on npm and there is no download, so running `agiplan` gives command not found. The table below records implementation status, not whether you can run a command today.

| Command | What it does | Status |
| --- | --- | --- |
| agiplan login | device-code auth: confirm in the browser, key delivered to the terminal | Available |
| agiplan status | remaining percentage in each of the three windows | Available |
| agiplan models | available models and capability groups | Available |
| agiplan use <name> | bind a custom model to the current key; --none unbinds | Available |
| agiplan env | print evaluable environment variables | Available |
| agiplan keys rotate <config> | rotate a key | Declined, see below |
| agiplan uninstall | delete the config file setup wrote (--yes to actually delete) | Available |

**`keys rotate` is not offered, for security reasons.** If a key could issue its own successor, an attacker with a leaked key could rotate first, and the new key would survive when you revoke the old one. Rotation only happens through browser confirmation: rotate in the console, or run `agiplan login` again.

A per-project `.agiplan` file is supported. It holds **only the profile name, never a key**, so committing it is safe.

## Migrating from another service

If you already use an official SDK or another aggregator, only two things change: the endpoint and the key. Where model names differ, a custom model name gives you a mapping layer and your application code stays untouched.

**Two behaviours differ from the official API.** First, if you omit `max_tokens` we substitute 4096 and send it to the model, so long answers may be truncated at 4096 with `finish_reason: "length"`; when we do, the response carries `x-agiplan-max-tokens-default: 4096`. Second, when `max_tokens` is above 16k, or when the window is nearly used up, the cap sent to the model may be lowered, to bound how far a single request can go over quota (see the Streaming section above). When that happens, the trace records the value before and after.

**GLM models think, and the thinking tokens count against `max_tokens`.** Give it a small budget and you get an empty answer with `finish_reason: "length"`, billed as usual. With `auto` we steer around it: a request that did not ask for thinking and allows fewer than 1024 output tokens will not land on GLM. If you name a GLM model, leave `max_tokens` roomier than usual (at least 1024); to turn thinking on explicitly, send `thinking: { "type": "enabled", "budget_tokens": 2048 }`, accepted in both request formats.

**One more thing that affects your bill: when a request needs a capability the tier you picked cannot provide, we lift it to a tier that can — and bill the tier it landed on.** The common case is images: your custom model selects the fast tier, no model there has vision, so the call lands on the domestic flagship tier and is billed at that tier's higher coefficients. We only ever lift, never drop, so a downgrade never happens silently. **Every text-endpoint response carries `x-agiplan-billed-group` naming the tier actually billed**, matching what appears in your usage detail. To avoid being lifted, don't send that custom model content its tier can't handle, or pick a tier that supports it.

- Create a custom model named after the model name you use today, routing to the matching capability tier.
- Change the base URL and key, then run your tests.
- Check the coefficients at /models and reconcile your first day against the usage detail in the console.

## JMRAI legacy balance migration

Legacy JMRAI (jmrai.net) users can migrate their balance: sign in at jmrai.net, get your migration link, then confirm it on this page. Amounts are fixed by the frozen snapshot taken when the legacy service stopped; one legacy account binds to exactly one AGI Plan account, permanently.

The migrated amount lands as **bonus balance**: valid for 90 days from credit, usable for pay-as-you-go (not for buying or renewing plans), non-refundable, non-withdrawable and not invoiceable. After any paid purchase you also get a 5% bonus on your legacy top-ups (migrated amount included), credited automatically after a 7-day confirmation window with the same 90-day validity.

- Migration entry: jmrai.net (legacy password or WeChat verification code).
- The migration window closes automatically on 2027-10-12; unclaimed balances are forfeited after that.
- For amount or eligibility disputes, open a support ticket with your legacy order records.

If something is missing or unclear, email support@agiplan.dev or open a ticket in the console.
