<!--
Sitemap:
- [Paybox](/index): The non-custodial wallet for AI agents
- [Getting started](/getting-started)
- [Credentials & agents](/concepts/model): The Paybox model
- [Approvals & passkeys](/concepts/approvals)
- [Request lifecycle](/concepts/requests): From intent to result
- [MCP connector](/connect/mcp)
- [OAuth 2.1](/connect/oauth)
- [MCP tools](/reference/mcp-tools): What an agent can call
- [API & endpoints](/api-reference)
- [SDK & CLI](/sdk-cli)
-->

# SDK & CLI

`@paybox-sh/sdk` is a typed Node SDK and `paybox` CLI for the Paybox agent API.
It wraps the core MCP tool surface — `list_credentials`, `request_payment`,
`claim_payment_credentials`, `request_wallet_sign`, `request_secret`,
`request_swap`, `get_portfolio`, `verify_solana_balance`, `get_buy_link`,
`request_account_change`, the x402 tools (`discover_services`, `pay_x402`,
`use_service`), `get_request`, and
REST-supported read-only [plugin tools](/reference/mcp-tools#plugin-tools) — but
talks to the REST API directly, with no MCP host and **no signing iframe**.
Wallet signing is non-custodial and runs in-process: the SDK reuses the
wallet-sign signing core and signs the MoonX envelope with your `pbxk1.` key;
the MoonX secret never reaches the client.

:::note
A few surfaces are **MCP-only today**: geofenced World money tools; request history
([`list_requests`](/reference/mcp-tools#list_requests)) has no SDK method or CLI
command, and the wrappers don't expose the advanced x402 options (the v2
`x402_version` + `resource` fields on `pay_x402`; custom `headers` and probe
mode on `use_service`). Use the [MCP connector](/connect/mcp) for those.
:::

The request/response types are generated from the server's MCP `list_tools`
schemas, so the SDK stays in sync with the API rather than being hand-maintained.

## Install

```bash
pnpm add @paybox-sh/sdk      # library
npx @paybox-sh/sdk login     # or use the CLI directly
```

## Library

```ts
import { PayboxClient } from "@paybox-sh/sdk";

// Reads ~/.config/paybox + env (PAYBOX_API_KEY / PAYBOX_API_URL), or pass
// { apiKey, signingKey } / { token } explicitly.
const paybox = PayboxClient.fromConfig();

const { credentials, ungranted_summary } = await paybox.listCredentials();
const pay = await paybox.requestPayment({
  credentialId: credentials[0].credential.id,
  merchant: "Acme",
  merchantUrl: "https://acme.com",
  amountCents: 1999,
});

// Count-only hints; no ungranted credential IDs, names, addresses, or metadata.
console.log(ungranted_summary.wallet.evm);

const signed = await paybox.requestWalletSign({
  credentialId: walletId,
  intent: { op: "message", message: "gm" },
}); // signs in-process when a pbxk1. signing key is configured

const verified = await paybox.verifySolanaBalance({
  address: "5EUa…SViS",
  tokenMint: "EPjF…Dt1v",
  transactionSignature: "5h6x…q2Ms",
});
console.log(verified.balance.ui_amount_string);

// Approval-mode operations can wait for the user's passkey approval and then
// sign in-process — the headless equivalent of the in-chat signing window.
const swap = await paybox.requestSwap(
  {
    credentialId: walletId,
    srcChain: "eip155:8453",
    srcToken: "native",
    dstToken: "0x…",
    amount: "1000000000000000",
  },
  { waitForApproval: true },
);
```

## CLI

```bash
paybox login                              # OAuth 2.1 + PKCE, then provision a key
paybox login --no-provision               # OAuth only, skip the key step
paybox login --key pbx_live_…             # personal API key instead (no OAuth)
paybox login --signing-key pbxk1.…        # supply the signing key non-interactively

paybox credentials                        # list usable credentials
paybox pay --credential <id> --merchant Acme --url https://acme.com --amount 1999
paybox claim <request_id>                 # claim an approved payment's one-time card
paybox secret --credential <id> --purpose "deploy"
paybox sign --credential <id> --intent '{"op":"message","message":"gm"}'
paybox swap --credential <id> --src-chain eip155:8453 --src-token native --dst-token 0x… --amount 1000000000000000
paybox portfolio --address 0x… --networks 1,8453
paybox verify-solana-balance --address 5EUa…SViS --mint EPjF…Dt1v --transaction 5h6x…q2Ms
paybox buy-link --credential <id> --amount-usd 50   # MoonPay checkout URL to fund a wallet

paybox discover "weather api"             # browse curated paid x402 services
paybox pay-x402 --credential <id> --url https://svc/api --accepts @accepts.json
paybox use-service --credential <id> --url https://svc/api   # paybox pays + fetches

paybox account-change --note "need a wallet grant"  # link for the user to update access
paybox request <request_id> --wait        # poll a pending request

paybox version                            # installed version (+ update check)
paybox update                             # update the global install to latest
paybox uninstall                          # clear stored config (prints npm rm)

paybox --json credentials                 # machine-readable output on any command
```

REST-supported read-only plugin tools get their own command groups (run
`paybox --help` to see them, and `paybox <plugin> --help` for the subcommands);
if the plugin isn't enabled, the command errors with the plugin to enable.

### Logging in

`paybox login` is a guided two-step:

1. **Authenticate** — opens your browser for the OAuth 2.1 + PKCE flow; you sign
   in and approve with a passkey. A scoped, audience-bound token (and a refresh
   token) is saved to `~/.config/paybox/config.json` (mode `0600`).
2. **Provision a signing key** — to sign or swap, the CLI then opens the Paybox
   app's signing-key page for this agent, where a `pbxk1.` key is minted scoped
   to the wallets you granted. Paste it back at the prompt and it's stored
   locally. The key never leaves your machine except to MoonX; Paybox never sees
   it. Pass `--no-provision` to skip, or `--signing-key <pbxk1.…>` to supply it
   directly.

### Signing and approvals

`sign`, `swap`, `pay-x402`, and `use-service` complete in-process when a
`pbxk1.` signing key is configured (`paybox whoami` shows `canSign`) and the
operation clears immediately under an autonomous grant. Without a key those
commands stop at `pending_signature`.

When a grant requires approval, pass `--wait`: the command waits for your
passkey approval in the app and then signs in-process — there is no signing
window on this surface. Without `--wait` it returns `pending_approval`; approve
in the app, then poll `paybox request <id>`. Solana swaps are safe to approve at
your own pace — the SDK refreshes the transaction's recent blockhash right
before signing, so a swap that waited on approval doesn't expire.

You can also integrate over the **[API reference](/api-reference)** directly, or
connect an agent via the **[MCP connector](/connect/mcp)**.
