关于 sp3nd
SP3ND 是供 AI Agent 使用的购物技能,可在 Amazon 和 eBay 选购商品并以 Solana 上的 USDC 付款。文档涵盖注册、购物车和订单创建,以及构建并签名支付交易的流程。
主要功能
- 01在 Amazon 和 eBay 选购商品
- 02按地区选择商城域名
- 03创建购物车和订单
- 04构建并签名 USDC 交易
- 05查询订单支付状态
适用场景
- 01让 Agent 按指定商品链接下单
- 02根据收货地区选用商城域名
- 03使用 Solana USDC 支付购物订单
- 04轮询确认订单付款
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ starchild-ai-agent/ official-skills --skill sp3nd安装后在 Claude Code 中输入/sp3nd确认已加载。
详细介绍
SP3ND — 使用 Solana 上的 USDC 自主在 Amazon/eBay 购物
SP3ND 可让 AI Agent 使用 Solana 上的 USDC 在 Amazon 和 eBay 购买真实商品。无需 KYC、无需账户、平台费率为 0%,符合条件的 Amazon 商品可享受免费 Prime 配送。
完整 API 文档: https://sp3nd.shop/partner-api/docs
SKILL.md: https://sp3nd.shop/skill.md
基础 URL: https://us-central1-sp3nddotshop-prod.cloudfunctions.net
前置条件
- 持有 USDC 余额的 Solana 钱包(铸币地址:
EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v) solders和solanaPython 包(pip install solders solana).env中的 SP3ND API 凭据(通过下方步骤 1 获取)
步骤 1:注册 Agent(仅需一次)
自助注册,无需排队审批。凭据只会显示一次;请立即保存。
import urllib.request, json
BASE_URL = "https://us-central1-sp3nddotshop-prod.cloudfunctions.net"
wallet_pubkey = "<your Solana wallet pubkey>"
payload = json.dumps({
"agent_name": "My Agent",
"solana_public_key": wallet_pubkey,
"contact_email": "[email protected]",
"description": "Autonomous shopping agent"
}).encode()
req = urllib.request.Request(
f"{BASE_URL}/registerAgent",
data=payload,
headers={"Content-Type": "application/json"},
method="POST"
)
with urllib.request.urlopen(req, timeout=15) as r:
d = json.loads(r.read())
print(d["api_key"], d["api_secret"]) # save both to .env
保存到 .env:
SP3ND_API_KEY=sp3nd_...
SP3ND_API_SECRET=sp3nd_sec_...
步骤 2:选择正确的 Amazon/eBay 顶级域名
重要: 使用与配送国家/地区对应的市场顶级域名。顶级域名错误会导致订单失败或价格错误。
各地区的 Amazon 顶级域名
| 顶级域名 | 覆盖国家/地区 |
|---|---|
amazon.com | US,以及默认回退选项 |
amazon.co.uk | GB、IE |
amazon.de | DE、AT、CH 以及欧洲大部分地区 |
amazon.fr | FR |
amazon.it | IT |
amazon.es | ES |
amazon.nl | NL、BE |
amazon.pl | PL |
amazon.se | SE |
amazon.com.tr | TR |
amazon.co.jp | JP |
amazon.com.au | AU、NZ |
amazon.in | IN |
amazon.sg | SG、MY、TH、VN、ID、PH、MM、BN、KH、LA |
amazon.ae | AE、OM、BH、KW、QA、JO、IQ、LB |
amazon.sa | SA、YE |
amazon.eg | EG |
amazon.com.br | BR |
amazon.com.mx | MX |
amazon.ca | CA |
各地区的 eBay 顶级域名
| 顶级域名 | 国家/地区 |
|---|---|
ebay.com | US(默认) |
ebay.co.uk | GB |
ebay.de | DE、AT、CH |
ebay.fr | FR |
ebay.it | IT |
ebay.es | ES |
ebay.com.au | AU |
ebay.ca | CA |
步骤 3:创建购物车
API_KEY = os.environ["SP3ND_API_KEY"]
API_SECRET = os.environ["SP3ND_API_SECRET"]
HEADERS = {"Content-Type": "application/json", "X-API-Key": API_KEY, "X-API-Secret": API_SECRET}
payload = json.dumps({
"items": [{"product_url": "https://www.amazon.sg/dp/ASIN", "quantity": 1}]
}).encode()
req = urllib.request.Request(f"{BASE_URL}/createPartnerCart", data=payload, headers=HEADERS, method="POST")
with urllib.request.urlopen(req, timeout=20) as r:
cart = json.loads(r.read())
cart_id = cart["cart"]["cart_id"]
total = cart["cart"]["total_amount"] # in USD = USDC amount needed
步骤 4:创建订单
payload = json.dumps({
"cart_id": cart_id,
"customer_email": "[email protected]", # required
"shipping_address": {
"name": "Full Name",
"address_line1": "Street address",
"address_line2": "Unit/suburb", # optional
"city": "City",
"state": "State/province",
"zip": "Postal code",
"country": "ISO 2-letter code (e.g. MY, US, GB)",
"phone": "+1234567890"
}
}).encode()
req = urllib.request.Request(f"{BASE_URL}/createPartnerOrder", data=payload, headers=HEADERS, method="POST")
with urllib.request.urlopen(req, timeout=20) as r:
order = json.loads(r.read())
order_id = order["order"]["order_id"]
order_number = order["order"]["order_number"]
total_amount = order["order"]["total_amount"]
步骤 5:构建并签署支付交易
这是比较棘手的部分。 SP3ND 使用 x402 v2 协议。调用 payAgentOrder 时会返回带有支付要求的 HTTP 402。你必须:
- 在链上查找财库的实际 USDC 代币账户(ATA)——不要推导,直接获取
- 构建一笔包含两条指令的交易:USDC
transferChecked,以及内容为SP3ND Order: <order_number>的 Memo - Memo 为必填项——没有它,SP3ND 的 webhook 就无法将支付与订单匹配
- 直接通过 Solana RPC 签署并广播
import base64, struct, urllib.request, json
from solders.pubkey import Pubkey
from solders.hash import Hash
from solders.message import Message
from solders.transaction import Transaction
from solders.instruction import Instruction, AccountMeta
from solana.rpc.api import Client
USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
TOKEN_PROG = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
MEMO_PROG = "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"
TREASURY = "2nkTRv3qxk7n2eYYjFAndReVXaV7sTF3Z9pNimvp5jcp"
RPC_URL = "https://api.mainnet-beta.solana.com"
def get_treasury_ata():
"""Fetch SP3ND treasury's actual USDC ATA on-chain. Do NOT derive — fetch."""
payload = json.dumps({
"jsonrpc": "2.0", "id": 1,
"method": "getTokenAccountsByOwner",
"params": [TREASURY, {"mint": USDC_MINT}, {"encoding": "jsonParsed"}]
}).encode()
req = urllib.request.Request(RPC_URL, data=payload, headers={"Content-Type": "application/json"})
with urllib.request.urlopen(req, timeout=10) as r:
d = json.loads(r.read())
return d["result"]["value"][0]["pubkey"]
def build_unsigned_tx(wallet_pubkey, our_ata, treasury_ata, amount_usdc_units, order_number):
"""Build unsigned tx: transferChecked + memo. amount_usdc_units = USDC * 1_000_000."""
client = Client(RPC_URL)
bh = client.get_latest_blockhash().value.blockhash
wallet_pk = Pubkey.from_string(wallet_pubkey)
src = Pubkey.from_string(our_ata)
dst = Pubkey.from_string(treasury_ata)
mint = Pubkey.from_string(USDC_MINT)
token_prog = Pubkey.from_string(TOKEN_PROG)
memo_prog = Pubkey.from_string(MEMO_PROG)
# Instruction 1: transferChecked (discriminator=12, u64 amount, u8 decimals=6)
ix_transfer = Instruction(
program_id=token_prog,
accounts=[
AccountMeta(pubkey=src, is_signer=False, is_writable=True),
AccountMeta(pubkey=mint, is_signer=False, is_writable=False),
AccountMeta(pubkey=dst, is_signer=False, is_writable=True),
AccountMeta(pubkey=wallet_pk, is_signer=True, is_writable=False),
],
data=bytes([12]) + struct.pack("<Q", amount_usdc_units) + bytes([6])
)
# Instruction 2: Memo — required for SP3ND webhook to match payment to order
ix_memo = Instruction(
program_id=memo_prog,
accounts=[AccountMeta(pubkey=wallet_pk, is_signer=True, is_writable=False)],
data=f"SP3ND Order: {order_number}".encode("utf-8")
)
msg = Message.new_with_blockhash([ix_transfer, ix_memo], wallet_pk, Hash.from_string(str(bh)))
tx = Transaction.new_unsigned(msg)
return base64.b64encode(bytes(tx)).decode()
签署并广播(Starchild Privy 钱包)
Starchild Agent 内置由 Privy 管理的 Solana 钱包。按顺序使用以下两个工具:
步骤 1 — 获取钱包地址:
wallet_info() → returns solana address (e.g. C4ffoATXA5j3UdyvP4UQ3vMuQ547G18bG2QqhSs5bDvb)
步骤 2 — 构建交易前检查 USDC 余额:
wallet_sol_balance() → lists all SPL tokens including USDC
步骤 3 — 签署未签名的交易:
wallet_sol_sign_transaction(transaction=unsigned_b64)
→ returns { signed_transaction: "<base64>" }
步骤 4 — 直接通过 Solana RPC 广播:
⚠️ 不要使用 wallet_sol_transfer——它只能处理原生 SOL,不能处理 SPL 代币。转账 USDC 时,必须自行通过 Solana RPC 广播已签名的交易。
signed_b64 = "<signed_transaction from tool above>"
payload = json.dumps({
"jsonrpc": "2.0", "id": 1,
"method": "sendTransaction",
"params": [signed_b64, {"encoding": "base64", "preflightCommitment": "confirmed"}]
}).encode()
req = urllib.request.Request(RPC_URL, data=payload, headers={"Content-Type": "application/json"})
with urllib.request.urlopen(req, timeout=30) as r:
d = json.loads(r.read())
tx_sig = d["result"] # transaction signature
print(f"https://solscan.io/tx/{tx_sig}")
查找你的 USDC 代币账户(our_ata):
# Fetch your own USDC ATA on-chain — same pattern as treasury ATA lookup
payload = json.dumps({
"jsonrpc": "2.0", "id": 1,
"method": "getTokenAccountsByOwner",
"params": [wallet_pubkey, {"mint": USDC_MINT}, {"encoding": "jsonParsed"}]
}).encode()
req = urllib.request.Request(RPC_URL, data=payload, headers={"Content-Type": "application/json"})
with urllib.request.urlopen(req, timeout=10) as r:
d = json.loads(r.read())
our_ata = d["result"]["value"][0]["pubkey"]
balance = d["result"]["value"][0]["account"]["data"]["parsed"]["info"]["tokenAmount"]["uiAmount"]
步骤 6:确认订单已付款
每隔约 5 秒轮询一次 getPartnerOrders。SP3ND 的 Helius webhook 会检测链上的 USDC 和 memo,并将订单标记为已付款——通常在 60 秒内完成。
import time
for _ in range(24): # up to ~2 minutes
req = urllib.request.Request(f"{BASE_URL}/getPartnerOrders", headers=HEADERS)
with urllib.request.urlopen(req, timeout=15) as r:
orders = json.loads(r.read())["orders"]
order = next((o for o in orders if o["order_number"] == order_number), None)
if order and order["status"] == "Paid":
print("Order paid:", order["order_number"])
break
time.sleep(5)
常见问题
| 问题 | 解决方法 |
|---|---|
| 金库 ATA 错误 | 始终通过 getTokenAccountsByOwner 获取链上数据,切勿自行推导 |
| 缺少备注指令 | 添加 MemoSq4g... 指令,并附上 SP3ND Order: <order_number> —— 缺少此指令时,USDC 虽会到账,但订单仍显示未付款 |
使用 wallet_sol_transfer 转账 USDC | 无法使用——构建原始交易,再调用 wallet_sol_sign_transaction,然后通过 RPC 广播 |
| 国家对应的 Amazon 顶级域名错误 | 使用步骤 2 中的顶级域名表——顶级域名错误会导致订单失败 |
| 使用派生 ATA 的未签名交易 | 金库的实际 ATA 与派生 ATA 不同——请获取实际 ATA |
订单中缺少 customer_email | 此字段为必填项——缺少时,createPartnerOrder 会返回 400 |
| 购物车过期 | 购物车会在 30 分钟后过期——请及时下单 |
费用结构
- 平台费用:默认 0%
- 付款方式:Solana 上的 USDC(6 位小数,美元金额乘以 1,000,000)
- Amazon:符合条件的商品可享受 Prime 免费配送
- eBay:每件商品的配送费由卖家设定
关键地址
| 项目 | 值 |
|---|---|
| SP3ND 金库 | 2nkTRv3qxk7n2eYYjFAndReVXaV7sTF3Z9pNimvp5jcp |
| USDC mint(Solana) | EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v |
| x402 中介服务 | https://facilitator.payai.network |
| 支持邮箱 | [email protected] |