SPB Git forge

spb/rareindex

Public
54commits 1branches 0releases
7.1 MBsize
maindefault branch
10 days agolast push
TypeScript 61.9% HTML 37.2% SQL 0.7%
5.1 KB · 82 lines markdown
Rendered Raw Blame History
1# RareIndex Public API (v1)23Base URL (production): `https://www.rareindex.io/api/v1` — the web app proxies `/api/v1/*` to the4Fastify service (`apps/api`, port `API_PORT`, default 8211). Direct access in development:5`http://localhost:8211/v1`. Machine-readable contract: `GET /v1/openapi.json` (also `docs/openapi.json`).67## Authentication & tiers89`Authorization: Bearer ri_live_<prefix>_<secret>`. Requests without a key use the **public** tier.10Only the SHA-256 hash of a key is stored (`api_keys.key_hash`); mint keys with1112```13pnpm --filter @rareindex/api create-key -- --name "Research desk" --tier professional [--user usr_…]14```1516| Tier | req/min | req/day |17|---|---|---|18| public (no key) | 20 | 500 |19| free | 60 | 1 000 |20| hobby | 120 | 10 000 |21| professional | 600 | 100 000 |22| research | 600 | 250 000 |23| enterprise | 3 000 | 5 000 000 |2425Rate-limit headers: `x-ratelimit-limit`, `x-ratelimit-remaining`, `x-ratelimit-reset`; every response26carries `x-request-id`. Usage is counted per key/day/endpoint in `api_usage`.2728## Conventions2930- Envelope: `{ "data": …, "meta": { "count", "cursor", "as_of", "attribution", … } }`.31- Pagination: `limit` (≤ 200) + opaque `cursor` (from `meta.cursor`, `null` when exhausted).32- Errors: RFC 9457 `application/problem+json` (`title`, `status`, `detail`, `instance`, `request_id`).33- Export: add `?format=csv` on list endpoints for a flat CSV download.34- Caching: read endpoints send `cache-control` and weak ETags; gzip/brotli negotiated.35- Money: `price` + `currency` are the native transaction values; `price_usd` uses the FX rate of the36  transaction date. Valuations (`riv_usd`, `riv_low_usd`, `riv_high_usd`) always come with37  `riv_confidence` and `riv_sample_size`. Listing prices are asks, never transactions.38- Attribution is required (see `meta.attribution`).3940## Endpoints4142| Method & path | Purpose |43|---|---|44| `GET /v1/assets/search?q&category&limit&cursor` | Search canonical assets (FTS + trigram + identifiers) |45| `GET /v1/assets/{idOrSlug}` | Asset detail: attributes, stats, variants with their own valuations, latest valuation, sources |46| `GET /v1/assets/{id}/sales?variant&include_flagged` | Observed sales (valid only by default); `all_in_usd` = buyer-pays price (hammer + premium per `fee_basis`) |47| `GET /v1/assets/{id}/listings?availability` | Listings (asks) with `discount_to_riv` |48| `GET /v1/assets/{id}/history?variant&from&to` | Daily series: RIV, latest sale, median, sales count, volume, listings, min ask |49| `GET /v1/assets/{id}/depth?variant` | Market depth (asks within ±5/10/20 % of RIV, below/above, best & median ask, RareIndex spread), days on market (sold vs withdrawn), median time-to-sale by asking band (≤ 90 %, 90–100 %, 100–110 %, > 110 % of RIV; null under 5 observations), fair buy/sell ladder. `liquidation.level` is `category` when the asset has < 10 completed lifecycles. Model estimates, not advice |50| `GET /v1/assets/{id}/auctions?status` | Auction lots for an asset with native, USD and all-in (buyer-pays) amounts, `fee_basis`, `bid_vs_riv` / `estimate_vs_riv` and `assessment_verdict` |51| `GET /v1/auctions/lots?status&ending_within_hours&category&house&below_riv&asset&sort` | Live/upcoming lots across houses: current bid or low estimate + the house's buyer premium (published, ≈ estimated or default 22 %) compared with the RIV of the lot's own variant through the ask gates. `below_riv=true` keeps verdict `deal` only. Taxes, duties and shipping excluded; bids are not transactions |52| `GET /v1/categories` | Taxonomy with tracked asset counts |53| `GET /v1/indices` | RARE + subindices: latest value, 1d/7d/30d/YTD/1y changes, breadth, market cap estimate + confidence; `published=false` until breadth threshold |54| `GET /v1/indices/{ticker}/history?from&to` | Index history |55| `GET /v1/markets` | Latest category snapshot per family |56| `GET /v1/markets/{slug}` | Market detail: counts, gainers/losers (≥ 3 sales), most valuable, most liquid, recent sales, history |57| `GET /v1/trending?category` | Assets ranked by trending score |58| `GET /v1/sales/latest?category&min_usd` | Latest observed sales across the platform |59| `GET /v1/records` | Highest verified sale per family (bundles and low-confidence excluded) |60| `GET /v1/stats` | Platform counts |61| `GET /healthz` | Liveness (DB ping) |6263## Internal endpoints (loopback only)6465`POST /internal/lookup { url }` and `GET /internal/lookup/sources` are used by the web Scanner to66resolve a marketplace URL through the connector framework (connector modules are loaded67dynamically, which the Next.js bundler cannot do). Auth: header `x-internal-token` =68HMAC-SHA256(`SESSION_SECRET`, `"internal"`), and the caller must be 127.0.0.1.6970## Running7172```73pnpm --filter @rareindex/api dev      # tsx watch, port 821174pnpm --filter @rareindex/api start75pnpm --filter @rareindex/api test     # fastify.inject integration tests against DATABASE_URL76pnpm --filter @rareindex/api exec tsx scripts/gen-openapi.ts   # refresh docs/openapi.json77```7879Environment: `DATABASE_URL`, `API_PORT`, `API_HOST` (default 127.0.0.1 — put it behind the web proxy),80`SESSION_SECRET` (shared with the web app for internal calls), `FIRECRAWL_API_KEY`/`SCRAPFLY_API_KEY`81(URL lookups), `LOG_LEVEL`.82