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

# RareIndex Public API (v1)

Base URL (production): https://www.rareindex.io/api/v1 — the web app proxies /api/v1/* to the Fastify service (apps/api, port API_PORT, default 8211). Direct access in development: http://localhost:8211/v1. Machine-readable contract: GET /v1/openapi.json (also docs/openapi.json).

# Authentication & tiers

Authorization: Bearer ri_live_<prefix>_<secret>. Requests without a key use the public tier. Only the SHA-256 hash of a key is stored (api_keys.key_hash); mint keys with

text
pnpm --filter @rareindex/api create-key -- --name "Research desk" --tier professional [--user usr_…]
Tier req/min req/day
public (no key) 20 500
free 60 1 000
hobby 120 10 000
professional 600 100 000
research 600 250 000
enterprise 3 000 5 000 000

Rate-limit headers: x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset; every response carries x-request-id. Usage is counted per key/day/endpoint in api_usage.

# Conventions

  • Envelope: { "data": …, "meta": { "count", "cursor", "as_of", "attribution", … } }.
  • Pagination: limit (≤ 200) + opaque cursor (from meta.cursor, null when exhausted).
  • Errors: RFC 9457 application/problem+json (title, status, detail, instance, request_id).
  • Export: add ?format=csv on list endpoints for a flat CSV download.
  • Caching: read endpoints send cache-control and weak ETags; gzip/brotli negotiated.
  • Money: price + currency are the native transaction values; price_usd uses the FX rate of the transaction date. Valuations (riv_usd, riv_low_usd, riv_high_usd) always come with riv_confidence and riv_sample_size. Listing prices are asks, never transactions.
  • Attribution is required (see meta.attribution).

# Endpoints

Method & path Purpose
GET /v1/assets/search?q&category&limit&cursor Search canonical assets (FTS + trigram + identifiers)
GET /v1/assets/{idOrSlug} Asset detail: attributes, stats, variants with their own valuations, latest valuation, sources
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)
GET /v1/assets/{id}/listings?availability Listings (asks) with discount_to_riv
GET /v1/assets/{id}/history?variant&from&to Daily series: RIV, latest sale, median, sales count, volume, listings, min ask
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
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
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
GET /v1/categories Taxonomy with tracked asset counts
GET /v1/indices RARE + subindices: latest value, 1d/7d/30d/YTD/1y changes, breadth, market cap estimate + confidence; published=false until breadth threshold
GET /v1/indices/{ticker}/history?from&to Index history
GET /v1/markets Latest category snapshot per family
GET /v1/markets/{slug} Market detail: counts, gainers/losers (≥ 3 sales), most valuable, most liquid, recent sales, history
GET /v1/trending?category Assets ranked by trending score
GET /v1/sales/latest?category&min_usd Latest observed sales across the platform
GET /v1/records Highest verified sale per family (bundles and low-confidence excluded)
GET /v1/stats Platform counts
GET /healthz Liveness (DB ping)

# Internal endpoints (loopback only)

POST /internal/lookup { url } and GET /internal/lookup/sources are used by the web Scanner to resolve a marketplace URL through the connector framework (connector modules are loaded dynamically, which the Next.js bundler cannot do). Auth: header x-internal-token = HMAC-SHA256(SESSION_SECRET, "internal"), and the caller must be 127.0.0.1.

# Running

text
pnpm --filter @rareindex/api dev      # tsx watch, port 8211
pnpm --filter @rareindex/api start
pnpm --filter @rareindex/api test     # fastify.inject integration tests against DATABASE_URL
pnpm --filter @rareindex/api exec tsx scripts/gen-openapi.ts   # refresh docs/openapi.json

Environment: DATABASE_URL, API_PORT, API_HOST (default 127.0.0.1 — put it behind the web proxy), SESSION_SECRET (shared with the web app for internal calls), FIRECRAWL_API_KEY/SCRAPFLY_API_KEY (URL lookups), LOG_LEVEL.