Concrete — Complete GuideIndependent guide, unofficial

For developers

Public API

Every endpoint below is the same JSON API this site's own pages call — nothing held back for a private tier. All are read-only GET requests, unauthenticated, no API key. There's no SLA: this is a community-run site, not Concrete's own infrastructure, so treat it as best-effort and cache aggressively on your end.

Base URL

https://concrete-guide-six.vercel.app

Auth

None. Don't send wallet private keys or signatures — every endpoint here only ever reads public on-chain / public API data.

Rate limits

Unposted routes (market/gas/vaults/etc.) have no explicit limit but are cached at the edge. Write-adjacent read routes (reviews, quiz leaderboard) are limited per-IP — expect a 429 with a short cooldown if you poll too fast.

Errors

Non-2xx responses return { status: "error", message } or, for a missing/invalid query param, { error: "..." }. Some endpoints return { status: "not_configured" } (200) when the underlying store — e.g. reviews, quiz leaderboard — isn't set up on this deployment, rather than a 4xx/5xx.

GET/api/vault

A wallet's live position (shares held, underlying value, share price) in one or more vaults on one chain.

ParamRequiredDescription
walletyesA checksummable 0x address.
chainnoethereum (default), arbitrum, or base.
vaultsyesComma-separated vault (ERC-4626) addresses.

Example

GET https://concrete-guide-six.vercel.app/api/vault?wallet=0xabc...&chain=ethereum&vaults=0x0e60...,0xacce...

Response shape

{ vaults: [{ vaultAddress, name, symbol, underlyingSymbol, sharesHeldFormatted, underlyingValueFormatted, totalAssetsFormatted, sharePrice, blockNumber, error? }], warnings? }

Freshness: no-store — always reads the current block.

GET/api/vaults

Every vault in this app's known-vault list, read live on-chain — no wallet needed. Powers the home vault dashboard.

Example

GET https://concrete-guide-six.vercel.app/api/vaults

Response shape

{ fetchedAt, chains: [{ chain, blockNumber }], vaults: LiveVaultResult[] }

Freshness: no-store.

GET/api/points

A wallet's Fuul points total, rank, and (when Fuul's response includes it) a per-campaign breakdown.

ParamRequiredDescription
walletyesA checksummable 0x address.

Example

GET https://concrete-guide-six.vercel.app/api/points?wallet=0xabc...

Response shape

{ wallet, status: "ok" | "not_configured" | "error", totals }

Freshness: no-store.

GET/api/leaderboard

The Fuul points leaderboard — top wallets by points, plus total participant count.

ParamRequiredDescription
limitno1–1000, default 1000.

Example

GET https://concrete-guide-six.vercel.app/api/leaderboard?limit=100

Response shape

{ status: "ok", rows: [{ rank, wallet, points }], totalUsers }
GET/api/market

The Vault Terminal's market snapshot for all 4 modeled vaults: APY, TVL, daily yield, and ETH/BTC prices, with source labelled (live / partial / rpc / simulated).

Example

GET https://concrete-guide-six.vercel.app/api/market

Response shape

{ vaults: Record<VaultId, {apy, tvl, dailyYield}>, prices: {WETH, WBTC, USDC, FRAX, USD1, WSTETH}, source, ts }

Freshness: CDN-cached 60s; source chain is app.concrete.xyz → DefiLlama → ETH RPC → simulated fallback.

GET/api/gas

Current Ethereum mainnet gas price (eth_gasPrice), server-proxied so the browser never hits a public RPC directly.

Example

GET https://concrete-guide-six.vercel.app/api/gas

Response shape

{ gwei, source: "live" | "simulated", ts }

Freshness: 30s.

GET/api/ens

Reverse-resolves an address to its ENS name, if any.

ParamRequiredDescription
addressyesA checksummable 0x address.

Example

GET https://concrete-guide-six.vercel.app/api/ens?address=0xabc...

Response shape

{ address, name: string | null }

Freshness: 5 min in-memory per serverless instance.

GET/api/ct-price

$CT token price from CoinGecko by contract address. Returns { trading: false } honestly until $CT actually lists — not an error state.

