Skip to Content
Docs for agents

Agent API Quickstart

Starship exposes a small paid API for trading agents that need Base token and wallet intelligence during scanner loops. The API is read-only: it does not execute trades, place orders, trigger backfills, or mutate indexing jobs.

Use it as a decision input, not as trading advice or execution infrastructure.

Base URL

https://api.strshp.ai/v1/agent

Payment Model

Paid production requests use x402 exact EVM payments on Base mainnet (eip155:8453). Requests without payment receive 402 Payment Required with x402 payment requirements. A paying client signs the quoted payment and retries the same HTTP request with a PAYMENT-SIGNATURE header.

Every paid request must include a stable x402 extension named payment-identifier. Generate one id per logical request and reuse it only when retrying that exact request.

Prices

EndpointPrice
GET /token/{address}/analysis$0.05
GET /wallet/{address}/quality$0.025
GET /alerts/recent$0.005
GET /token/{address}/top-wallets$0.10
POST /batch/analyzePer item: $0.05 for token_analysis, $0.025 for wallet_quality

batch/analyze accepts up to 20 items and is charged as the sum of item prices.

  1. Poll GET /alerts/recent every 10 minutes. The endpoint accepts no query parameters and returns public alerts from the last 10 minutes.
  2. Ignore stale alerts and low-confidence alerts before paying for deeper checks.
  3. For candidate tokens, call GET /token/{address}/analysis.
  4. Skip tokens with has_critical_flags: true, weak decision_grade, low confidence, poor liquidity, or unacceptable holder concentration.
  5. If the token still passes, call GET /token/{address}/top-wallets.
  6. Call GET /wallet/{address}/quality only for wallets that affect your policy, such as large smart buyers, top holders, recent sellers, or bad-wallet clusters.
  7. Log the request URL, payment id, settlement response, response payload, policy decision, and simulated or real trade outcome.

Python x402 Example

Install:

pip install "x402[httpx]" eth-account
import asyncio import os import uuid from eth_account import Account from x402 import x402Client from x402.http import x402HTTPClient from x402.http.clients import x402HttpxClient from x402.mechanisms.evm import EthAccountSigner from x402.mechanisms.evm.exact.register import register_exact_evm_client API_BASE = os.environ["STARSHIP_AGENT_API_BASE"].rstrip("/") MAX_PRICE_USD = 0.10 def payment_extensions(payment_id: str) -> dict: return {"payment-identifier": payment_id} async def paid_get(path: str, *, max_price_usd: float) -> dict: if max_price_usd > MAX_PRICE_USD: raise ValueError("max_price_usd exceeds local agent spend policy") client = x402Client() account = Account.from_key(os.environ["EVM_PRIVATE_KEY"]) register_exact_evm_client(client, EthAccountSigner(account)) payment_id = f"starship:{uuid.uuid4()}" http_client = x402HTTPClient(client) async with x402HttpxClient(client) as http: response = await http.get( f"{API_BASE}{path}", extensions=payment_extensions(payment_id), timeout=20, ) response.raise_for_status() await response.aread() settlement = http_client.get_payment_settle_response( lambda name: response.headers.get(name) ) print({"payment_id": payment_id, "settlement": settlement}) return response.json() async def main() -> None: token = "0x0000000000000000000000000000000000000000" analysis = await paid_get( f"/token/{token}/analysis", max_price_usd=0.05, ) if analysis["has_critical_flags"] or analysis["decision_grade"] not in ("A", "B"): return top_wallets = await paid_get( f"/token/{token}/top-wallets", max_price_usd=0.10, ) print(top_wallets) asyncio.run(main())

TypeScript x402 Example

Install:

npm install @x402/fetch @x402/evm viem
import { x402Client, wrapFetchWithPayment, x402HTTPClient } from "@x402/fetch"; import { registerExactEvmScheme } from "@x402/evm/exact/client"; import { privateKeyToAccount } from "viem/accounts"; import { randomUUID } from "node:crypto"; const apiBase = process.env.STARSHIP_AGENT_API_BASE!.replace(/\/$/, ""); const maxPriceUsd = 0.10; type AgentAnalysis = { has_critical_flags: boolean; decision_grade: "A" | "B" | "C" | "D" | "F" | null; confidence: number | null; }; function paymentExtensions(paymentId: string) { return { "payment-identifier": paymentId }; } async function paidGet<T>(path: string, priceCapUsd: number): Promise<T> { if (priceCapUsd > maxPriceUsd) { throw new Error("price cap exceeds local agent spend policy"); } const signer = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`); const client = new x402Client(); registerExactEvmScheme(client, { signer }); const fetchWithPayment = wrapFetchWithPayment(fetch, client); const paymentId = `starship:${randomUUID()}`; const response = await fetchWithPayment(`${apiBase}${path}`, { method: "GET", extensions: paymentExtensions(paymentId), } as RequestInit); if (!response.ok) { throw new Error(`Starship request failed: ${response.status} ${await response.text()}`); } const httpClient = new x402HTTPClient(client); const settlement = httpClient.getPaymentSettleResponse((name) => response.headers.get(name) ); console.log({ paymentId, settlement }); return response.json() as Promise<T>; } const token = "0x0000000000000000000000000000000000000000"; const analysis = await paidGet<AgentAnalysis>(`/token/${token}/analysis`, 0.05); if (!analysis.has_critical_flags && ["A", "B"].includes(analysis.decision_grade ?? "")) { const wallets = await paidGet(`/token/${token}/top-wallets`, 0.10); console.log(wallets); }

Retry And Idempotency

Treat payment-identifier as the idempotency key for paid requests.

  • Reuse the same payment-identifier only when retrying the exact same method, path, query string, and JSON body.
  • If the first request settled and the response was cached, the same request and payment id returns the cached response without re-running the protected handler or settling again.
  • If the same payment id is reused with a different route, query, path, or body, the API rejects it before handler execution.
  • If the idempotency store is unavailable, paid requests fail closed with 503 before handler execution.
  • Generate a new payment id for every new logical request, even if the URL is similar.

cache_status describes the response cache for live data (hit, miss, error, or unknown). It is separate from paid x402 idempotency replay.

Endpoint Reference

GET /alerts/recent

Use this as the discovery endpoint. It accepts no query parameters and returns public alerts created in the last 10 minutes.

Supported public alert types are strong_launch and dormant_buy.

{ "alerts": [ { "id": 120944, "chain": "base", "token_address": "0x1111111111111111111111111111111111111111", "alert_type": "strong_launch", "severity": "high", "confidence": 0.91, "payload": { "reason": "smart_wallet_cluster", "smart_buyers": 6 }, "created_at": "2026-06-21T10:31:04Z" } ], "page": { "limit": 1, "returned": 1, "next_cursor": null, "since": "2026-06-21T10:21:04Z" }, "data_freshness_ms": 2400, "cache_status": "miss" }

GET /token/{address}/analysis

Use this for the main token decision. The response intentionally excludes internal lifecycle and raw score fields.

{ "chain": "base", "token_address": "0x1111111111111111111111111111111111111111", "symbol": "SHIP", "name": "Starship", "source": "uniswap_v4", "deployer": "0x2222222222222222222222222222222222222222", "first_seen_at": "2026-06-21T09:58:17Z", "age_hours": 0.55, "price_usd": 0.000012, "fdv_usd": 1200000, "fdv_confidence": 0.86, "liquidity_depth_eth": 18.4, "volume_24h_eth": 92.3, "buy_count_24h": 421, "sell_count_24h": 138, "total_holders": 812, "top_10_pct": 24.8, "top_50_pct": 51.2, "dev_status": "sold_partial", "confidence": 0.88, "buyer_summary": { "elite_count": 3, "good_count": 9, "neutral_count": 72, "bad_count": 2, "elite_volume_pct": 18.5, "good_volume_pct": 31.4 }, "has_critical_flags": false, "reason_codes": [ { "code": "smart_buyer_cluster", "severity": "info", "detail": "Multiple quality wallets bought in the launch window" } ], "recent_alerts": [ { "id": 120944, "chain": "base", "token_address": "0x1111111111111111111111111111111111111111", "alert_type": "strong_launch", "severity": "high", "confidence": 0.91, "payload": { "smart_buyers": 6 }, "created_at": "2026-06-21T10:31:04Z" } ], "decision_grade": "B", "data_freshness_ms": 6100, "cache_status": "miss" }

GET /token/{address}/top-wallets

Use this after a token passes analysis. It returns bounded decision-relevant groups, not a full holder export.

{ "chain": "base", "token_address": "0x1111111111111111111111111111111111111111", "top_holders": [ { "wallet": "0x3333333333333333333333333333333333333333", "group": "top_holder", "quality_tier": "good", "quality_score": 74, "pct_supply": 2.8, "balance": 28000000, "realized_pnl_eth": 12.4, "lifetime_pnl_eth": 84.2, "playstyle": "early_accumulator", "first_buy_at": "2026-06-21T10:03:30Z", "last_trade_at": "2026-06-21T10:22:10Z", "flags": [] } ], "smart_buyers": [], "recent_sellers": [], "bad_wallets": [], "data_freshness_ms": 8800, "cache_status": "miss" }

GET /wallet/{address}/quality

Use this only when a wallet changes the decision. Example: a top holder is also an elite profitable wallet, or a recent seller has a scam-heavy profile.

{ "chain": "base", "wallet": "0x3333333333333333333333333333333333333333", "tier": "good", "score": 74, "win_rate": 0.61, "lifetime_pnl_eth": 84.2, "total_tokens_sold": 143, "scam_victim_count": 1, "quality_updated_at": "2026-06-21T10:20:00Z", "quality_confidence": 0.83, "quality_confidence_reason": "sufficient_realized_trade_history", "playstyle_updated_at": "2026-06-21T10:21:00Z", "playstyle": "early_accumulator", "notable_trades": [ { "token_address": "0x1111111111111111111111111111111111111111", "token_symbol": "SHIP", "approx_profit_eth": 6.7 } ], "decision_grade": "B", "data_freshness_ms": 31000, "cache_status": "hit" }

POST /batch/analyze

Use this for scanner loops that already have a small bounded candidate set. Each item must be token_analysis or wallet_quality.

{ "chain": "base", "items": [ { "kind": "token_analysis", "address": "0x1111111111111111111111111111111111111111" }, { "kind": "wallet_quality", "address": "0x3333333333333333333333333333333333333333" } ] }
{ "chain": "base", "items": [ { "kind": "token_analysis", "address": "0x1111111111111111111111111111111111111111", "status": "ok", "token_analysis": { "chain": "base", "token_address": "0x1111111111111111111111111111111111111111", "symbol": "SHIP", "buyer_summary": { "elite_count": 3, "good_count": 9, "neutral_count": 72, "bad_count": 2, "elite_volume_pct": 18.5, "good_volume_pct": 31.4 }, "has_critical_flags": false, "reason_codes": [], "recent_alerts": [], "decision_grade": "B", "data_freshness_ms": 6100, "cache_status": "miss" }, "wallet_quality": null }, { "kind": "wallet_quality", "address": "0x3333333333333333333333333333333333333333", "status": "ok", "token_analysis": null, "wallet_quality": { "chain": "base", "wallet": "0x3333333333333333333333333333333333333333", "tier": "good", "score": 74, "lifetime_pnl_eth": 84.2, "total_tokens_sold": 143, "scam_victim_count": 1, "notable_trades": [], "decision_grade": "B", "data_freshness_ms": 31000, "cache_status": "miss" } } ], "cache_status": "miss" }

Response Interpretation

  • decision_grade: compact grade for automated policies. Treat A and B as candidates, C as manual-review or low-size, and D/F as skip unless your strategy explicitly accepts high risk.
  • confidence: model confidence for the token or wallet signal. Do not use grade without confidence.
  • has_critical_flags: hard risk indicator. Most agents should skip when true.
  • reason_codes: machine-readable explanation for policy logs and audits.
  • data_freshness_ms: age of the newest underlying data used by the response.
  • cache_status: live response cache status. error means cache access failed and the API returned live data where possible.

Limits And Errors

  • Addresses must be EVM addresses matching 0x plus 40 hex characters.
  • alerts/recent returns all public alerts from the last 10 minutes and rejects query parameters.
  • top-wallets returns bounded groups of decision-relevant wallets.
  • batch/analyze accepts 1 to 20 items.
  • Expensive endpoints have concurrency limits and may return 429.
  • Guardrail timeouts return 504.
  • Missing, malformed, mismatched, or rejected payment returns 402.
  • Idempotency store failures return 503.