Apps from Replit, Lovable, Bolt and v0
The builder's own agent runs on its own models, but the app it builds can call RouterPlus with your key: a ready prompt.
Replit, Lovable, Bolt and v0 build apps for you with their own AI agents. Those agents run on the builder's own models, billed by the builder: you cannot point Replit Agent, Lovable, Bolt or v0 itself at RouterPlus. The app that the builder makes for you is different. When the app has AI features of its own (a chat box, a summary button, an agent), it can call RouterPlus with your key. You choose the model, and every call is billed to one RouterPlus balance.
Before you start
- 01
- 02Give the app its own key, and set a monthly spend cap on it with Set cap. A bug or a loop in the app then cannot spend your whole balance.
- 03Pick a model id from
/api/models.json.claude-sonnet-5-5is a good default.gpt-6-lunaandclaude-haiku-5-5cost much less.
The prompt
Paste this into the builder's chat, as it is:
Use my own API key. Call AI through RouterPlus: OpenAI-compatible, base URL https://api.routerplus.com/v1, model claude-sonnet-5-5, key in a secret named TM_API_KEY.The builder then writes code that calls the gateway with the OpenAI SDK, and asks you for the secret. If it offers its own AI service instead, say no: that service bills you through the builder, not through RouterPlus.
For an app with more AI features, add the rules that keep it safe and cheap:
Rules for every AI call:
- Use the official OpenAI SDK with baseURL https://api.routerplus.com/v1 and apiKey from the TM_API_KEY secret.
- Call it only from server-side code (an API route, a server action or a backend function). Never put the key in browser code.
- Send max_tokens on every request. Stream answers that a person reads as they arrive.
- Copy model ids from https://app.routerplus.com/api/models.json. Never invent one.
- On an error, read error.metadata.error_type. On rate_limit, wait retry-after seconds, then retry, at most twice. On insufficient_quota, show "AI is unavailable" and do not retry.
- Docs for the gateway: https://app.routerplus.com/llms.txtStore the key as a secret
Keep the key in the builder's secret store, under the name TM_API_KEY. Never paste it into the chat, and never into code.
| Builder | Where the secret goes |
|---|---|
| Replit | Tools → Setup → Secrets → New Secret, key TM_API_KEY, then Add Secret. The app reads it as an environment variable. A published app does not get workspace secrets by itself: add it again under Publishing → Adjust settings → Production app secrets. |
| Lovable | More → Cloud → Secrets → Add secret, or the secure form that Lovable shows in the chat when it asks for the key. Only the app's server code (its backend functions) can read it. |
| Bolt | The Secrets page of Bolt Cloud (the database icon at the top): a name TM_API_KEY and the key as its value, then Create secret. The app's server functions read it. |
| v0 | The project's Settings → Environment Variables (the Vars panel), for the environments that need it. The v0 preview reads the Development value. |
The key must stay on the server. A key in browser code can be copied by anyone who opens the app, and the gateway accepts calls from any web page. Some builders put a variable into browser code when its name starts with VITE_ or NEXT_PUBLIC_: never give the key such a name.
What the code looks like
The builder writes this for you. It is here so that you can check its work.
openai packageimport OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.routerplus.com/v1",
apiKey: process.env.TM_API_KEY,
});
export async function POST(req: Request) {
const { question } = await req.json();
const reply = await client.chat.completions.create({
model: "claude-sonnet-5-5",
max_tokens: 1024,
messages: [{ role: "user", content: question }],
});
return Response.json({ answer: reply.choices[0]?.message.content });
}openai packageimport os
from openai import OpenAI
client = OpenAI(base_url="https://api.routerplus.com/v1", api_key=os.environ["TM_API_KEY"])
reply = client.chat.completions.create(
model="claude-sonnet-5-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Summarize this note in one line."}],
)
print(reply.choices[0].message.content)Every chat model in the catalog answers on /v1/chat/completions, Claude and GPT alike. For GPT models, the OpenAI SDK's Responses API works too (client.responses.create, with model: "gpt-6-luna"): see POST /v1/responses. Claude models are a preview on that API, so call Claude on /v1/chat/completions.
Limits
- The builder's own agent keeps its own models and its own pricing. Your RouterPlus balance pays for the calls your app makes, never for the builder's work.
- The key belongs in a secret on the server, never in the browser.
- Each call is billed at the model's price, and
usage.costin every answer gives the exact amount (on the Responses API, inresponse.usage). GET /v1/usage and the console show what the app spent. - Limits and spend caps apply to the app's key: see Rate limits & spend caps.
Where next
Markdown source for agents: /docs/app-builders.md · index at /llms.txt