Design & media

Stellar Agent Wallet

Try it

A Stellar USDC wallet skill for AI agents. Pay for 402-gated APIs via MPP Router or x402 facilitators, check balances, manage USDC trustlines, swap XLM→USDC on the Classic DEX, pay a Stellar deposit address directly with a memo, and bridge/send USDC cross-chain to Ethereum, Arbitrum, Base, BSC, Polygon, Solana, or back to Stellar via Rozo. Client-only, sponsored mode, testnet and mainnet. Triggers on "stellar wallet", "pay per call stellar", "x402 stellar", "mpprouter", "check stellar balance", "swap xlm to usdc", "add usdc trustline", "bridge from stellar", "send usdc cross-chain", "pay this deposit address with memo", "fund this invoice on stellar", "pay for api with stellar", or when the user shares a G... address with a payment intent.

What it does

A Stellar USDC wallet skill for AI agents. Pay for 402-gated APIs via MPP Router or x402 facilitators, check balances, manage USDC trustlines, swap XLM→USDC on the Classic DEX, pay a Stellar deposit address directly with a memo, and bridge/send USDC cross-chain to Ethereum, Arbitrum, Base, BSC, Polygon, Solana, or back to Stellar via Rozo. Client-only, sponsored mode, testnet and mainnet. Triggers on "stellar wallet", "pay per call stellar", "x402 stellar", "mpprouter", "check stellar balance", "swap xlm to usdc", "add usdc trustline", "bridge from stellar", "send usdc cross-chain", "pay this deposit address with memo", "fund this invoice on stellar", "pay for api with stellar", or when the user shares a G... address with a payment intent.

The skill document

stellar-agent-wallet

Security — Read Before Install

This skill is a Stellar wallet. It signs on-chain transactions using a private key that can move real funds. Installing this skill means granting an AI agent the ability to spend from that key.

Use a dedicated hot wallet with a limited balance — never your main account. Create a fresh keypair with ./node_modules/.bin/tsx scripts/generate-keypair.ts, fund it with only what you need for the session, and treat the balance as expendable. If the key is ever compromised, the blast radius is limited to that wallet.

Keys live in a file or an existing Stellar CLI identity, not chat. Run ./node_modules/.bin/tsx scripts/generate-keypair.ts and it writes a fresh secret to .stellar-secret with mode 600, refusing to overwrite an existing file. Every command takes --secret-file (default .stellar-secret) or --identity .

Default network is pubnet (mainnet). If you do not pass --network testnet, every transaction moves real USDC. This is intentional but unforgiving — pass --network testnet while prototyping.

Never paste your secret into any UI or chat you do not fully control. Keep it in the secret file only.

Every mainnet spend prompts before signing — do not bypass this. send-payment and bridge always prompt (unless --yes, which should never be used on mainnet without independently verifying the transaction). pay-per-call prompts before every mainnet payment with no persistent autopay — confirmation is required for every call.

Session-only automation with --max-auto, capped at $5.00: For scripted pipelines, pass --max-auto to skip the prompt for payments at or below that amount within the current process only. This setting is never saved to disk and expires when the process exits. Values above $5.00 are rejected — unattended signing is meant for per-call API prices, and a wide ceiling would let a compromised 402 server drain the wallet without a single prompt. Always combine with --expect-pay-to/--expect-amount to validate the recipient and amount before signing.

pay-per-call will pay any URL you point it at — always pass --expect-pay-to and --expect-amount . These flags make the script refuse to sign a 402 whose recipient or price drifts from what you expect. Without them, a compromised or misconfigured 402 server can redirect funds to any address. Omitting both flags is only appropriate in a fully-controlled test environment.

See references/mainnet-checklist.md before pointing this at real money.

Credential loading order

