Skip to content

Integrate

TypeScript SDK

@fomoquant/sdk is a zero-dependency, fully typed client: fetch, global WebSocket and WebCrypto only. Responses are typed snake_case objects identical to the REST JSON.

Install

pnpm add @fomoquant/sdk

Runs in Node ≥ 22, Bun, Deno, Cloudflare Workers / Vercel Edge and browsers (keep keys out of browsers you do not control — anything shipped to a browser is public).

Create a client

TypeScript
import { FomoQuant } from "@fomoquant/sdk";

const fq = new FomoQuant({
  apiKey: process.env.FOMOQUANT_API_KEY!, // fq_live_…
  baseUrl: "https://fomoquant.app",
});

Options

NameDescription
apiKeyrequired
string
fq_live_… (live dataset).
baseUrl
string
API origin (this deployment: https://fomoquant.app).Default https://fomoquant.app
streamUrl
string
Pin the WebSocket URL. By default stream() discovers it from GET {baseUrl}/v1/stream/info before every (re)connect.
fetch
typeof fetch
Custom fetch (tests, proxies).
timeoutMs
number
Per-request timeout.Default 30000
maxRetries
number
Automatic retries on 429 honouring Retry-After (max 5).Default 2
  • apiKeystringrequired
    fq_live_… (live dataset).
  • baseUrlstring
    API origin (this deployment: https://fomoquant.app).
    Default https://fomoquant.app
  • streamUrlstring
    Pin the WebSocket URL. By default stream() discovers it from GET {baseUrl}/v1/stream/info before every (re)connect.
  • fetchtypeof fetch
    Custom fetch (tests, proxies).
  • timeoutMsnumber
    Per-request timeout.
    Default 30000
  • maxRetriesnumber
    Automatic retries on 429 honouring Retry-After (max 5).
    Default 2

Methods

tokens

  • fq.tokens.get(ref)TokenQuant

    Quant snapshot. ref: "$XYZ", "XYZ", "tk_…", "<chain>:<address>" or "<address>". Reference

  • fq.tokens.list({ sort?, dir?, limit?, cursor?, narrative?, chain?, q? })List<TokenRow>

    Tokens with current scores. Reference

  • fq.tokens.analogs(ref, { k? })TokenAnalogs

    Nearest historical setups (no lookahead). Reference

  • fq.scanner.run({ preset?, rules?, sort?, sort_dir?, limit?, chains?, narrative? })ScanResult

    Run scanner rules; null values never pass. Reference

signals

  • fq.signals.list({ min_score?, signal_type?, chain?, market_cap?, liquidity?, created_after?, status?, token?, limit?, cursor? })List<Signal>

    The signal feed. min_score accepts { field, value } or "momentum:70". Reference

  • fq.signals.get(id)SignalDetail

    Conditions, feature snapshot, analogs, prior firings, rule doc. Reference

  • fq.signals.iterate(params)AsyncGenerator<Signal>

    Every matching signal across pages.

users, cohorts, narratives

  • fq.users.get(handle)UserQuant

    Point-in-time author metrics. Leading @ is optional. Reference

  • fq.cohorts.list({ kind? })List<Cohort>

    Algorithmic cohorts plus your own. Reference

  • fq.cohorts.get(id)Cohort

    Members, activity, convergence events. Reference

  • fq.narratives.list()List<Narrative>

    Narrative map. Reference

  • fq.narratives.get(slug)Narrative

    One narrative. Reference

  • fq.narratives.rotation({ window? })NarrativeRotation

    Attention-share change (24h | 7d). Reference

  • fq.narratives.heatmap({ metric?, bucket?, range? })NarrativeHeatmap

    Narrative × time matrix. Reference

research

  • fq.backtests.create({ rules, horizon, name?, from?, to?, cooldown?, dead_token_policy?, universe? })BacktestRun

    Queue a backtest (202). Scope backtests:write, Pro / Team. Reference

  • fq.backtests.get(id)BacktestRun

    Current state of a run. Reference

  • fq.backtests.wait(id, { intervalMs?, timeoutMs?, signal? })BacktestRun

    Poll with backoff until done or failed (default timeout 5 min).

  • fq.eventStudies.list()List<EventStudy>

    All event studies. Reference

  • fq.eventStudies.get(slug)EventStudy

    One event study. Reference

webhooks & realtime

  • fq.webhooks.create({ url, events })WebhookCreated

    Register an endpoint; secret returned once. Reference

  • fq.webhooks.list()List<Webhook>

    Webhooks for this key's dataset. Reference

  • fq.webhooks.delete(id)Deleted

    Delete a webhook. Reference

  • fq.webhooks.test(id)WebhookTestResult

    Send a signed webhook.test now. Reference

  • fq.stream({ events, tokens?, onEvent, onError? })StreamHandle

    WebSocket stream with automatic reconnect + resubscribe; handle.close(). Reference

  • FomoQuant.verifyWebhook(secret, rawBody, signatureHeader, toleranceSec?)Promise<WebhookEvent>

    Static. Verify and parse a delivery (default tolerance 300 s). Reference

meta & helpers

  • fq.key()KeyInfo

    Mode, dataset, scopes, rate limit and plan of the key. Reference

  • fq.models()ModelCatalog

    Score and signal definitions and versions. Reference

  • fq.health()Health

    Provider status, freshness and the current stream URL. Reference

  • fq.streamInfo()StreamInfo

    Where the realtime WebSocket lives right now (stream() resolves it for you). Reference

  • fq.paginate(fetchPage)AsyncGenerator<T>

    Iterate any cursor-paginated list.

  • fq.request(method, path, { query?, body?, signal? })Promise<T>

    Low-level call with auth, retries and typed errors.

  • fq.lastResponseRequestMeta | null

    Status, request id and rate-limit headers of the last response.

  • fq.mode"live" | "test"

    Derived from the key prefix.

Pagination

Lists return { object: "list", data, has_more, next_cursor }. Pass cursor to continue, or iterate:

TypeScript
for await (const s of fq.signals.iterate({ signal_type: ["EARLY_ACCELERATION"] })) {
  console.log(s.token.symbol, s.fired_at, s.analogs?.n);
}

// any list
for await (const t of fq.paginate((cursor) => fq.tokens.list({ sort: "momentum", cursor }))) {
  console.log(t.token.symbol, t.scores.momentum);
}

Errors & retries

TypeScript
import { FomoQuantError } from "@fomoquant/sdk";

try {
  await fq.tokens.get("$NOPE");
} catch (e) {
  if (e instanceof FomoQuantError) console.log(e.status, e.code, e.message, e.requestId);
}

FomoQuantError carries code, status, message, requestId, details and retryAfter. Codes mirror the API (error table) plus NETWORK and TIMEOUT (status 0). 429 responses are retried automatically up to maxRetries, waiting for Retry-After.

Realtime stream

TypeScript
const stream = fq.stream({
  events: ["signal.created", "score.updated", "cohort.convergence", "narrative.shift"],
  tokens: ["$XYZ"], // optional; applies to token-scoped events
  onEvent(ev) {
    if (ev.event === "score.updated") console.log(ev.data.symbol, ev.data.scores.momentum);
  },
  onError: (err) => console.warn(err.code, err.message),
});

// later
stream.close();

Requires scope stream:read. The realtime host is separate from the REST API and its address can change, so stream() resolves it from /v1/stream/info before every (re)connect; while that host is offline you get a STREAM_UNAVAILABLE error in onError and the SDK keeps retrying with backoff. The connection receives only the key's dataset, reconnects with backoff and resubscribes. In Node the key travels in the Authorization header; browsers cannot set headers, so the SDK uses ?key= there — use a key that has only the stream:read scope. Protocol details are in the API reference.

Webhooks

Use FomoQuant.verifyWebhook(secret, rawBody, signatureHeader) on the raw request body; it throws on a bad or stale signature and returns the typed event. See Webhooks.

FomoQuant provides analytics and historical/statistical context, not financial advice or guaranteed predictions.