Documentation
Build with Slice
The reward math, and a free read-only API for live tokenized stock prices and Jupiter swap quotes on Solana. No key, no signup.
On this page
01
Introduction
Slice pays for attention in stock. Watch a thirty-second ad, earn $0.50, and once you reach $1 it converts into a tokenized share on Solana.
Per ad
$0.50
Claim at
$1
Daily cap
$10
Every price and conversion on this site comes from Jupiter. The endpoints below expose the same data so you can build dashboards, bots or widgets on top of it.
02
How rewards work
A reward is a dollar amount, converted to stock at the live price. Because shares are divisible to eight decimals, even $0.50 buys a real fraction.
- 1
Watch. The ad counts only after the full thirty seconds, and the timer pauses when the tab is hidden.
- 2
Accrue. Each finished ad adds $0.50, up to $10 (20 ads) a day.
- 3
Claim. At $1 (2 ads) you pick a stock and the treasury swaps USDC for it on Jupiter.
- 4
Hold. The shares land in a wallet on your phone, and every payout is public on chain.
const EARN_PER_AD_USD = 0.5
const CLAIM_AT_USD = 1
const DAILY_CAP_USD = 10
/** Fraction of a share one ad is worth at a given price. */
export function unitsPerAd(priceUsd: number) {
return EARN_PER_AD_USD / priceUsd
}
/** Ads needed before a claim unlocks, and before one whole share. */
export function milestones(priceUsd: number) {
return {
adsToClaim: Math.ceil(CLAIM_AT_USD / EARN_PER_AD_USD), // 2
adsToShare: Math.ceil(priceUsd / EARN_PER_AD_USD),
maxAdsPerDay: Math.round(DAILY_CAP_USD / EARN_PER_AD_USD), // 20
}
}
unitsPerAd(225) // 0.0000888… of one NVDAx
milestones(225) // { adsToClaim: 50, adsToShare: 11250, maxAdsPerDay: 50 }03
Quickstart
The API is public, read-only and returns JSON. Ask what $1 of NVIDIA gets you right now:
curl "https://www.useslice.tech/api/quote?stock=NVDA&usd=1"Base URL is https://www.useslice.tech. Responses are cached for 30 seconds, CORS is open to every origin, and each IP gets 60 requests a minute per endpoint.
API
List stocks with live prices
GET/api/stocks
Every supported stock with its mint, current USD price, 24-hour change and the fraction one ad buys. No parameters.
curl "https://www.useslice.tech/api/stocks"const res = await fetch("https://www.useslice.tech/api/stocks")
if (!res.ok) throw new Error(`HTTP ${res.status}`)
const { stocks, readAt } = await res.json()
for (const s of stocks) {
console.log(s.ticker, s.priceUsd, `${s.unitsPerAd} per ad`)
}import requests
res = requests.get("https://www.useslice.tech/api/stocks", timeout=10)
res.raise_for_status()
for s in res.json()["stocks"]:
print(s["ticker"], s["priceUsd"], s["unitsPerAd"])| Name | Type | Description |
|---|---|---|
| symbol | string | Token symbol, e.g. NVDAx. |
| ticker | string | Underlying ticker, e.g. NVDA. |
| mint | string | SPL token mint address on Solana mainnet. |
| decimals | number | Token decimals. 8 for every xStock. |
| priceUsd | number | null | Jupiter Price API v3. Null if Jupiter has no price. |
| change24hPct | number | null | Price change over 24 hours, in percent. |
| exchangePriceUsd | number | null | Last price of the real share on its stock exchange. |
| gapPct | number | null | How far priceUsd sits above (+) or below (−) exchangePriceUsd. |
| liquidityUsd | number | null | On-chain pool liquidity in USD, as Jupiter reports it. |
| marketCapUsd | number | null | Market cap of the underlying company or fund. |
| unitsPerAd | number | null | How much of the token $0.50 buys at priceUsd. |
{
"readAt": "2026-09-27T14:16:33.767Z",
"earnPerAdUsd": 0.5,
"stocks": [
{
"symbol": "NVDAx",
"ticker": "NVDA",
"name": "NVIDIA",
"mint": "Xsc9qvGR1efVDFGLrVsmkzv3qi45LTBjeUKSPmx9qEh",
"decimals": 8,
"priceUsd": 225.08835302735343,
"change24hPct": 0.13174618878523983,
"exchangePriceUsd": 224.9975,
"gapPct": 0.04037957193010255,
"liquidityUsd": 3034823.4885465493,
"marketCapUsd": 5434765290000,
"unitsPerAd": 0.0022213499422568455
},
{
"symbol": "AAPLx",
"ticker": "AAPL",
"name": "Apple",
"mint": "XsbEhLAtcf6HdfpFZ5xEMdqW8nfAvcsP5bdudRLJzJp",
"decimals": 8,
"priceUsd": 340.79661466044877,
"change24hPct": 0.38784615676226736,
"exchangePriceUsd": 341.4603,
"gapPct": -0.1943667651997173,
"liquidityUsd": 592709.0972641185,
"marketCapUsd": 4977636972600,
"unitsPerAd": 0.0014671507241883046
},
…4 more
]
}API
Quote a USDC to stock swap
GET/api/quote?stock=NVDA&usd=1
A real Jupiter swap quote from USDC into a stock, including route, price impact and the minimum you would receive after 1% slippage. Quotes only: nothing is signed or sent.
| Name | Type | Description |
|---|---|---|
| stockrequired | string | Ticker, symbol or mint. One of NVDA, AAPL, TSLA, COIN, SPY, QQQ. |
| usd | string | Amount of USDC to swap, 0.01 to 10,000, up to 6 decimals. Defaults to 1. |
curl "https://www.useslice.tech/api/quote?stock=SPY&usd=10"async function quote(stock: string, usd: number) {
const url = new URL("/api/quote", "https://www.useslice.tech")
url.searchParams.set("stock", stock)
url.searchParams.set("usd", String(usd))
const res = await fetch(url)
const body = await res.json()
if (!res.ok) throw new Error(body.error.message)
return body as {
outputUnits: number
minOutputUnits: number
priceImpactPct: number
route: string
}
}
const q = await quote("SPY", 10)
console.log(`$10 buys ${q.outputUnits} SPYx via ${q.route}`)import requests
res = requests.get(
"https://www.useslice.tech/api/quote",
params={"stock": "SPY", "usd": "10"},
timeout=10,
)
body = res.json()
if not res.ok:
raise RuntimeError(body["error"]["message"])
print(f"$10 buys {body['outputUnits']} SPYx via {body['route']}"){
"readAt": "2026-09-27T14:16:33.768Z",
"stock": {
"symbol": "NVDAx",
"ticker": "NVDA",
"mint": "Xsc9qvGR1efVDFGLrVsmkzv3qi45LTBjeUKSPmx9qEh",
"decimals": 8
},
"inputUsd": 1,
"outputUnits": 0.00443475,
"minOutputUnits": 0.00439041,
"slippageBps": 100,
"priceImpactPct": 0.00017109804897001555,
"route": "Riptide",
"slot": 451021090
}API
TypeScript types
Copy these into your project for typed responses.
export type StocksResponse = {
readAt: string // ISO timestamp
earnPerAdUsd: number // 0.5
stocks: {
symbol: string // "NVDAx"
ticker: string // "NVDA"
name: string
mint: string // SPL mint address
decimals: number // 8 for every xStock
priceUsd: number | null
change24hPct: number | null
unitsPerAd: number | null
}[]
}
export type QuoteResponse = {
readAt: string
stock: { symbol: string; ticker: string; mint: string; decimals: number }
inputUsd: number
outputUnits: number
minOutputUnits: number // after 1% slippage
slippageBps: number
priceImpactPct: number
route: string // e.g. "Whirlpool"
slot: number // Solana slot the quote was read at
}
export type ApiError = { error: { code: string; message: string } }API
Errors and limits
Errors return a non-2xx status and a body of { error: { code, message } }. The message is written for humans; switch on the code.
| Name | Type | Description |
|---|---|---|
| 400 unknown_stock | client | The stock parameter did not match a supported ticker, symbol or mint. |
| 400 invalid_amount | client | usd was missing a number, negative, in exponent form, or outside 0.01 to 10000. |
| 429 rate_limited | retry | Over 60 requests a minute. Wait for the retry-after seconds. |
| 502 upstream_unavailable | retry | Jupiter did not answer in 4 seconds. Safe to retry. |
Every response carries x-ratelimit-limit and x-ratelimit-remaining. A small retry helper that respects both:
export async function getJson<T>(url: string, attempts = 3): Promise<T> {
for (let i = 0; i < attempts; i++) {
const res = await fetch(url)
if (res.ok) return res.json()
const retryable = res.status === 429 || res.status === 502
if (!retryable || i === attempts - 1) {
const { error } = await res.json()
throw new Error(`${error.code}: ${error.message}`)
}
const wait = Number(res.headers.get("retry-after") ?? 2 ** i)
await new Promise((r) => setTimeout(r, wait * 1000))
}
throw new Error("unreachable")
}Try it
Playground
Send real requests to this deployment. Pick the unsupported stock to see an error response.
Send a request to see the live response.
Recipe
Embed a price widget
No code needed: drop an iframe on any page and it shows a stock's live Jupiter price, today's move and how many ads one share takes. It refreshes every 30 seconds and links back here.
<iframe
src="https://www.useslice.tech/embed/nvda"
width="340"
height="200"
style="border:0;border-radius:20px"
title="NVIDIA live price"
loading="lazy"
></iframe>Recipe
Live prices in React
Poll /api/stocks with SWR. A 30 second interval matches the server cache, so faster polling only returns the same numbers.
"use client"
import useSWR from "swr"
const fetcher = (url: string) => fetch(url).then((r) => r.json())
export function StockPrice({ ticker }: { ticker: string }) {
const { data, isLoading } = useSWR("https://www.useslice.tech/api/stocks", fetcher, {
refreshInterval: 30_000, // matches the server cache
})
if (isLoading) return <span>…</span>
const stock = data?.stocks.find((s: { ticker: string }) => s.ticker === ticker)
return <span>{stock?.priceUsd?.toFixed(2) ?? "—"}</span>
}Recipe
Verify a mint on chain
Do not take our word for the addresses. Read the mint account from any Solana RPC and check it is a real token with 8 decimals.
import { Connection, PublicKey } from "@solana/web3.js"
const connection = new Connection("https://api.mainnet-beta.solana.com")
const mint = new PublicKey("Xsc9qvGR1efVDFGLrVsmkzv3qi45LTBjeUKSPmx9qEh") // NVDAx
const info = await connection.getParsedAccountInfo(mint)
const parsed = (info.value?.data as any)?.parsed
console.log(parsed.type) // "mint"
console.log(parsed.info.decimals) // 8
console.log(parsed.info.supply) // raw supply in base unitsRecipe
Quote Jupiter directly
Slice's quote endpoint is a thin wrapper. If you would rather skip it, this is the underlying call:
// The same quote, straight from Jupiter. No key needed.
const params = new URLSearchParams({
inputMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC
outputMint: "Xsc9qvGR1efVDFGLrVsmkzv3qi45LTBjeUKSPmx9qEh", // NVDAx
amount: String(1_000_000), // $1, USDC has 6 decimals
slippageBps: "100",
})
const q = await fetch(`https://lite-api.jup.ag/swap/v1/quote?${params}`).then((r) => r.json())
console.log(Number(q.outAmount) / 1e8, "NVDAx") // xStocks use 8 decimalsReference
Mint addresses
All tokens are issued by xStocks on Solana mainnet.
Reference
What is live
| Name | Type | Description |
|---|---|---|
| Prices and quotes | live | Read from Jupiter on every request, cached 30 seconds. |
| Public API | live | The endpoints on this page, free and keyless. |
| Ad player | preview | Runs the real 30 second flow with a stand-in clip. No advertiser is booked. |
| Payouts | live | Claims are paid from a public treasury capped at $1,000 a day, each with a receipt. |
Slice




