Treasures Finance Agent Skills
Agent Skills for building AI agents on the Treasures finance APIs.
A skill is a folder of plain-Markdown instructions (SKILL.md) that a coding agent loads on demand. The skills here teach an agent to call the Treasures finance APIs correctly — discover tokenized stocks, quote and execute trades, bridge USDC across chains, operate a delegated wallet, and read portfolios — including the signing details and footguns that are easy to get wrong.
Skill catalog
| Skill | What it does |
|---|---|
treasures-b2b-api |
Build an agent on the Treasures public B2B API: discover tokenized stocks, quote/execute trades, bridge USDC across Solana and Ethereum, and read portfolio + trade history for a single end-user wallet pair. Covers endpoint selection, ownership-proof signing (incl. embedded wallets), trade/bridge execution, and error handling. |
treasures-wallet |
Operate a Treasures delegated wallet over HTTP: onboard (provision a wallet + mint a scoped API key), quote, execute async buys/sells (non-custodial — the agent never signs; Treasures signs as a delegated signer scoped strictly to RWA trades), read balances/portfolio/trade history, and manage API keys. Trades tokenized equities (xStocks / Ondo) vs USDC on Solana or Ethereum with only HTTPS + an API key — no web3 libraries, keys, or RPC. |
⚠️ Read this before any trade attempt (verified live 2026-07-27)
Two things fail silently if you don't know them. Both were confirmed with live calls, not docs.
1. Base URL needs a path prefix
https://api.treasures.io alone 404s on every path. Two planes off the same host:
| Plane | Base | Used by |
|---|---|---|
| Public B2B | https://api.treasures.io/public/v1 |
treasures-b2b-api (default) |
| Delegated agent | https://api.treasures.io/api/v1 |
treasures-wallet |
2. Trade paths are geo-fenced at the load balancer
Reads are open worldwide; writes are not.
| Path | Result from a blocked IP |
|---|---|
GET /stocks/*, /portfolio, /trades |
✅ 200 |
POST /quote/buy, /quote/sell, /bridge/quote, /trade/submit |
❌ 451 unavailable_for_legal_reasons |
- The block sits at the AWS load balancer (
server: awselb/2.0), matched on path + real TCP source IP, before auth and before the app. Unknown paths return 404 (not 451), andGET/OPTIONSon a trade path also 451 → the path is fenced, not the write method. Both planes are covered —/api/v1/quote/sell451s identically to/public/v1/quote/sell. - Spoofed geo headers do not work (
X-Forwarded-For,CF-IPCountry,X-Real-IP,True-Client-IPall still 451). - Blocked: US (default Starchild egress is San Jose, CA) and GB. Clear: DE, NL, SE, CH, SG, HK, JP — tested via the
sc-vpnskill with a per-request proxy (proxies=/curl -x). Never set a globalHTTP_PROXY; it breaks sc-proxy billing.
A 451 is never a wallet, signing, or delegation problem. Don't debug signatures until you're past it.
Error ladder on /quote/sell — tells you which layer rejected you
451 unavailable_for_legal_reasons → geo edge (change exit region)
400 invalid_request → schema (fix the body)
401 ownership_proof_eth_invalid → signature (re-sign the challenge)
422 holdings_insufficient → auth OK, wallet just lacks the asset
Reaching 422 proves geo and signing both work — it's the healthiest failure you can get.
Eligibility — not optional
The 451 is an eligibility rule working as designed, not an outage. Ondo/xStocks tokenized equities are not offered to US persons, and Ondo additionally enforces KYC/transfer whitelists at the token contract, so an ineligible wallet is rejected on-chain no matter what the exit IP says. Confirm the user is eligible in a permitted jurisdiction before routing around the fence. Clearing a geo-block for a user who is genuinely non-US is fine; using it to evade a securities restriction is not.
How to route trade calls through sc-vpn
Prerequisite: the sc-vpn skill (official). Install if missing — npx skills add Starchild-ai-agent/official-skills --skill sc-vpn --agent openclaw. No credentials; internal network only. Health check: curl http://sc-vpn.internal:8081/health → {"status": "ok"}.
Proxy URL format is http://<region>:x@sc-vpn.internal:8080 — the username is the region code. Omit it and you get 400 No region specified.
Rule: reads go direct, only the fenced trade paths go through the VPN. Sending everything through the tunnel is slower and pointless — /stocks, /portfolio and /trades already work from anywhere.
import requests, time
from core.skill_tools import wallet # run from a dir where `core` is importable (e.g. /tmp or /data/workspace)
BASE = "https://api.treasures.io/public/v1"
VPN = "http://de:x@sc-vpn.internal:8080" # de | nl | se | ch | sg | hk | jp
PROX = {"http": VPN, "https": VPN} # per-request ONLY — never os.environ
ETH = "0x...".lower() # wallet address, lowercase
# READ — direct, no proxy
pf = requests.get(f"{BASE}/portfolio", params={"eth_wallet": ETH}, timeout=30).json()
# WRITE — through the VPN, with a signed ownership proof
issued = int(time.time())
challenge = f"treasures-finance-quote-v1\n{issued}\n\n{ETH}" # verified format; note the blank line
sig = wallet.wallet_sign(challenge)["signature"]
body = {
"ticker": "GOOGL", "chain": "eth",
"amount_shares": "0.01", "max_slippage_bps": 100,
"eth_wallet": ETH,
"ownership_proof": {"issued_at": issued, "eth_signature": sig},
}
r = requests.post(f"{BASE}/quote/sell", json=body, proxies=PROX, timeout=60)
print(r.status_code, r.text) # 422 holdings_insufficient = geo + signing both OK
Same thing from bash:
curl -x "http://de:x@sc-vpn.internal:8080" \
-X POST https://api.treasures.io/public/v1/quote/sell \
-H 'content-type: application/json' -d @body.json
Confirm the exit before trusting a result: curl -x "http://de:x@sc-vpn.internal:8080" https://ipinfo.io/json.
Footguns
| Symptom | Cause |
|---|---|
| Still 451 through the VPN | Region is itself blocked — GB is fenced too. Use DE/NL/SE/CH/SG/HK/JP. |
| Every other API starts 401ing | You set a global HTTP_PROXY and bypassed sc-proxy. Unset it; use proxies= per request. |
400 Bad Request: No region specified |
Missing the region username in the proxy URL. |
502 Unknown region |
Region code not in the sc-vpn list of 18. |
401 ownership_proof_eth_invalid |
Proof issue, not geo — check lowercase address, fresh issued_at, exact challenge string. |
Keep the whole trade sequence (/quote/* → /trade/submit, and /bridge/quote → bridge submit) on the same exit region. Mixing exits mid-flow risks the backend seeing an inconsistent origin between legs.
Install
# Install one sub-skill (recommended — pulls just what you need)
npx skills add treasures-io/treasures-finance-agent-skills --skill treasures-b2b-api
npx skills add treasures-io/treasures-finance-agent-skills --skill treasures-wallet
# Or install everything (auto-detects your environment and installs accordingly)
npx skills add treasures-io/treasures-finance-agent-skills
npx skills installs SKILL.md files into the right place for 70+ coding agents (Claude Code, Codex, Cursor, GitHub Copilot, Windsurf, Cline, OpenCode, …) and auto-detects which ones you have. It reads this repo's skills/<name>/SKILL.md layout directly, so no extra setup is required.
Target specific agents with -a:
npx skills add treasures-io/treasures-finance-agent-skills -a claude-code -a codex -a cursor
License
MIT