Guard API v1

Should this xStock buy go through right now?

The guard behind bozBasket, as one HTTP call any app can make before buying a tokenized stock on Solana mainnet. It takes a live Jupiter quote for your size and the latest Pyth price, runs both through the same checks the keeper uses, and tells you whether to buy or wait, and why. Free, read-only, no key, open to browsers.

Try it

live · Solana mainnet · read-only
GET https://boz-basket-web.vercel.app/api/v1/verdict

Try usdc 50000 to watch price impact widen the gap, or maxDivergenceBps 1 to see a defer.

GET/api/v1/verdict

Every parameter is optional.

symbol
Default all
Comma-separated xStocks or their tickers: TSLAx (TSLA), QQQx (QQQ).
usdc
Default 100
Buy size in USDC, up to 100,000. The Jupiter quote, and so the price impact, is for this size.
maxStalenessSecs
Default 120
Oldest acceptable Pyth publish time, in seconds.
maxConfBps
Default 50
Widest acceptable Pyth confidence band, in bps of the price.
maxDivergenceBps
Default 150
Largest acceptable gap between Jupiter's price per share and Pyth, in either direction.
minLiquidityUsd
Default 500
Smallest acceptable pool liquidity, in USD, as Jupiter reports it.
curl "https://boz-basket-web.vercel.app/api/v1/verdict?symbol=TSLAx&usdc=500"

What comes back

overall
buy when every requested xStock passes, defer when any fails, unavailable when a price source did not answer. Treat unavailable as defer.
results[].verdict
The same, per xStock.
results[].reason
Code, name and label of the first failing check, in the program's order: staleness, confidence, gap, depth. Null when unavailable.
results[].reference
The Pyth price, its confidence in bps, its publish time and its age in seconds.
results[].venue
What Jupiter quotes for your size: price per share with the issuer's share multiplier applied, shares, price impact, route and pool liquidity.
results[].gapBps
Signed: above zero the pool charges more than Pyth.
usSession
Whether the US regular session is open. Informational: the guard judges the price, not the calendar.

Use it before a swap

const url = "https://boz-basket-web.vercel.app/api/v1/verdict?symbol=TSLAx&usdc=500";
const { overall, results } = await fetch(url).then((r) => r.json());

if (overall !== "buy") {
  // A stale price, a wide confidence band, a pool off fair value or no depth:
  // wait, and tell the user why.
  return defer(results.map((r) => r.reason?.label ?? r.error));
}
await swap(); // your own Jupiter swap, right away

A quote is not a fill. Ask right before you send the swap, not minutes earlier.

GET/api/v1/history

The $100 checks bozBasket's keeper records every few minutes with the default limits, newest first. This is the data behind the chart on the home page.

symbol
Default all
As above.
since
Default 24 h ago
Unix seconds.
limit
Default 288
Rows to return, up to 1000.
curl "https://boz-basket-web.vercel.app/api/v1/history?symbol=QQQx&limit=12"

Reason codes

The same codes the on-chain program writes when it defers a basket.

0
Name OK
Meaning Executed
yes
1
Name REFERENCE_STALE
Meaning Reference price stale
yes
2
Name CONFIDENCE_TOO_WIDE
Meaning Confidence too wide
yes
3
Name MARKET_CLOSED
Meaning Market closed
no: a plan's session policy or vault
4
Name DIVERGENCE
Meaning Venue diverged from reference
yes
5
Name LOW_LIQUIDITY
Meaning Low liquidity
yes
6
Name INSUFFICIENT_BALANCE
Meaning Insufficient vault balance
no: a plan's session policy or vault

Fine print

  • Read-only: nothing is signed and nothing is bought.
  • Identical requests are cached for 15 seconds, and each address may send 60 requests a minute.
  • The arithmetic is checkLeg in packages/shared, the off-chain twin of the program's guard, which the keeper and the guard panel also use.
  • Covered: TSLAx and QQQx. VOOx is left out: no pool holds it on Solana, so Jupiter finds no route.
  • This runs on a free tier for a hackathon, with no uptime promise. Treat an error or unavailable as defer.

Machine-readable description: /api/v1/openapi.json (OpenAPI 3.1).