pai
    Preparing search index...

    pai interface reference

    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).

    Credit left, credit spent, and expiry of the configured key.

    Read-only. Runs as the configured key. Phantom AI calls: GET /key/balance.

    No input.

    Keys 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.

    Revoke 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

    Check 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

    Check 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

    The 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.

    Replace (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

    Which 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"

    Start 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

    Start 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

    Status 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: string
    max_tokens: number
    messages: { 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?: boolean
    stick_minutes?: number
    stick_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?: boolean
    stick_minutes?: number
    stick_by_prompt?: boolean
    Authorization: Bearer <apiKey>, Content-Type: application/json RouteResult
    POST /key/route/test testRoute model: string
    messages?: unknown
    tools?: 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?: string
    amount_usd: number
    hosted: boolean
    Authorization: Bearer <apiKey>, Content-Type: application/json CardPaymentRequest
    POST /purchase/solana requestSolanaPayment target_api_key: string
    amount_usd: number
    coin: BuyCoin
    Authorization: Bearer <apiKey>, Content-Type: application/json SolanaPaymentRequest
    POST /purchase/x402 run amount_usd: number
    workspace_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?: boolean
    public_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: string
    amount_usd: number
    coin: 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: string
    limit_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