sp3nd について
SP3NDは、AIエージェントがAmazonやeBayの商品を購入し、Solana上のUSDCで支払うためのショッピングスキルです。登録、カート・注文作成、支払いトランザクションの構築と署名を扱います。
主な機能
- 01AmazonとeBayで商品を購入
- 02地域に応じてマーケットプレイスのドメインを選択
- 03カートと注文を作成
- 04USDCトランザクションを構築・署名
- 05注文の支払い状況を確認
活用シーン
- 01商品リンクからエージェントに注文させる
- 02配送地域に合わせたドメインを選ぶ
- 03Solana 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 エージェントが 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 ウォレット(mint:
EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v) soldersおよびsolanaPython パッケージ(pip install solders solana).env内の SP3ND API 認証情報(以下のステップ 1 で取得)
ステップ 1: エージェントを登録する(初回のみ)
自己登録 — 承認待ちのキューはありません。認証情報は一度だけ表示されるので、すぐに保存してください。
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 の TLD を選択する
重要: 配送先の国に一致するマーケットプレイスの TLD を使用してください。TLD が誤っていると、注文の失敗や誤った価格設定につながります。
地域別の Amazon TLD
| TLD | 対象国 |
|---|---|
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 TLD
| TLD | 対象国 |
|---|---|
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)を見つける — 導出せず、取得してください
- 2 つの命令を含むトランザクションを構築する: 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 エージェントには、Privy が管理する Solana ウォレットが組み込まれています。次の 2 つのツールを順番に使用してください:
ステップ 1 — ウォレットアドレスを取得する:
wallet_info() → returns solana address (e.g. C4ffoATXA5j3UdyvP4UQ3vMuQ547G18bG2QqhSs5bDvb)
ステップ 2 — 構築前に USDC 残高を確認する:
wallet_sol_balance() → lists all SPL tokens including USDC
ステップ 3 — 未署名の tx に署名する:
wallet_sol_sign_transaction(transaction=unsigned_b64)
→ returns { signed_transaction: "<base64>" }
ステップ 4 — Solana RPC 経由で直接ブロードキャストする:
⚠️ wallet_sol_transfer は使用しないでください — これはネイティブ SOL のみを扱い、SPL トークンには対応していません。USDC の送金では、署名済みの tx を 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 を検出し、注文を Paid としてマークします — 通常は 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 でオンチェーンから取得し、導出してはいけません |
| memo 命令の欠落 | SP3ND Order: <order_number> を付けた MemoSq4g... 命令を追加してください — これがないと USDC は着金しますが注文は未払いのままです |
USDC に wallet_sol_transfer を使用 | 動作しません — 生の tx を構築し、wallet_sol_sign_transaction を実行して、RPC 経由でブロードキャストしてください |
| 国に対して誤った Amazon TLD | ステップ 2 の TLD 表を使用してください — 誤った TLD は注文失敗につながります |
| 導出した ATA を使った未署名 tx | トレジャリーの実際の ATA は導出した ATA と異なります — 取得してください |
注文に customer_email がない | 必須フィールドです — これがないと createPartnerOrder は 400 を返します |
| カートの有効期限 | カートは 30 分で失効します — 速やかに注文してください |
手数料体系
- プラットフォーム手数料: デフォルトで 0%
- 支払い: Solana 上の USDC (6 桁、USD 金額に 1,000,000 を乗算)
- Amazon: 対象商品は Prime 送料無料
- eBay: 商品ごとの送料は出品者が設定
主要なアドレス
| 項目 | 値 |
|---|---|
| SP3ND トレジャリー | 2nkTRv3qxk7n2eYYjFAndReVXaV7sTF3Z9pNimvp5jcp |
| USDC mint (Solana) | EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v |
| x402 ファシリテーター | https://facilitator.payai.network |
| サポート | [email protected] |