Example

GET https://concrete-guide-six.vercel.app/api/ct-price

Response shape

{ trading: false } | { trading: true, usd, usdMarketCap, ts }

Freshness: 60s.

GET/api/vault-reviews

Community upvote/downvote + short-comment reviews for one of the Vault Terminal's 4 modeled vaults.

ParamRequiredDescription
vaultIdyesweeth, ctwbtc, ctusd, frxusd, frontier, rwausd1, srroyusdc, or royeth.
limitno1–100, default 30.
clientIdnoYour own anonymous client id, to get yourReview back.

Example

GET https://concrete-guide-six.vercel.app/api/vault-reviews?vaultId=ctusd&limit=30

Response shape

{ status: "ok" | "not_configured" | "error", upvotes, downvotes, reviews: [{name, vote, comment, updatedAt}], yourReview }

Freshness: 15s.

GET/api/quiz-leaderboard

The Concrete-knowledge quiz's leaderboard.

ParamRequiredDescription
limitno1–200, default 50.

Example

GET https://concrete-guide-six.vercel.app/api/quiz-leaderboard?limit=50

Response shape

{ status: "ok", rows: [{ rank, name, weightedScore, totalCorrect, tierKey, streak }] }
GET/api/alert-check

Stateless: reads a vault's live share price and, if a threshold is currently crossed, POSTs a payload to your webhook URL. Add &format=discord to send a ready-to-post Discord message body instead of raw JSON.

ParamRequiredDescription
vaultyesVault (ERC-4626) address.
chainnoethereum (default), arbitrum, or base.
directionnoabove (default) or below.
thresholdyesNumeric share-price threshold.
webhooknoURL to POST to when crossed (Slack/Discord/Zapier/your own).
formatnoraw (default) or discord.

Example

GET https://concrete-guide-six.vercel.app/api/alert-check?vault=0x0e60...&threshold=1.05&webhook=https://hooks.slack.com/...

Response shape

{ vault, chain, sharePrice, threshold, direction, crossed, webhook, checkedAt }

Freshness: Always live. Re-fires every check while the condition holds — point a cron at it, and have your receiver de-duplicate, or use the Telegram bot below for built-in dedup.

Telegram alerts bot

A stateful alternative to /api/alert-check above: message a Telegram bot directly and it remembers your watches, checking on a cron and pinging you only when a threshold is newly crossed (not on every tick).

Commands (DM the bot)

  • /watchprice <chain> <vault_address> <above|below> <price>
  • /watchapy <weeth|ctwbtc|ctusd|frxusd|frontier|rwausd1|srroyusdc|royeth> <above|below> <apy>
  • /watchct <above|below> <usd_price>
  • /myalerts · /unwatch <id> · /stop · /help

Running your own instance

  1. Create a bot with @BotFather and set TELEGRAM_BOT_TOKEN in your deployment's environment.
  2. Set KV_REST_API_URL / KV_REST_API_TOKEN (Vercel KV) or UPSTASH_REDIS_REST_URL / UPSTASH_REDIS_REST_TOKEN — subscriptions are stored there. Free tier is plenty.
  3. Register the webhook once, from anywhere, by visiting:https://api.telegram.org/bot<TOKEN>/setWebhook?url=https://concrete-guide-six.vercel.app/api/telegram-webhook
  4. Optionally set TELEGRAM_CRON_SECRET to any string, then point a free external cron (cron-job.org, EasyCron, a GitHub Actions schedule) at:https://concrete-guide-six.vercel.app/api/telegram-check?secret=<TELEGRAM_CRON_SECRET>every 2–5 minutes. Without the secret set, the endpoint works unauthenticated — fine for low-traffic personal use.

Without a Telegram bot, use /api/alert-check's webhook param with any Slack/Discord/Zapier URL instead — no bot token needed.

Nothing here is versioned yet — paths and response shapes can change as the app evolves. If you're building something that depends on one of these, open an issue (or a PR) on GitHub so a breaking change doesn't surprise you.

Looking for Concrete's own protocol data (not this guide's cached copies)? See the SDK guide and subgraph & events doc pages.