npm run docs writes this file from the code in src/. Do not edit it by hand. On the
docs site the names in braces link to the code reference.
Each command, the subcommands and flags its branch of run reads, whether it needs a Phantom AI key, and the Phantom AI calls it can make (see HTTP calls). Every command also takes the flags in the Flags section of the help text.
| Command | Subcommands | Flags | Needs a key | Phantom AI calls |
|---|---|---|---|---|
balance |
yes | GET /key/balance |
||
burn |
--key-name |
yes | DELETE /key |
|
buy |
--amount, --card, --coin, --new, --save, --wait |
only without --card |
GET /key/balance, POST /purchase/solana, POST /purchase/card, GET /purchase/{paymentId}/status |
|
claude |
--key, --limit, --mpp, --network, --no-browser |
no | POST /chat/completions, GET /key/balance, POST /auth/device, POST /auth/device/token |
|
codex |
--key, --limit, --mpp, --network, --no-browser |
no | POST /chat/completions, GET /key/balance, POST /auth/device, POST /auth/device/token |
|
key |
list, rm, save, show |
--balance |
no | GET /key/balance |
keys |
rm, save, saved, show |
--amount, --balance, --budget, --card, --clear-policy, --coin, --file, --id, --limit, --mpp, --name, --no-browser, --pay, --period, --policy-file, --rate, --sandbox, --save, --x402 |
no | GET /key/balance, GET /workspaces/{workspace_id}, POST /workspaces/{workspace_id}/keys or /workspaces/{workspace_id}/keys/{id}, DELETE /workspaces/{workspace_id}/keys/{id}, PATCH /workspaces/{workspace_id}/keys/{id}, DELETE /workspaces/{workspace_id}/access/{id}, GET /workspaces/{workspace_id}/payments/{id}, POST /purchase/x402, POST /workspaces/{workspace_id}/fund |
login |
--network, --no-browser, --paste, --save, --wallet |
no | GET /key/balance, POST /auth/device, POST /auth/device/token |
|
logout |
no | |||
mcp |
per tool | GET /key/balance, GET /key/route, PUT /key/route, PATCH /key/route, DELETE /key/route, POST /key/route/test, POST /purchase/solana, POST /purchase/card, GET /purchase/{paymentId}/status, DELETE /key, GET /receipts/key, POST /chat/completions |
||
payment |
--wait |
yes | GET /purchase/{paymentId}/status |
|
pi |
--key, --limit, --mpp, --network, --no-browser |
no | POST /chat/completions, GET /key/balance, POST /auth/device, POST /auth/device/token |
|
rotate |
yes | POST /key/rotate |
||
route |
add, clear, get, rm, rule, set, test |
--applies-to, --at, --fallback, --file, --if, --model, --models, --on-empty, --stick-by-prompt, --stick-minutes, --use |
yes | GET /key/route, PUT /key/route, PATCH /key/route, DELETE /key/route, POST /key/route/test |
setup |
--agent, --dry-run, --mcp, --model, --provider, --restore, --yes |
no | ||
verify |
--model, --receipt |
only without --receipt |
GET /receipts/key, POST /chat/completions |
|
workspace |
rm, save, saved, show |
--amount, --balance, --budget, --card, --clear-policy, --coin, --file, --id, --limit, --mpp, --name, --no-browser, --pay, --period, --policy-file, --rate, --sandbox, --save, --x402 |
no | GET /key/balance, GET /workspaces/{workspace_id}, POST /workspaces/{workspace_id}/keys or /workspaces/{workspace_id}/keys/{id}, DELETE /workspaces/{workspace_id}/keys/{id}, PATCH /workspaces/{workspace_id}/keys/{id}, DELETE /workspaces/{workspace_id}/access/{id}, GET /workspaces/{workspace_id}/payments/{id}, POST /purchase/x402, POST /workspaces/{workspace_id}/fund |
The output of pai --help --all:
pai — AI inference for your coding agents
Commands:
login [--save <name>] [--no-browser] connect an account or guest workspace by device code
login --wallet [--network tempo|tempo-testnet] connect an optional Tempo wallet
login --paste validate and save an existing key
login [key] save your key so you don't need PHANTOM_API_KEY
(use --paste to prompt for an existing key)
workspace [status] shared balance, keys, recent usage and management access
workspace fund --amount <USD> [--card | --coin usdc|usdt|sol] [--no-browser]
workspace fund --amount <USD> --pay [--mpp | --x402] [--sandbox]
pay with the native pay.sh wallet; save purchase before paying
workspace payment --id <payment-id> check verified funding status
workspace export --file <path> export private guest recovery; refuses overwrites
workspace import --file <path> restore a guest, then issue replacement keys
workspace revoke-access --id <id> revoke a browser, device or recovery credential
keys [list] remote workspace key metadata, never secrets
keys create [--save <name>] [--limit <USD>]
keys set --id <id> [--limit <USD|none>] [--budget <USD|none>]
[--period <days|none>] [--rate <USD|none>] [--name <name>]
[--policy-file <path> | --clear-policy]
keys rotate --id <id> [--save <name>] replace only the corresponding saved key
keys revoke --id <id> revoke access, keeping workspace credit
keys saved [--balance] local saved key metadata
keys save <name> [key] validate and save an existing key (prompts if omitted)
keys show [name] print a secret for shell integration only
keys rm <name> forget a local copy; remote key keeps working
claude [--key <name>] [--mpp --limit <USD> --network tempo|tempo-testnet --no-browser] -- <agent arguments>
codex [--key <name>] [--mpp --limit <USD> --network tempo|tempo-testnet --no-browser] -- <agent arguments>
pi [--key <name>] [--mpp --limit <USD> --network tempo|tempo-testnet --no-browser] -- <agent arguments>
run with a saved key; --mpp opts into wallet payments
balance show credit balance and expiry
key list [--balance] saved keys, by name and id
key save <name> [key] save a key by name (prompts if no key is given)
key show [name] print a saved key, for PHANTOM_API_KEY=$(...);
no name prints the key pai is using
key rm <name> forget a saved key (the key keeps working)
route [get] show which model "auto" runs, and why
route set --models a,b,c models for "auto", first is the default
[--applies-to auto|all] [--on-empty stop|cheapest] [--fallback]
[--stick-minutes n] keep a conversation's model this long (default 5)
[--stick-by-prompt false] only x-phantom-session marks a conversation
route set --file policy.json replace the whole policy
route rule add --if <name=value> --use <model|cheapest|first|next> [--at n]
conditions: pace, budget_left_pct_below,
days_left_below, has_tools, input_tokens_over,
reasoning_requested
route rule rm <n> remove rule n
route test [--model auto] which model a request would get now (free)
route clear remove the policy
buy --amount <usd> buy credit for this key with crypto
[--coin <code>] usdc (default), usdt or sol, paid straight to
Phantom AI on Solana
[--wait] wait until the credit lands
buy --amount <usd> --card buy credit for this key by card ($5 minimum; the
card pays the amount plus 5% plus $0.30): opens
Stripe's page in the browser and waits until paid
[--new] buy a new key instead (the default with no key set)
[--save <name>] save the new key by name (default: as the login key)
payment <id> [--wait] check a payment started with buy
rotate issue a new key, retire this one
burn [--key-name <name>] revoke this key (or a saved one) and forget the
saved copy
logout forget workspace access and the default saved key
setup set up every agent found: install the skill and
point its model calls at Phantom AI; shows each
file's changes and asks first
[--yes] don't ask
[--dry-run] show the changes, write nothing
[--model <id>] the model each agent starts on (default phantom-1)
setup --agent <name> [--mcp] install the skill for one agent, without asking:
pi, codex, claude, cursor, opencode, continue, goose, aider, copilot or cline
or all; --mcp also adds the MCP server
setup [--agent <name>] --provider point that agent's model calls at Phantom AI;
--provider off removes only what pai wrote
setup --restore [--agent <name>] put back the files setup changed, from the
.pai.bak copies it kept
verify --model <id> make one tiny call and check its signed receipt
names the model you asked for (costs a fraction of a cent)
verify --receipt <receipt> check a receipt you already have
mcp run as an MCP server over stdio
Flags:
--table human-readable output instead of JSON
--help, -h print help and run nothing
--all include advanced commands in help
--version, -v print the version
Environment:
PHANTOM_API_KEY your Phantom AI API key (or save one with login)
PHANTOM_KEY_NAME run as a key saved with keys save; wins over PHANTOM_API_KEY
PHANTOM_BASE_URL API base, https:// only (default https://phantom.codes/v1)
PHANTOM_STATE_DIR where pai keeps keys (default ~/.config/phantom-key)
PAI_KEYCHAIN 0 saves keys to files instead of the macOS Keychain; 1 uses the Keychain on any system, which fails where /usr/bin/security is missing
TEMPO_PRIVATE_KEY optional server wallet for explicit Tempo MPP commands
pai mcp serves these tools over stdio ( createMcpServer).
get_balanceCredit left, credit spent, and expiry of the configured key.
Read-only. Runs as the configured key. Phantom AI calls: GET /key/balance.
No input.
list_saved_keysKeys saved on this machine by name (with key save), with the id for each. Never returns the keys.
Read-only. Needs no API key. Makes no Phantom AI call.
No input.
delete_keyRevoke an API key and forget any saved copy.
Writes. Destructive. Runs as the configured key. Phantom AI calls: DELETE /key.
| Field | Type | Required | Limits | Description |
|---|---|---|---|---|
api_key |
string |
optional | matches ^sk-phantom-.* |
API key to revoke |
key_name |
string |
optional | Name of a saved key, instead of api_key. Its saved copy is removed too |
verify_modelCheck which model answers for a model id. Makes one tiny call (a fraction of a cent) with the configured key, checks the signed receipt against Phantom AI's published key, and reports the model served, whether it matches, and the cost.
Writes. Not destructive. Runs as the configured key. Phantom AI calls: GET /receipts/key, POST /chat/completions.
| Field | Type | Required | Limits | Description |
|---|---|---|---|---|
model |
string |
required | at least 1 character | Model id to check, for example deepseek/deepseek-v3.2 |
verify_receiptCheck a receipt from the x-phantom-receipt header or the phantom.receipt stream event against Phantom AI's published key. Returns whether the signature is valid and what the receipt says was served. Needs no API key.
Read-only. Needs no API key. Phantom AI calls: GET /receipts/key.
| Field | Type | Required | Limits | Description |
|---|---|---|---|---|
receipt |
string |
required | at least 1 character | The compact receipt: payload.signature |
get_routeThe configured key's route policy: which models model "auto" can run and the rules that pick one.
Read-only. Runs as the configured key. Phantom AI calls: GET /key/route.
No input.
set_routeReplace (or with merge: true, change some fields of) the route policy. Rules run in order and the first match wins; with no match "auto" runs models[0]. Conditions: pace (on_pace|ahead), budget_left_pct_below, days_left_below, has_tools, input_tokens_over, reasoning_requested. use: a model from models, or cheapest, first, next. Pass policy null to remove it.
Writes. Not destructive. Runs as the configured key. Phantom AI calls: PUT /key/route, PATCH /key/route, DELETE /key/route.
| Field | Type | Required | Limits | Description |
|---|---|---|---|---|
policy |
object | null |
required | The policy, for example {"models":["a","b"],"rules":[{"if":{"pace":"ahead"},"use":"cheapest"}]} | |
policy.models |
string[] |
optional | ||
policy.applies_to |
"auto" | "all" |
optional | ||
policy.rules |
object[] |
optional | ||
policy.rules[].if |
Record<string, string | number | boolean> |
required | ||
policy.rules[].use |
string |
required | ||
policy.on_empty |
"stop" | "cheapest" |
optional | ||
policy.fallback_on_error |
boolean |
optional | ||
policy.stick_minutes |
integer |
optional | whole number, at least 0, at most 1440 | |
policy.stick_by_prompt |
boolean |
optional | ||
merge |
boolean |
optional | Change only the fields given and keep the rest |
test_routeWhich model a request would run right now, and the rule that picked it. Free: nothing is called or charged.
Read-only. Runs as the configured key. Phantom AI calls: POST /key/route/test.
| Field | Type | Required | Limits | Description |
|---|---|---|---|---|
model |
string |
optional | Model to ask for. Default "auto" |
buy_creditStart a crypto payment that adds credit to the configured key. Returns the address and exact amount to send, and a payment_id for check_payment. USDC, USDT or SOL, paid straight to Phantom AI on Solana, with a Solana Pay link that carries the reference the payment is found by. Nothing is charged until someone sends the coins.
Writes. Not destructive. Runs as the configured key. Phantom AI calls: POST /purchase/solana.
| Field | Type | Required | Limits | Description |
|---|---|---|---|---|
amount_usd |
number |
required | over 0 | Amount to buy in USD |
coin |
"usdc" | "usdt" | "sol" | "usdcsol" | "usdtsol" |
optional | usdc (default), usdt or sol, on Solana |
buy_credit_cardStart a card payment that adds credit to the configured key. Returns a Stripe checkout link for the user to open and pay in their own browser, the card total, and a payment_id for check_payment. The card pays the amount plus 5% plus $0.30, and the amount must be at least $5. Nothing is charged until the user pays on the page. Give the user the link; don't open or fill in the page for them.
Writes. Not destructive. Runs as the configured key. Phantom AI calls: POST /purchase/card.
| Field | Type | Required | Limits | Description |
|---|---|---|---|---|
amount_usd |
number |
required | over 0 | Amount of credit to buy in USD, at least 5 |
check_paymentStatus of a payment started with buy_credit or buy_credit_card. topped_up is true once the credit is on the key.
Read-only. Runs as the configured key. Phantom AI calls: GET /purchase/{paymentId}/status.
| Field | Type | Required | Limits | Description |
|---|---|---|---|---|
payment_id |
string |
required | at least 1 character | The payment_id returned by buy_credit or buy_credit_card |
Every call goes to PHANTOM_BASE_URL (default DEFAULT_BASE_URL, https://phantom.codes/v1), which must be https ( httpsOnly).
A failed call becomes a PhantomApiError. <apiKey> is the key the command runs as, except
DELETE /key, which sends the key being deleted.
| Method | Path | Made by | Body fields | Headers sent | Headers read | Response |
|---|---|---|---|---|---|---|
POST |
/auth/device |
run | client_name: string |
Authorization: Bearer <apiKey>, Content-Type: application/json |
{ device_code: string; user_code: string; verification_uri_complete: string; interval: number; expires_in: number } |
|
POST |
/auth/device/token |
run | device_code: string |
Authorization: Bearer <apiKey>, Content-Type: application/json |
||
POST |
/chat/completions |
verifyModel | model: stringmax_tokens: numbermessages: { role: string; content: string; }[] |
Authorization: Bearer <apiKey>, Content-Type: application/json |
x-phantom-receipt |
|
POST |
/chat/completions |
payFetch, run | stream: boolean |
content-type: application/json |
||
DELETE |
/key |
burnKey | Authorization: Bearer <apiKey> |
BurnResult | ||
GET |
/key/balance |
getBalance | Authorization: Bearer <apiKey> |
BalanceResult | ||
GET |
/key/balance |
run | Authorization: Bearer <apiKey> |
{ credit_spent_usd: number; credit_balance_usd: number } |
||
POST |
/key/rotate |
rotateKey | Authorization: Bearer <apiKey> |
RotateResult | ||
DELETE |
/key/route |
clearRoute | Authorization: Bearer <apiKey> |
RouteResult | ||
GET |
/key/route |
getRoute | Authorization: Bearer <apiKey> |
RouteResult | ||
PATCH |
/key/route |
patchRoute | models?: string[]applies_to?: "auto" | "all"rules?: RouteRule[]on_empty?: "stop" | "cheapest"fallback_on_error?: booleanstick_minutes?: numberstick_by_prompt?: boolean |
Authorization: Bearer <apiKey>, Content-Type: application/json |
RouteResult | |
PUT |
/key/route |
putRoute | models: string[]applies_to?: "auto" | "all"rules?: RouteRule[]on_empty?: "stop" | "cheapest"fallback_on_error?: booleanstick_minutes?: numberstick_by_prompt?: boolean |
Authorization: Bearer <apiKey>, Content-Type: application/json |
RouteResult | |
POST |
/key/route/test |
testRoute | model: stringmessages?: unknowntools?: unknown |
Authorization: Bearer <apiKey>, Content-Type: application/json |
RouteTestResult | |
GET |
/purchase/{paymentId}/status |
getPaymentStatus | Authorization: Bearer <apiKey>, x-phantom-recovery-code: <recoveryCode> (when recoveryCode is given) |
PaymentStatusResult | ||
POST |
/purchase/card |
requestCardPayment | target_api_key?: stringamount_usd: numberhosted: boolean |
Authorization: Bearer <apiKey>, Content-Type: application/json |
CardPaymentRequest | |
POST |
/purchase/solana |
requestSolanaPayment | target_api_key: stringamount_usd: numbercoin: BuyCoin |
Authorization: Bearer <apiKey>, Content-Type: application/json |
SolanaPaymentRequest | |
POST |
/purchase/x402 |
run | amount_usd: numberworkspace_id: string |
Authorization: Bearer <apiKey>, Content-Type: application/json |
{ payment_id: string; payment_url: string; expires_at: string; credit_usd: number } |
|
GET |
/receipts/key |
checkReceipt | signs?: booleanpublic_key_jwk?: JsonWebKey |
|||
GET |
/workspaces/{workspace_id} |
run | Authorization: Bearer <apiKey> |
|||
GET |
/workspaces/{workspace_id} |
run | Authorization: Bearer <apiKey> |
{ balance_usd: number; keys: unknown[] } |
||
DELETE |
/workspaces/{workspace_id}/access/{id} |
run | Authorization: Bearer <apiKey> |
|||
POST |
/workspaces/{workspace_id}/fund |
run | method: stringamount_usd: numbercoin: string | true |
Authorization: Bearer <apiKey>, Content-Type: application/json |
{ checkout_url?: string; solana_pay_url?: string } |
|
POST |
/workspaces/{workspace_id}/keys or /workspaces/{workspace_id}/keys/{id} |
run | name: stringlimit_usd: number | null |
Authorization: Bearer <apiKey>, Content-Type: application/json |
{ api_key: string } |
|
DELETE |
/workspaces/{workspace_id}/keys/{id} |
run | Authorization: Bearer <apiKey> |
|||
PATCH |
/workspaces/{workspace_id}/keys/{id} |
run | Record<string, unknown> |
Authorization: Bearer <apiKey>, Content-Type: application/json |
||
GET |
/workspaces/{workspace_id}/payments/{id} |
run | Authorization: Bearer <apiKey> |
| Goes to | What | Made by |
|---|---|---|
| Tempo Wallet device authorization | through accounts/cli |
payFetch, run |
| MPP payment retry | through mppx/client |
payFetch, run |
| Tempo MPP payments | through mppx/tempo |
payFetch, run |
| Tempo JSON-RPC | through viem |
payFetch, run |
| Tempo JSON-RPC actions | through viem/actions |
payFetch, run |
| Tempo JSON-RPC actions | through viem/tempo |
payFetch, run |
Secret: holds a secret, so keep it out of files, logs and the model's context. Environment only: no flag or tool argument can set it. Cap: limits what an agent can spend. The list is ENV_VARS.
| Variable | Meaning | Secret | Environment only | Cap |
|---|---|---|---|---|
PHANTOM_API_KEY |
your Phantom AI API key (or save one with login) | yes | ||
PHANTOM_KEY_NAME |
run as a key saved with keys save; wins over PHANTOM_API_KEY | |||
PHANTOM_BASE_URL |
API base, https:// only (default https://phantom.codes/v1) | |||
PHANTOM_STATE_DIR |
where pai keeps keys (default ~/.config/phantom-key) | |||
PAI_KEYCHAIN |
0 saves keys to files instead of the macOS Keychain; 1 uses the Keychain on any system, which fails where /usr/bin/security is missing | |||
TEMPO_PRIVATE_KEY |
optional server wallet for explicit Tempo MPP commands | yes |
pai also reads these, which are not its own settings:
| Variable | Why pai reads it |
|---|---|
HOME |
Home folder. setup looks here for agents to set up and for their settings files (default: the system home folder) |
ANTHROPIC_AUTH_TOKEN |
setup warns when it is set, because Claude Code would send it instead of the Phantom AI key |
SHELL |
Which shell startup file setup adds its key block to: ~/.zshrc, ~/.bash_profile on macOS and ~/.bashrc elsewhere, fish's config.fish, or ~/.profile for any other shell |
ZDOTDIR |
Where zsh keeps .zshrc, for the same block (default: the home folder) |
XDG_CONFIG_HOME |
Where setup looks for fish's config.fish, opencode and Goose (default: ~/.config) |
CODEX_HOME |
Where Codex keeps config.toml, which setup edits (default: ~/.codex) |
CLAUDE_CONFIG_DIR |
Where Claude Code keeps settings.json, which setup edits (default: ~/.claude) |
COPILOT_HOME |
The folder that tells setup GitHub Copilot CLI is installed (default: ~/.copilot) |
pai sets these for other programs:
| Variable | Where |
|---|---|
PAI_AGENT_TOKEN |
Ephemeral proxy credential passed only to the launched agent |
ANTHROPIC_BASE_URL |
Written to the env block of ~/.claude/settings.json by setup for Claude Code, as Phantom AI's Claude Code address (https://phantom.codes/claude-code); removed by --provider off |
ENABLE_TOOL_SEARCH |
Written as true to the same env block, for the same command |
ANTHROPIC_API_KEY |
Written as an empty string to the same env block, so a key in the shell can't win over the Phantom AI key |
CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY |
Written as 1 to the same env block, so Claude Code's /model list shows Phantom AI's models |
ANTHROPIC_MODEL |
Written to the same env block when --model is given |
GOOSE_PROVIDER |
Written as custom_phantom to Goose's config.yaml by setup |
GOOSE_MODEL |
Written to the same file: --model, or phantom-1 |
AIDER_OPENAI_API_KEY |
Set to $PHANTOM_API_KEY in the shell block setup writes for Aider |
COPILOT_PROVIDER_BASE_URL |
Set in the shell block setup writes for GitHub Copilot CLI: Phantom AI's address for coding agents |
COPILOT_PROVIDER_API_KEY |
Set in the same block to $PHANTOM_API_KEY |
COPILOT_MODEL |
Set in the same block: --model, or phantom-1 |