Calling a model
Your site can ask a model a question: Anthropic or OpenAI with your key, or any visitor's own AI through OpenRouter. The key is never in the page.
Why not just put the key in
Because a published site is public. A key in the file is a key in the browser of everyone who opens it, and the first they will do with it is not what you had in mind. Bring-your-own-key on a static host is usually a way to leak one.
So the key stays with us. Your page asks its own address, we add the key, and we forward.
Who pays
Somebody pays for every answer. In the site's settings, under AI, you choose who, once for the site:
- You, with a saved key. On Pro and Team. Your own Anthropic or OpenAI key pays, up to a monthly cap you set.
- Each visitor, with their own OpenRouter account. On every plan, Free included. Each visitor connects once and pays for their own calls.
- Off. The site doesn't call a model.
Only one of them at a time, so you always know whose money a call spends.
Saved keys
A key is saved once, in Keys and connections under Model keys, and each site then chooses one from a list. Give each a name, such as “Anthropic, work”, and keep as many as you like, several for one provider included. A workspace's keys are saved in the workspace's settings, by its owner or an admin, and only its own sites can use them; your personal keys never pay for a workspace's site, or the other way round.
Once saved, a key is never shown again, only its last four characters, when it was last used and which sites use it. A key a site still uses can't be removed until that site chooses another, and Solta says which sites those are.
Create a separate key just for Solta, with a spending limit at the provider. Our cap is one defence; the provider's limit is the one that holds whatever happens here.
Choosing a model
You choose a tier, not a model, and every call from the site uses the tier's model whatever the page asks for. Answers are also held to the tier's longest, so a page can't ask for an essay on your key. The same tiers apply when visitors pay.
| Tier | Anthropic | OpenAI | Longest answer | 1,000 short answers |
|---|---|---|---|---|
| Fast and cheap | claude-haiku-5-5 | gpt-6-luna | 1,024 tokens | about $0.14 with Anthropic |
| Balanced (the default) | claude-sonnet-5-5 | gpt-6.1-sol | 2,048 tokens | about $2.80 with Anthropic |
| Best | claude-opus-5-5 | gpt-6-astra | 4,096 tokens | about $5.60 with Anthropic |
A short answer is a question of about 400 tokens and an answer of about 200, at the provider's list price. Your provider bills you, not us.
Caps and the limit for each visitor
When your key pays, each answer is priced from what the provider says it used, and the site stops at a monthly cap in dollars, $10 unless you set another. The site's settings show where it is, such as “$3.20 of $10 this month”. We email you at 80% and again at 100%. At the cap, calls are refused with { "code": "ai_allowance" } and a sentence your page can show, until the month turns or you raise the cap. Changing the key does not start the month again.
Each visitor also gets so many calls an hour, 20 unless you set another, whoever pays: counted by address and by a cookie on the site, so one visitor cannot empty a month's cap over lunch. Past it, calls are refused with { "code": "ai_visitor_limit" } and a retry-after.
Using it
With your key paying, post to /_solta/ai. The body is the provider's own request body, and what comes back is the provider's own response, unchanged, because its shape is theirs and not ours to promise. The model and the longest answer are the tier's; answers come back whole rather than streamed.
const res = await fetch("/_solta/ai", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
max_tokens: 512,
messages: [{ role: "user", content: "Summarise this page" }],
}),
});
const answer = await res.json();Visitors bring their own AI
On every plan, Free included. Choose Each visitor, with their own OpenRouter account and each visitor pays for their own calls: they connect their own OpenRouter account once, on this site only, with a spending limit they choose there. Your key is not used, and nobody pastes a key anywhere.
There is nothing to install. Every page of the site has window.solta.ai:
const answer = await solta.ai.chat({
messages: [{ role: "user", content: "Summarise this page" }],
});The model is the tier you chose, in OpenRouter's naming, such as anthropic/claude-sonnet-5.5. solta.ai.request() gives back OpenRouter's whole response, in OpenAI's chat-completions shape; solta.ai.status() says whether this visitor is connected, and solta.ai.disconnect() forgets them.
The key OpenRouter creates is kept here, encrypted, and never reaches the page. It works on your site only, and is deleted when the visitor disconnects, after 90 days unused, or when you choose anything other than visitors. Connecting needs the site in its own tab, so inside the Viewer or an embed the visitor is offered one; on a Private site, which only its own people open through Solta, use your own key instead.
What visitors see
The first time the site needs their AI, a visitor who hasn't connected sees this, and the call goes through once they have:
Use your own AI
This site uses AI that you pay for yourself, through OpenRouter. Connect once: you set a spending limit there, and you can disconnect at any time.
Not now · Connect with OpenRouter
Your key is kept encrypted by Solta, never in this page, and deleted after 90 days unused.
Once connected, a small “AI: connected · Disconnect” chip sits in a corner of the page, so they can always see that the site spends their credit and stop it. They can hide it for the rest of the visit. Your site's settings show the same words.
What this does not do
It cannot tell one visitor from another for certain. Anyone who can open your site can make it call the model, and with your key that is spending your money. There is no way around it while the site is public: a secret shipped to the public is not a secret. The tier, the cap, the limit for each visitor and the provider's own limit are what keep it to what you meant; the alternative is asking every visitor to bring their own AI.
Changing the site by asking
When your key pays, the site gets a Chat tab beside Comments and Versions. Ask for a change and the whole file comes back; a button saves it as a new version.
Nothing is saved until you press that button, and saving a version changes nothing anyone can see — the link keeps serving what it served before, until you publish. A model finishing is not a reason for your link to move.
It spends the same key, tier and cap as the site does, because it is the same key. And it only works on a site that is one file: a folder has no single thing to iterate on, and handing a model one file out of forty is worse than refusing.