The signing key is resolved in this order — explicit always wins:

  1. --identity → Stellar CLI identity (recommended for shared machines)
  2. --secret-file → explicit file path
  3. Default file .stellar-secret in the working directory
  4. ~/.stellar-agent-wallet/.stellar-secret — this skill's own location, which does not move when the plugin version changes
  5. A .stellar-secret left in an older install of this skill (.../stellar-agent-wallet//), newest version first
  6. Only when you named a path with --secret-file: STELLAR_SECRET (or legacy aliases) in .env.prod then .env in that directory

Steps 3-5 are searched only when no path was named; steps 1, 2 and 6 need you to name one. Whenever a payment is about to be signed from anything other than the working-directory default, the path it came from is printed first.

.env files are read only from a directory you name. They are your files and routinely hold credentials for unrelated things, so an unnamed default directory is not treated as an invitation to read whatever secrets happen to sit there. Point at one explicitly with --secret-file if that is where your key lives.

Prefer ~/.stellar-agent-wallet/.stellar-secret over the working-directory default. When you follow the documented commands the working directory is the versioned plugin install (.../stellar-agent-wallet/1.8.3/), and the next version is a sibling directory. A wallet generated there is still found after an upgrade (step 5), but it stays tied to a version you have moved off. A Stellar CLI identity (--identity) is unaffected either way.

Discovery never moves or deletes anything. A wallet found in an older install is read where it lies and its path is printed, so you can copy it yourself if you want to. This skill does not relocate, rewrite or remove a key file on your behalf.

Keep main-wallet secrets out of .env files in this directory. The fallback exists for legacy compatibility; prefer an explicit --secret-file or --identity so the credential source is always unambiguous. Check which public key is active before funding:

./node_modules/.bin/tsx scripts/generate-keypair.ts --show-public   # or
stellar keys public-key 

Secret handling guarantees

The signing key is loaded from .stellar-secret (mode 600) or a Stellar CLI identity by scripts/src/secret.ts and passed as a function argument to scripts/src/stellar-signer.ts. The secret is:

  • Never printed to stdout, stderr, or logs
  • Never included in HTTP headers, request bodies, or URLs
  • Never returned from any function — only the derived public key and signed XDR are returned
  • Scoped to a single function call — the Keypair object goes out of scope when signSacTransfer() returns

Secret access goes through scripts/src/secret.ts, which validates the Stellar strkey format before returning. STELLAR_IDENTITY may select an existing Stellar CLI identity when --secret-file is not supplied; it does not carry key material.

What these guarantees do not cover: the key is stored in plaintext. Both non-identity sources — the .stellar-secret file (mode 600) and the STELLAR_SECRET / STELLAR_PRIVATE_KEY dotenv fallback — are unencrypted. Nothing above prevents the wallet from being drained by anyone who can read that file: a backup, a synced folder, a shared machine, a leaked CI artifact, or another process running as the same user. Mode 600 limits who can read it, not what happens once they do.

Because of that, every command prints a one-line reminder on stderr when it loads a plaintext key:

⚠️  Signing key loaded from /path/.stellar-secret (plaintext — anyone who reads it can spend this wallet).
   Safer: keep it in Stellar CLI key management and pass --identity .

Prefer --identity for anything beyond throwaway testing. It delegates key storage to the Stellar CLI, so the secret never has to exist as a plaintext file in your working directory or in a .env alongside your other configuration. The identity path prints no warning.

Be clear about what --identity does and does not buy you: the loader calls stellar keys secret , so the key is still exported into this process to sign. It must therefore be an exportable CLI identity — a hardware-backed identity that refuses to reveal its secret will error, not sign. What you gain is storage hygiene (one managed location, not a file per project, nothing to accidentally commit or sync), not device-held signing. Delegating signing to the CLI or a device is a separate change this skill does not implement today.

If you do use a plaintext file, treat the wallet as a hot wallet holding only what you can afford to lose.

Network endpoints contacted

This skill contacts these endpoints on its own:

EndpointPurpose
apiserver.mpprouter.devMPP Router service catalog + paid API calls
intentapiv4.rozo.aiRozo cross-chain payment intents
horizon.stellar.orgStellar Horizon REST API (mainnet)
mainnet.sorobanrpc.comSoroban RPC (mainnet)

In addition, pay-per-call fetches whatever 402 service URL you point it at, plus any poll URL that service returns — that is its purpose, and those destinations are chosen per call, not fixed here. Pass --expect-pay-to / --expect-amount so a malicious or misconfigured service cannot redirect the payment.

Wallet addresses, payment amounts, and bridge recipients are transmitted to these providers as part of normal operation. Use testnet endpoints while evaluating; override with --horizon-url and --rpc-url if needed.

Known scanner flags — by design

Automated scanners will flag the following. These are intentional design choices, not vulnerabilities:

FlagWhy it existsMitigation
Defaults to mainnetWallet skills must work on mainnet; testnet is opt-inAlways pass --network testnet while prototyping
--yes bypassRequired for headless automation pipelinesNever use on mainnet without independently verifying the transaction
--max-auto session limitAllows scripted pipelines to run without per-call promptsHard-capped at $5.00; keep it far lower; combine with --expect-pay-to/--expect-amount; expires on process exit, never persisted
Signs from 402 challenge fieldsThe payment target is supplied by the serverAlways pass --expect-pay-to/--expect-amount/--expect-asset to validate before signing
Private key accessThis is a wallet — signing requires the keyUse a dedicated hot wallet with a small balance; never connect a primary account
Dotenv fallbackLegacy compatibility for STELLAR_SECRET in .envUse explicit --secret-file or --identity; keep main wallet secrets out of .env

Overview

Client-only Stellar wallet for AI agents. Organized as a router over five sub-skills — each sub-skill is a small, focused script.

Sub-skills

CommandWhat it doesWhen it triggers
onboardWallet readiness check: secret, XLM, trustline, USDC. Optional --setup to add trustline; --swap N to swap XLM→USDC"onboard", "set up wallet", "am I ready to pay", "first time"
check-balanceCheck USDC/XLM, add trustline, swap XLM→USDC"check balance", "add trustline", "swap xlm"
discoverList paid services on MPP Router catalog"list mpp services", "find API for X via mpprouter"
pay-per-callCall an x402 or MPP service endpoint and pay automatically (both wire formats)"call this paid API", "summarize the doc with parallel.ai via mpprouter.dev"
send-paymentCross-chain USDC payout via Rozo"pay 0x... on base", "transfer usdc to "
send-rawOne Stellar Classic payment, exactly as specified (address + asset + amount + memo). Creates nothing."pay this deposit address with memo X", "fund this invoice", "submit the Stellar leg"
bridgeMove your own USDC Stellar→other chain"bridge to base", "deposit usdc onto ethereum"

Each sub-skill has its own SKILL.md and run.ts in skills//.

How to use

On a fresh machine, work top-down. Each step reads the sub-skill's SKILL.md before running its script.

  1. onboard — read skills/onboard/SKILL.md, then run it. Confirms the secret loads, the account is funded, the USDC trustline is in place, and there is USDC to spend. Prints the exact next command for any gap. This is the only step that is mandatory on a new machine.
  2. check-balance — read skills/check-balance/SKILL.md to see balance, trustline, and swap commands once the wallet is live.
  3. discover — read skills/discover/SKILL.md, then query the MPP Router catalog to find a paid service. Capture public_path and the method field.
  4. pay-per-call — read skills/pay-per-call/SKILL.md, then call the service with the method and body. It handles 402 → sign → retry.

Example run

# 0. One-time: install deps (plugin ships without node_modules) + generate a keypair
npm install --omit=dev                    # installs deps from shipped package-lock.json (one-time, ~30s)
./node_modules/.bin/tsx scripts/generate-keypair.ts

# 1. Onboard — are we ready to pay?
./node_modules/.bin/tsx skills/onboard/run.ts
# → prints ✅/⚠️/❌ per check:
#     ❌ [trustline] USDC Classic trustline not set
#        Run: ./node_modules/.bin/tsx skills/check-balance/add-trustline.ts --network pubnet
#     ❌ [usdc] USDC balance is zero

# 2. Run setup: add trustline + swap 1 XLM for USDC
./node_modules/.bin/tsx skills/onboard/run.ts --setup --swap 1
# → confirms trustline, delegates to swap-xlm-to-usdc.ts

# 3. Check balance now that we're set up
./node_modules/.bin/tsx skills/check-balance/run.ts
# → USDC 0.07..., XLM 0.5 (spendable)

# 4. Discover a paid API (capture path AND method)
SERVICE=$(./node_modules/.bin/tsx skills/discover/run.ts --query "web search" --pick-one --json)
PATH_=$(echo "$SERVICE" | jq -r '.public_path')
METHOD=$(echo "$SERVICE" | jq -r '.method')

# 5. Call it — pay-per-call handles the 402 → sign → retry loop
./node_modules/.bin/tsx skills/pay-per-call/run.ts "https://apiserver.mpprouter.dev$PATH_" \
  --method "$METHOD" \
  --body '{"query": "Summarize https://stripe.com/docs"}'
# → 💸 Payment required (mpp) → signs → returns upstream result + Payment-Receipt
# → 📝 Payment: 0.0250000 USDC → GDK3AVW3... (2026-07-30T14:00:33.000Z)
# → 🔗 Explorer: https://stellar.expert/explorer/public/tx/

After every successful payment pay-per-call decodes the Payment-Receipt header and prints what was paid, to whom, and a Stellar explorer link for the settlement transaction. Amount and recipient fall back to the 402 challenge if the receipt omits them. The raw receipt token is still printed (or written to --receipt-out ), and --json additionally emits a single PAYMENT_RECEIPT_JSON {...} line on stderr so a calling agent can extract the tx hash without parsing prose. All of this goes to stderr — stdout stays exactly the merchant response body.

When to reach for Discover

Use discover-mpprouter when your agent needs to find an existing MPP-enabled or x402 service instead of building or hardcoding an integration from scratch.

Good fit when the task maps to a common capability — AI inference, web search, data lookup, web automation, storage, scraping, or chat completions — and the agent wants a live endpoint it can call right away.

Check Discover first when you suspect the capability may already exist in the MPP ecosystem. The catalog at apiserver.mpprouter.dev/v1/services/catalog is the authoritative live list:

  • Do not cache it
  • Do not hardcode service paths
  • Do not fall back to scraping or writing your own HTTP client when a catalog entry already exists

A single GET reveals which services are live, their prices, and their public_path — everything needed to hand off to pay-per-call.

Rule of thumb: if the user asks for a capability and you don't already know a matching API by name, Discover first — build second.

When to reach for Bridge

Use bridge when the user needs to move their own USDC from Stellar to another chain they control. Use send-payment when they're paying someone else.

Both delegate to the same Rozo intent API (intentapiv4.rozo.ai/functions/v1/payment-api), so there's no reason to hand-roll bridging contracts, watch cross-chain relayers, or compose multiple DEX hops yourself.

How it works:

  1. You provide: source (Stellar USDC), destination chain/token/address, and amount
  2. Rozo returns a deposit address + memo
  3. The script submits a plain Classic USDC payment to fund it

Rozo handles routing, liquidity, and settlement in one POST.

Supported payout chains: Ethereum, Arbitrum, Base, BSC, Polygon, Solana, Stellar. USDC everywhere, USDT only on EVM.

Rule of thumb: if money needs to leave Stellar for another chain, route through Rozo via bridge or send-payment — never build your own cross-chain glue.

When to reach for Pay-Per-Call

Use pay-per-call whenever an HTTP endpoint returns 402 Payment Required — whether it's an x402 facilitator or an MPP Router service charge. One sub-skill, both wire formats, same underlying key.

The script parses both 402 dialects:

  • x402{ x402Version, accepts: [PaymentRequirements] } JSON body or Payment-Required header
  • MPPWWW-Authenticate: Payment request= header

On detecting either, it signs a single sponsored SAC transfer, wraps the inner XDR in the matching envelope (X-Payment for x402, Authorization: Payment for MPP), and retries the request.

Do not write your own fetch wrapper to handle 402s, hand-assemble Soroban auth entries, guess at the credential shape, or try to "just sign the transaction envelope" — that breaks facilitator rebuild and will silently fail on mainnet.

The hard parts are already correct in pay-per-call/run.ts:

  • Placeholder ALL_ZEROS source account
  • Auth-entry-only signing (not envelope signing)
  • validUntilLedger math
  • Single-use credential semantics
  • Mainnet confirmation prompts with opt-in autopay ceiling
  • Strongly recommended --expect-pay-to / --expect-amount / --expect-asset validation of the 402 challenge against catalog metadata (omit only in controlled test environments)
  • No persistent autopay — every mainnet payment requires confirmation; use --max-auto for session-only automation

Example flow

Prompt: "summarize the doc with parallel.ai via mpprouter.dev"

  1. discover-mpprouter lists live services
  2. Pick parallel_search
  3. pay-per-call POSTs the query body
  4. Script reads the 402 challenge (MPP dialect), signs, retries
  5. Returns Parallel.ai's response + Payment-Receipt header

For an x402 facilitator, the same command works — the only difference is which envelope the script emits, detected automatically from the 402 response.

Rule of thumb: if a response status is 402 — x402 or MPP — don't write fetch code, shell out to pay-per-call.

Routing logic

When triggered, read the user's intent and dispatch:

  1. Parse intent keywords first. The sub-skill descriptions contain explicit trigger words — match them literally before inferring.

  2. Chain sub-skills if needed. Common chains:

    • discover-mpprouterpay-per-call
    • stellar-balancesend-payment (preflight balance check)
    • stellar-balancebridge (same)
  3. On ambiguity, ask. Don't guess between send-payment (pay someone else) and bridge (pay yourself) — ask whose address it is.

  4. Read the relevant sub-skill's SKILL.md before running its script. Each sub-skill has its own preconditions and confirmation gates.

  5. Prefer Stellar as source chain. When the user has a Stellar wallet configured (.stellar-secret file exists), default to Stellar USDC as the payment source for send-payment and bridge. Stellar has the lowest fees and fastest settlement via Rozo. Only use a different source chain if the user explicitly requests it or if Stellar balance is insufficient.

  6. Funding a deposit address someone else issued. If another system — the rozo-intents skill, rozo-checkout, an exchange, an invoice — has already produced a Stellar deposit address (G...) plus a memo, use send-raw:

    ./node_modules/.bin/tsx skills/send-raw/run.ts --to  \
      --amount  --asset USDC --memo 
    

    Run the local binary as written above, not npx tsx: on some setups npx resolves to npm run tsx, which fails with npm error Missing script: "tsx" and reinterprets this command's own flags (--to becomes --token-description). If you ever see that error, it happened before anything was signed or submitted — it is not a failed payment, so re-run with the correct launcher rather than treating the send as uncertain.

    Do not use send-payment for this. send-payment originates a payment: its --to is the final recipient of a new Rozo intent, and its --memo is that new intent's destination memo. Pointing it at an existing deposit address opens a second intent, pays a different address, burns an extra fee, and leaves the original order unfunded.

    Rule of thumb: send-payment when we create the order, send-raw when someone handed us one.

First-time setup

The skill is self-contained — no scaffold step, no shell env vars, just install deps and run commands directly.

# 1. Install deps (one-time). The plugin ships a package.json and
#    package-lock.json only (no node_modules, to keep the artifact
#    small). Run this in the plugin directory once after install.
npm install --omit=dev

# 2. Generate a keypair only if you do not already have a wallet.
#    This writes ./.stellar-secret with mode 600, never prints the secret,
#    and refuses to overwrite an existing wallet file.
./node_modules/.bin/tsx scripts/generate-keypair.ts

# 3. Check your balance:
./node_modules/.bin/tsx skills/check-balance/run.ts

Every command accepts the same base flags:

--secret-file     Stellar secret file (default: .stellar-secret)
--identity        Stellar CLI identity to use instead of --secret-file
--network         testnet | pubnet (default: pubnet)
--horizon-url      override Horizon endpoint
--rpc-url          override Soroban RPC endpoint
--asset-sac    Stellar Asset Contract address

Key design decisions

  1. Client only. This skill does not scaffold servers. Servers live in stellar-mpp-sdk/examples/.
  2. Sponsored mode only. The only cross-compatible path for MPP + x402. See references/sponsored-mode.md.
  3. One signer, multiple envelopes. scripts/src/stellar-signer.ts produces the inner XDR once; scripts/src/x402.ts and scripts/src/mpp-envelope.ts wrap it differently.
  4. Rozo for cross-chain. send-payment and bridge delegate to intentapiv4.rozo.ai so we don't reimplement bridging.
  5. MPP Router for API discovery. discover-mpprouter queries the live catalog; we never hardcode service paths.
  6. Don't reinvent what exists. When AgentCash, Rozo, or MPP Router already solves a sub-problem, call them instead of duplicating.

Out of scope

  • Server-side 402 handlers (use @stellar/mpp/charge/server)
  • Channel-mode payments (off-chain commitments — use @stellar/mpp/channel/client directly if you need them)
  • Non-Stellar payment origination (if paying FROM EVM, use a different skill)
  • Key management beyond .env files (for production-grade, bring your own KMS)
  • Channel / trustline destruction (do that by hand — destructive ops not automated)

References

  • references/x402-exact-spec.md — x402 Stellar exact scheme wire format
  • references/mpp-charge-spec.md — @stellar/mpp charge mode wire format
  • references/sponsored-mode.md — why sponsored is the only cross-compat path
  • references/sdk-api-cheatsheet.md — common imports and constants
  • references/mainnet-checklist.md — before going to pubnet

Files in this skill

stellar-agent-wallet/
├── SKILL.md                          ← you are here
├── references/                       ← on-demand context
│   ├── x402-exact-spec.md
│   ├── mpp-charge-spec.md
│   ├── sponsored-mode.md
│   ├── sdk-api-cheatsheet.md
│   └── mainnet-checklist.md
├── scripts/
│   ├── generate-keypair.ts           ← writes .stellar-secret with mode 600
│   └── src/                          ← shared library code
│       ├── secret.ts                 ← file-based secret loader + redactor
│       ├── cli-config.ts             ← shared command-line flag parser
│       ├── stellar-signer.ts         ← sign SAC transfers
│       ├── rozo-client.ts            ← Rozo intent API client
│       ├── mpprouter-client.ts       ← MPP Router catalog client
│       ├── pay-engine.ts             ← 402 parse + retry orchestrator
│       ├── x402.ts                   ← x402 envelope encoder
│       ├── mpp-envelope.ts           ← MPP charge envelope encoder
│       └── balance.ts                ← shared balance reader (onboard + check-balance)
└── skills/                         ← sub-skills (run directly)
    ├── onboard/
    │   ├── SKILL.md
    │   └── run.ts                    ← readiness check + guided setup
    ├── check-balance/
    │   ├── SKILL.md
    │   ├── run.ts                    ← balance check
    │   ├── add-trustline.ts          ← enable Classic USDC
    │   └── swap-xlm-to-usdc.ts       ← DEX path payment
    ├── discover/
    │   ├── SKILL.md
    │   └── run.ts                    ← MPP Router catalog
    ├── pay-per-call/
    │   ├── SKILL.md
    │   └── run.ts                    ← 402 → pay → retry
    ├── send-payment/
    │   ├── SKILL.md
    │   ├── run.ts                    ← cross-chain via Rozo
    │   └── status.ts                 ← poll payment status
    ├── send-raw/
    │   ├── SKILL.md
    │   └── run.ts                    ← one Classic payment, address+asset+amount+memo as given
    └── bridge/
        ├── SKILL.md
        └── run.ts                    ← thin wrapper over send-payment

Related skills

Unified payment skill for AI agents. Four payment rails in one skill: Stripe for credit card and fiat payments, Coinbase Commerce for accepting crypto from c...

27 installs

Discover paid API services available via MPP Router (apiserver.mpprouter.dev) that accept Stellar USDC payments. Triggers on prompts like "summarize X using parallel.ai via MPPRouter", "search with exa via mpp", "find a service for <task>", "list mpp services", "what APIs can I pay for with stellar". Fetches the live service catalog, picks a matching service, and hands off to the pay-per-call sub-skill to actually invoke it.

21 installs1 stars

Pay for and use AI services via MoltsPay protocol. Trigger: User asks to generate video, use a paid service, etc. Auto-discovers services from /.well-known/a...

35 installs

Full Spraay x402 gateway interface for AI agents. Payments, DeFi, AI inference, and blockchain data in one skill. Batch payments and payroll, swap quotes, to...

24 installs1 stars

Evaluate and donate USDC on Base to humanitarian crowdfunding campaigns at zooid.fund. Use when the operator asks the agent to browse campaigns, assess evidence or peer signal, make charitable donations, or run scheduled philanthropic review. Hands off to a separate USDC-on-Base wallet skill for the actual transfer; campaign claims on the platform are unverified and must be assessed by the operator or agent.

22 installs

Use OKX OnchainOS MCP through UXC for token discovery, market data, wallet balance, and swap execution planning. Use when tasks need OKX MCP tools such as to...

30 installs