Contents
Pi takes any OpenAI-compatible API as a custom provider: add one entry to ~/.pi/agent/models.json with api set to openai-completions, baseUrl set to https://api.solcardinference.ai/v1, and our three model ids. Pi’s README calls it “a minimal, extensible agent harness”, and its file asks for more than a URL and a key: limits, prices and a few compatibility flags. This guide fills in each one. Using OpenCode instead? See Use SolCard Inference in OpenCode.
What you need
- A SolCard Inference API key. Make one on the dashboard’s API keys page. Keys start with
sk-si-and are shown once. - Some balance or a plan. One prepaid USD balance pays for every key and model; see how billing works.
- Pi. Its README installs it with
npm install -g --ignore-scripts @earendil-works/pi-coding-agent.
Export the key in the shell you start Pi from:
export SOLCARD_INFERENCE_API_KEY=sk-si-...
The models.json entry
models.json lives in Pi’s agent directory, which Pi’s configuration docs say “defaults to ~/.pi/agent”. Set PI_CODING_AGENT_DIR to move it. Create or extend the file:
{
"$schema": "https://pi.dev/schemas/models.schema.json",
"providers": {
"solcard-inference": {
"name": "SolCard Inference",
"baseUrl": "https://api.solcardinference.ai/v1",
"api": "openai-completions",
"apiKey": "$SOLCARD_INFERENCE_API_KEY",
"compat": {
"supportsStore": false,
"supportsDeveloperRole": false
},
"models": [
{
"id": "solcard-inference-fast",
"name": "SolCard Inference Fast",
"contextWindow": 1048576,
"maxTokens": 32768,
"cost": { "input": 1.25, "output": 2.5, "cacheRead": 0.125, "cacheWrite": 0 }
},
{
"id": "solcard-inference-large",
"name": "SolCard Inference Large",
"contextWindow": 1000000,
"maxTokens": 32768,
"cost": { "input": 3.75, "output": 6.25, "cacheRead": 0.375, "cacheWrite": 0 }
},
{
"id": "solcard-inference-base",
"name": "SolCard Inference Base",
"contextWindow": 262144,
"maxTokens": 32768,
"cost": { "input": 1.25, "output": 3.75, "cacheRead": 0.125, "cacheWrite": 0 }
}
]
}
}
}
What each field does, per Pi’s models.json reference:
| Field | What it’s for |
|---|---|
$schema | Optional. Gives your editor validation and completion. |
solcard-inference | The provider id. Any id that isn’t a built-in provider adds a new one. |
baseUrl | The API endpoint. Ours ends in /v1; don’t add /chat/completions. |
api | Which request format Pi speaks. openai-completions is Chat Completions. |
apiKey | A literal key, $NAME to read an environment variable, or !command to use a command’s output. |
compat | Overrides for APIs that differ from OpenAI’s. |
id | Sent to the API as the model. Must match ours exactly. |
contextWindow | Context size in tokens, from our models page. |
maxTokens | Output tokens per request. |
cost | USD per 1M tokens, which Pi uses to estimate spend. |
Three fields matter more than they look:
maxTokens: Pi’s default is 16,384. Our models stop at 32,768 tokens per request, so setting it lets Pi use the whole cap.contextWindow: Pi assumes 128,000 when you leave it out, far less than Fast’s or Large’s real context.cost: Pi marks all four price fields as required. Our price list has no cache-write rate, socacheWriteis0. Pi’s total is its own estimate; what you’re charged follows how billing works.
The two compat flags
Pi’s docs say most compat flags are “auto-detected from URL”, and ours isn’t a URL Pi knows, so setting two of them yourself removes the guess.
supportsStore: falsekeeps Pi from sending OpenAI’sstorefield. Our errors page listsstore: trueas a400 unsupported_parameter.supportsDeveloperRole: falsemakes Pi send its system prompt with thesystemrole instead ofdeveloper.
Pi’s author ran into the same split across providers. In a November 2025 post on building Pi, the author lists APIs that “don’t like the store field” and others that “don’t support the developer role for system prompts”, which is why these switches exist.
We left reasoning at its default, false, on all three. Large always reasons on its own, per our models page, so this guide doesn’t turn on Pi’s thinking controls. Pi’s models docs say /thinking offers only the “levels supported by the selected model”.
Check it works
Pi reads the file again when you open the model picker, so there’s no restart. Its models docs say: “Opening /model reloads the file.” From a terminal, list what Pi sees:
pi --list-models solcard
You should see the three SolCard Inference models. Then send one prompt in print mode, which Pi’s CLI docs say writes “the final assistant text to stdout” and exits:
pi --model solcard-inference/solcard-inference-fast -p "Say hello in five words."
If nothing comes back, test the key and URL without Pi:
curl https://api.solcardinference.ai/v1/models \
-H "Authorization: Bearer $SOLCARD_INFERENCE_API_KEY"
Switching models
Start on Fast and press Ctrl+S on it in /model to make it the default for new sessions. Pi’s models docs also say “Ctrl+P cycles through available models”, and /scoped-models limits that cycle to the ones you pick, so a scope of Fast and Large gives you a one-key jump when a change needs planning. Large costs three times as much on input. Fast, Large or Base compares the three.
What a turn costs
Pi’s own prompt is small, so most of each turn is your conversation, resent at the cached rate. In November 2025, its author wrote that “pi’s system prompt and tool definitions together come in below 1000 tokens.” A turn on Fast that resends 60,000 tokens, 55,000 of them cached, and writes 1,000 tokens is about $0.016. The same turn on Large is about $0.046, before its reasoning tokens.
Troubleshooting
These are the API’s codes from our errors page; Pi may word them differently.
- Models missing from
/model: Pi’s docs say the picker “shows models whose providers have usable authentication.” Check the variable is exported in the shell that startedpi, and thatapiKeykeeps its leading$. - 401
invalid_api_key: the key is wrong, revoked or unset. - 400
model_not_found: aniddoesn’t match. Usesolcard-inference-fast,-largeor-base. - 400
unsupported_parameter: something Pi sent isn’t accepted. ChecksupportsStoreisfalse. - 400
unsupported_content: an image reached the model. Our models take text only, and Pi’sinputdefault is["text"], so don’t add"image". - 402
insufficient_balance: top up, then retry.
FAQ
Can I keep Pi’s built-in providers?
Yes. A new provider id adds a provider next to the others. Pick between them in /model.
Can I keep the key out of my environment?
Yes. Pi’s reference says apiKey accepts !command, and its models docs say such commands “run at request time and are not cached by Pi”, so a password manager’s read command works there.
Can I use the Anthropic Messages format instead?
Pi has an anthropic-messages type, and our API speaks Anthropic Messages too. Pi’s docs don’t say whether that type adds /v1 to baseUrl, so this guide sticks to openai-completions.
Are my prompts stored? Not on our side. Prompts and responses are never logged or stored; keeps nothing follows one request through.