Skip to content
FireFutures

OPEN API · V1

Connect market data, checkups, and signals to your systems

This guide covers interfaces implemented in the current code: API Key and session authentication, consistent errors, pagination and rate limits, per-coin data, signed Webhooks, and Centrifugo realtime subscriptions.

Endpoint, parameter, and field tables read packages/api-client/openapi.json from this repository at build time, with authentication and business boundaries checked against platform routes. The page is static, makes no online requests, and does not assert that any external hostname has passed acceptance testing.

Quickstart

Create an API Key with only the scopes you need, then configure environment variables on a trusted server or in a local quantitative program. Never put the Key in source code, browser pages, logs, or a WS URL.

  1. Set API_BASE to the API root of your actual deployment, without a trailing slash. This guide does not assume an online address for you.
  2. Store FF_API_KEY in a secure environment variable or secret manager, and set ACCEPT_LANGUAGE to zh-CN, zh-TW, or en.
  3. Call a minimal read-only endpoint and inspect the HTTP status, problem+json errors, and RateLimit response headers before expanding the integration.
curl
curl --fail-with-body "${API_BASE}/v1/public/coins/BTCUSDT" \
  -H "Authorization: Bearer ${FF_API_KEY}" \
  -H "Accept-Language: ${ACCEPT_LANGUAGE}"

Example responses illustrate JSON shapes, not live market data, performance, or returns. Assess production availability through your own deployment and health checks.

Authentication and API Key scopes

Open endpoints use Authorization: Bearer <API-Key>. Keys start with ffk_live_ or ffk_test_. The plaintext is shown once at creation; the platform stores only its hash and prefix. The Quant entitlement api.enabled is checked again on every authentication.

A Key can have a CIDR IP allowlist. Grant minimum scopes, keep environment-specific Keys separate, and revoke a Key when it is exposed or no longer used. Anonymous endpoints neither need nor should receive a Key.

API Key scopes
ScopeAllowed operations
read:marketPublic coin state, radar lists, calibration, and market realtime channel tokens.
read:checkupRead checkup archives owned by the Key's user; never reports owned by another user.
read:signalsOfficial signal lists and sig:{stream_code} realtime channels.
webhooks:manageCreate, list, and revoke Webhook endpoints and read their deliveries.
export:dataMarket-state and signal CSV exports; the Key's user must also have data.export=full.

Forged, expired, revoked, or IP-rejected credentials return 401/403. Insufficient scope returns 403 FORBIDDEN; losing the API entitlement returns 402 ENT_FEATURE_LOCKED. /v1/me/api-keys creation, listing, and revocation use the user session, not another API Key.

Cookie sessions, CSRF, and idempotency

Browser Cookie session writes use double-submit validation: X-CSRF-Token must match the ff_csrf Cookie. Obtain a CSRF token first, then send it to session write endpoints such as API Key creation. Login rotates the token, so always use the latest value.

curl
curl --cookie-jar cookies.txt "${API_BASE}/v1/auth/csrf"

curl --request POST "${API_BASE}/v1/me/api-keys" \
  --cookie cookies.txt --cookie-jar cookies.txt \
  -H "Content-Type: application/json" \
  -H "X-CSRF-Token: ${CSRF_TOKEN}" \
  --data '{"name":"local-bot","scopes":["read:market"],"ip_allowlist":[]}'

cookies.txt and CSRF_TOKEN are local placeholders. Requests authorized with an API Key generally skip CSRF. The Cookie refresh-token flow is the documented exception; do not generalize that exception to every Bearer request.

Idempotent writes

Designated writes such as orders, payments, subscription changes, and withdrawals require a client-generated UUID in Idempotency-Key. A scope and Key pair is retained for 24 hours: replaying the same request returns the first response. Never reuse a Key with a different body.

HTTP
Idempotency-Key: ${IDEMPOTENCY_KEY}

The same Key with a different request returns 422 IDEMPOTENCY_KEY_REUSED. If the first request is still running, the response is 409 IDEMPOTENCY_IN_PROGRESS. Send the header only to endpoints that explicitly require it; do not turn read-only calls into writes.

REST errors: application/problem+json

Success responses return a resource or list directly, without a {code,data} wrapper. Errors follow RFC 9457. Clients should inspect both HTTP status and the stable code. title and detail may be localized through Accept-Language and must not drive program logic.

JSON
{
  "type": "<api-base>/errors/RATE_LIMITED",
  "title": "<localized-title>",
  "status": 429,
  "code": "RATE_LIMITED",
  "detail": "<localized-detail>",
  "instance": "/v1/public/coins/BTCUSDT",
  "request_id": "<request-id>",
  "meta": { "bucket": "api_key" }
}
Common error codes
Error codeHTTPMeaning and handling
AUTH_UNAUTHENTICATED401Missing, invalid, or revoked authentication. Check credentials instead of retrying indefinitely.
FORBIDDEN403Insufficient scope, IP access, or resource permission. Fix authorization rather than varying the request.
ENT_FEATURE_LOCKED / ENT_QUOTA_EXCEEDED402The feature is not entitled or quota is exhausted. Inspect entitlement or reset information in meta.
NOT_FOUND / MARKET_COIN_NOT_FOUND404The resource or coin does not exist. Check path parameters and symbols.
VALIDATION_FAILED422Invalid parameters, body, cursor, or time window. Correct the fields identified in meta.errors.
IDEMPOTENCY_IN_PROGRESS409The same idempotent request is still running. Query later or retry with the original Key.
RATE_LIMITED429A rate limit was reached. Honor Retry-After and reduce concurrency or request frequency.
DEPENDENCY_UNAVAILABLE503A dependency is temporarily unavailable. Retry with bounded backoff; never fabricate successful data.

For 422 VALIDATION_FAILED, meta.errors is an array of {field,code,message}. Use request_id when contacting support. Errors deliberately omit SQL, stack traces, raw third-party responses, and secrets.

Rate limits, pagination, time, and amounts

Rate limits

API Key REST calls use a 60-second api.rate_per_min token bucket keyed by the Key, so changing IP does not change the bucket. Anonymous public endpoints have separate IP buckets with potentially different limits. Charged requests may return RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset after either success or a business error; 429 also includes Retry-After.

RateLimit-Limit · RateLimit-Remaining · RateLimit-Reset · Retry-After

Cursor pagination

For regular lists, limit defaults to 20 and has a maximum of 100. When next_cursor is non-null, pass it back unchanged as cursor. Cursors are opaque: do not decode or construct them. Radar and predictions have their own schema limits, and short lists or CSV responses are not necessarily paginated.

JSON
{
  "items": [],
  "next_cursor": "<opaque-cursor-or-null>"
}

Time, amounts, and numbers

Time input and output use ISO 8601 UTC, with Z on output. CSV windows are [from,to) and can span at most 31 days. JSON fields use snake_case. Missing values remain null and are never replaced with zero.

Numeric representation
Data kindRule
Platform ledger amountsDecimal strings such as 39.000000. Never use binary floating point for amount calculations.
Trading prices and notional valuesTrading-related amounts and prices use strings; display-only market fields may use number when the schema says so.
_pct / _ratio / _scoreThese suffixes mean percentage, decimal ratio, and score respectively. A _pct value of 12.5 means 12.5%; a score is not a probability.
TimeISO 8601 UTC, for example 2026-10-28T00:00:00Z. Business days start at 00:00 UTC.

Per-coin checkups

The anonymous quick check returns six fields. It requires no login, consumes no full-checkup quota, and writes no archive. A separate IP limit may apply. sentence is generated in the requested language.

GET

/v1/public/checkup/symbols/{symbol}

operationId
checkup_public_symbol_get
Authentication
Anonymous; a separate IP rate limit may apply
Success response
200 · application/json

Request parameters

API field table: GET /v1/public/checkup/symbols/{symbol}
FieldLocationTypeRequirementConstraintsDescription
symbolpathstringRequired—Canonical engine coin symbol, for example BTCUSDT.

Response fields

API field table: GET /v1/public/checkup/symbols/{symbol}
FieldTypeRequirementConstraintsDescription
as_ofstringRequired—Cutoff of the data visible in this response; may be null.
gradestringRequired—Checkup grade A–E; not calculated by the client.
sentencestringRequired—One-sentence checkup summary in the requested language.
stagestringRequired—Engine lifecycle stage code.
stalebooleanRequired—Whether the data is not current. true should be visible to users.
symbolstringRequired—Canonical engine coin symbol, for example BTCUSDT.
curl
curl --fail-with-body "${API_BASE}/v1/public/checkup/symbols/BTCUSDT" \
  -H "Accept-Language: ${ACCEPT_LANGUAGE}"
JSON
{
  "symbol": "BTCUSDT",
  "grade": "B",
  "stage": "accumulation",
  "sentence": "<localized-summary>",
  "stale": false,
  "as_of": "2026-10-28T00:00:00Z"
}

The JSON above is a shape example, not BTC's current grade or stage. Use the actual response's as_of and stale values to communicate freshness.

Checkup archives and full checks

A Key with read:checkup can access only its user's reports: read an archive by report_id; get the coin's latest archive through GET /v1/public/checkups/{symbol}/latest; or run a full check through GET /v1/public/checkups/{symbol}?depth=full. pro=true requests professional fields; backend entitlements and content still determine visibility. locked, sections, and pro cannot be unlocked by the client.

GET

/v1/public/checkup/reports/{report_id}

operationId
checkup_public_report_get
Authentication
Bearer API Key · read:checkup
Success response
200 · application/json

Request parameters

API field table: GET /v1/public/checkup/reports/{report_id}
FieldLocationTypeRequirementConstraintsDescription
report_idpathstringRequireduuidReport UUID. The open archive endpoint also verifies ownership.
proquerybooleanOptionaldefault=falseWhether to request professional-mode fields; defaults to false.

Response fields

API field table: GET /v1/public/checkup/reports/{report_id}
FieldTypeRequirementConstraintsDescription
anomaly_countintegerRequired—Number of anomalous items in the report or section.
as_ofstringOptional · Nullabledate-timeCutoff of the data visible in this response; may be null.
cycle_atstringOptional · Nullabledate-timeEngine cycle that produced this data.
depthstringRequiredquick | fullCheckup depth: quick or full.
formula_versionstringRequired—Formula version used to produce the report.
gradestringRequired—Checkup grade A–E; not calculated by the client.
lockedbooleanRequired—Whether this report is locked by entitlements.
long_riskintegerRequired—Long-risk score, not a probability.
metaobjectRequired—Additional endpoint-defined metadata object.
proProOutOptional · Nullable—Whether to request professional-mode fields; defaults to false.
report_idstringOptional · NullableuuidReport UUID. The open archive endpoint also verifies ownership.
sectionsarray<SectionOut>Required—Checkup report sections, each with ready, empty, or locked status.
short_riskintegerRequired—Short-risk score, not a probability.
sourcestringRequiredmarket | gatewayData source or CSV record granularity.
stagestringRequired—Engine lifecycle stage code.
stalebooleanRequired—Whether the data is not current. true should be visible to users.
symbolstringRequired—Canonical engine coin symbol, for example BTCUSDT.
curl
curl --fail-with-body "${API_BASE}/v1/public/checkup/reports/${REPORT_ID}?pro=false" \
  -H "Authorization: Bearer ${FF_API_KEY}" \
  -H "Accept-Language: ${ACCEPT_LANGUAGE}"
GET

/v1/public/checkups/{symbol}/latest

operationId
checkup_public_symbol_latest
Authentication
Bearer API Key · read:checkup
Success response
200 · application/json

Request parameters

API field table: GET /v1/public/checkups/{symbol}/latest
FieldLocationTypeRequirementConstraintsDescription
symbolpathstringRequired—Canonical engine coin symbol, for example BTCUSDT.
proquerybooleanOptionaldefault=falseWhether to request professional-mode fields; defaults to false.

Response fields

API field table: GET /v1/public/checkups/{symbol}/latest
FieldTypeRequirementConstraintsDescription
anomaly_countintegerRequired—Number of anomalous items in the report or section.
as_ofstringOptional · Nullabledate-timeCutoff of the data visible in this response; may be null.
cycle_atstringOptional · Nullabledate-timeEngine cycle that produced this data.
depthstringRequiredquick | fullCheckup depth: quick or full.
formula_versionstringRequired—Formula version used to produce the report.
gradestringRequired—Checkup grade A–E; not calculated by the client.
lockedbooleanRequired—Whether this report is locked by entitlements.
long_riskintegerRequired—Long-risk score, not a probability.
metaobjectRequired—Additional endpoint-defined metadata object.
proProOutOptional · Nullable—Whether to request professional-mode fields; defaults to false.
report_idstringOptional · NullableuuidReport UUID. The open archive endpoint also verifies ownership.
sectionsarray<SectionOut>Required—Checkup report sections, each with ready, empty, or locked status.
short_riskintegerRequired—Short-risk score, not a probability.
sourcestringRequiredmarket | gatewayData source or CSV record granularity.
stagestringRequired—Engine lifecycle stage code.
stalebooleanRequired—Whether the data is not current. true should be visible to users.
symbolstringRequired—Canonical engine coin symbol, for example BTCUSDT.
GET

/v1/public/checkups/{symbol}

operationId
checkup_public_symbol_full
Authentication
Bearer API Key · read:checkup
Success response
200 · application/json

Request parameters

API field table: GET /v1/public/checkups/{symbol}
FieldLocationTypeRequirementConstraintsDescription
symbolpathstringRequired—Canonical engine coin symbol, for example BTCUSDT.
depthquerystringOptionaldefault="full" · ^full$Checkup depth: quick or full.
proquerybooleanOptionaldefault=falseWhether to request professional-mode fields; defaults to false.

Response fields

API field table: GET /v1/public/checkups/{symbol}
FieldTypeRequirementConstraintsDescription
anomaly_countintegerRequired—Number of anomalous items in the report or section.
as_ofstringOptional · Nullabledate-timeCutoff of the data visible in this response; may be null.
cycle_atstringOptional · Nullabledate-timeEngine cycle that produced this data.
depthstringRequiredquick | fullCheckup depth: quick or full.
formula_versionstringRequired—Formula version used to produce the report.
gradestringRequired—Checkup grade A–E; not calculated by the client.
lockedbooleanRequired—Whether this report is locked by entitlements.
long_riskintegerRequired—Long-risk score, not a probability.
metaobjectRequired—Additional endpoint-defined metadata object.
proProOutOptional · Nullable—Whether to request professional-mode fields; defaults to false.
report_idstringOptional · NullableuuidReport UUID. The open archive endpoint also verifies ownership.
sectionsarray<SectionOut>Required—Checkup report sections, each with ready, empty, or locked status.
short_riskintegerRequired—Short-risk score, not a probability.
sourcestringRequiredmarket | gatewayData source or CSV record granularity.
stagestringRequired—Engine lifecycle stage code.
stalebooleanRequired—Whether the data is not current. true should be visible to users.
symbolstringRequired—Canonical engine coin symbol, for example BTCUSDT.
curl
curl --fail-with-body "${API_BASE}/v1/public/checkups/BTCUSDT?depth=full&pro=false" \
  -H "Authorization: Bearer ${FF_API_KEY}" \
  -H "Accept-Language: ${ACCEPT_LANGUAGE}"

Per-coin prediction mirror

Anonymous and session predictions live at /v1/coins/{symbol}/predictions; API Key predictions live at /v1/public/coins/{symbol}/predictions and require read:market. For both, limit defaults to 50 with a maximum of 200, and viewer entitlements determine delay. Pass a non-null next_cursor back unchanged as cursor.

GET

/v1/coins/{symbol}/predictions

operationId
coin_predictions_v1_coins__symbol__predictions_get
Authentication
Anonymous; a separate IP rate limit may apply
Success response
200 · application/json

Request parameters

API field table: GET /v1/coins/{symbol}/predictions
FieldLocationTypeRequirementConstraintsDescription
symbolpathstringRequired—Canonical engine coin symbol, for example BTCUSDT.
limitqueryintegerOptionaldefault=50 · 1..200Maximum entries in this page. See constraints for the default and upper bound.
cursorquerystringOptional · Nullablelength 0..512Opaque cursor returned by the previous page.

Response fields

API field table: GET /v1/coins/{symbol}/predictions
FieldTypeRequirementConstraintsDescription
as_ofstringOptional · Nullabledate-timeCutoff of the data visible in this response; may be null.
delayed_minutesintegerOptionaldefault=0Minutes by which this view trails realtime data.
itemsarray<PredictionOut>Required—Resources in this page; see the type column for the element type.
next_cursorstringOptional · Nullable—Cursor for the next page, or null when no next page exists.
curl
curl --fail-with-body "${API_BASE}/v1/coins/BTCUSDT/predictions?limit=50"
GET

/v1/public/coins/{symbol}/predictions

operationId
market_public_coin_predictions
Authentication
Bearer API Key · read:market
Success response
200 · application/json

Request parameters

API field table: GET /v1/public/coins/{symbol}/predictions
FieldLocationTypeRequirementConstraintsDescription
symbolpathstringRequired—Canonical engine coin symbol, for example BTCUSDT.
limitqueryintegerOptionaldefault=50 · 1..200Maximum entries in this page. See constraints for the default and upper bound.
cursorquerystringOptional · Nullablelength 0..512Opaque cursor returned by the previous page.

Response fields

API field table: GET /v1/public/coins/{symbol}/predictions
FieldTypeRequirementConstraintsDescription
as_ofstringOptional · Nullabledate-timeCutoff of the data visible in this response; may be null.
delayed_minutesintegerOptionaldefault=0Minutes by which this view trails realtime data.
itemsarray<PredictionOut>Required—Resources in this page; see the type column for the element type.
next_cursorstringOptional · Nullable—Cursor for the next page, or null when no next page exists.
curl
curl --fail-with-body "${API_BASE}/v1/public/coins/BTCUSDT/predictions?limit=50" \
  -H "Authorization: Bearer ${FF_API_KEY}"
JSON
{
  "items": [
    {
      "prediction_id": "<prediction-id>",
      "symbol": "BTCUSDT",
      "type": "near_edge",
      "direction": "long",
      "status": "open",
      "target_lo": 100.0,
      "target_hi": 120.0,
      "invalid_price": 90.0,
      "resolve_price": null,
      "opened_at": "2026-10-28T00:00:00Z",
      "deadline": "2026-10-29T00:00:00Z",
      "resolved_at": null,
      "era": "5"
    }
  ],
  "next_cursor": null,
  "as_of": null,
  "delayed_minutes": 15
}

Prediction items[] fields

API field table: Prediction items[] fields
FieldTypeRequirementConstraintsDescription
prediction_idstringRequired—Stable identifier of the engine prediction mirror.
symbolstringRequired—Canonical engine coin symbol, for example BTCUSDT.
typestringRequirednear_edge | ignition | rally_target | dump_bottom | dump_riskRadar or prediction type, depending on the endpoint.
directionstringRequired · Nullable—Prediction direction.
statusstringRequiredopen | hit | failed | expired | corruptCurrent resource status.
target_lonumberRequired · Nullable—Lower target bound, or null when unavailable.
target_hinumberRequired · Nullable—Upper target bound, or null when unavailable.
invalid_pricenumberRequired · Nullable—Prediction invalidation price, or null when unavailable.
resolve_pricenumberRequired · Nullable—Prediction resolution price, or null while unresolved.
opened_atstringRequired · NullableISO 8601 UTCWhen the prediction opened.
deadlinestringRequired · NullableISO 8601 UTCPrediction deadline.
resolved_atstringRequired · NullableISO 8601 UTCWhen the prediction reached a terminal state, or null while unresolved.
erastringRequired—Engine era that produced the prediction.

The response card's OpenAPI is authoritative for the items element type. The table above reflects the platform market service's actual serialization. Prediction statuses are open, hit, failed, expired, and corrupt. Missing targets and results remain null. This is a prediction mirror, not a promise of returns.

Market data, signals, proofs, and CSV

These cards expand the real OpenAPI contracts directly. public in a path does not mean anonymous: check each endpoint's authentication row. When internal keys of free-form objects such as state, venues, and meta are not fixed by the schema, this page does not invent a field table for them.

GET

/v1/public/coins/{symbol}

operationId
market_public_coin_get
Authentication
Bearer API Key · read:market
Success response
200 · application/json

Request parameters

API field table: GET /v1/public/coins/{symbol}
FieldLocationTypeRequirementConstraintsDescription
symbolpathstringRequired—Canonical engine coin symbol, for example BTCUSDT.

Response fields

API field table: GET /v1/public/coins/{symbol}
FieldTypeRequirementConstraintsDescription
as_ofstringOptional · Nullable—Cutoff of the data visible in this response; may be null.
base_assetstringRequired—Base asset code.
delayed_minutesintegerOptionaldefault=0Minutes by which this view trails realtime data.
delistedbooleanRequired—Whether the coin has been delisted.
display_namestringRequired—Coin name for display.
first_seen_atstringOptional · Nullable—When the platform first observed the coin.
last_seen_atstringOptional · Nullable—When the platform most recently observed the coin.
listing_datestringOptional · Nullable—Listing date, or null when unknown.
prefix_multiplierintegerOptional · Nullable—Notional multiplier represented by the symbol prefix, or null.
primary_venuestringRequired—Current primary data venue.
quote_assetstringOptional · Nullable—Quote asset code, or null when unknown.
stateobjectOptional · Nullable—Latest or delayed coin-state object; its internal fields are not fixed by the current schema.
symbolstringRequired—Canonical engine coin symbol, for example BTCUSDT.
venuesarray<object>Optional—Array of venue coverage objects.
GET

/v1/public/radar/lists

operationId
market_public_radar_lists
Authentication
Bearer API Key · read:market
Success response
200 · application/json

Request parameters

API field table: GET /v1/public/radar/lists
FieldLocationTypeRequirementConstraintsDescription
typequerystringRequired—Radar or prediction type, depending on the endpoint.
limitqueryintegerOptionaldefault=50 · 1..200Maximum entries in this page. See constraints for the default and upper bound.

Response fields

API field table: GET /v1/public/radar/lists
FieldTypeRequirementConstraintsDescription
as_ofstringOptional · Nullable—Cutoff of the data visible in this response; may be null.
delayed_minutesintegerOptionaldefault=0Minutes by which this view trails realtime data.
itemsarray<object>Required—Resources in this page; see the type column for the element type.
typestringRequired—Radar or prediction type, depending on the endpoint.
GET

/v1/public/calibration

operationId
market_public_calibration
Authentication
Bearer API Key · read:market
Success response
200 · application/json

Request parameters

API field table: GET /v1/public/calibration
FieldLocationTypeRequirementConstraintsDescription
typequerystringOptional · Nullable—Radar or prediction type, depending on the endpoint.

Response fields

API field table: GET /v1/public/calibration
FieldTypeRequirementConstraintsDescription
itemsarray<CalibrationItemOut>Required—Resources in this page; see the type column for the element type.
GET

/v1/public/signals

operationId
signals_public_list
Authentication
Bearer API Key · read:signals
Success response
200 · application/json

Request parameters

API field table: GET /v1/public/signals
FieldLocationTypeRequirementConstraintsDescription
statusquerystringOptional · Nullableopen | closedCurrent resource status.
symbolquerystringOptional · Nullablelength 0..64Canonical engine coin symbol, for example BTCUSDT.
limitqueryintegerOptionaldefault=20 · 1..100Maximum entries in this page. See constraints for the default and upper bound.
cursorquerystringOptional · Nullablelength 0..512Opaque cursor returned by the previous page.

Response fields

API field table: GET /v1/public/signals
FieldTypeRequirementConstraintsDescription
itemsarray<SignalItem>Required—Resources in this page; see the type column for the element type.
next_cursorstringOptional · Nullable—Cursor for the next page, or null when no next page exists.
GET

/v1/public/signals/{stream}

operationId
signals_public_stream_list
Authentication
Bearer API Key · read:signals
Success response
200 · application/json

Request parameters

API field table: GET /v1/public/signals/{stream}
FieldLocationTypeRequirementConstraintsDescription
streampathstringRequiredlength 1..32Official signal stream stream_code.
statusquerystringOptional · Nullableopen | closedCurrent resource status.
symbolquerystringOptional · Nullablelength 0..64Canonical engine coin symbol, for example BTCUSDT.
limitqueryintegerOptionaldefault=20 · 1..100Maximum entries in this page. See constraints for the default and upper bound.
cursorquerystringOptional · Nullablelength 0..512Opaque cursor returned by the previous page.

Response fields

API field table: GET /v1/public/signals/{stream}
FieldTypeRequirementConstraintsDescription
itemsarray<SignalItem>Required—Resources in this page; see the type column for the element type.
next_cursorstringOptional · Nullable—Cursor for the next page, or null when no next page exists.
POST

/v1/public/proofs/verify

operationId
signals_public_proofs_verify
Authentication
Anonymous; a separate IP rate limit may apply
Success response
200 · application/json

Request body fields

API field table: POST /v1/public/proofs/verify
FieldTypeRequirementConstraintsDescription
daystringOptional · NullabledateUTC date of the proof batch.
leaf_hashstringOptional · Nullablelength 64..64 · ^[0-9a-f]{64}$64-character lowercase hexadecimal leaf hash to verify.
signal_idstringOptional · NullableuuidUUID of the signal to verify.

Response fields

API field table: POST /v1/public/proofs/verify
FieldTypeRequirementConstraintsDescription
daystringOptional · Nullable—UTC date of the proof batch.
foundbooleanRequired—Whether a matching proof item was found.
item_idstringOptional · Nullable—Proof item identifier.
item_typestringOptional · Nullable—Proof item type.
leaf_hashstringOptional · Nullable—64-character lowercase hexadecimal leaf hash to verify.
leaf_matches_currentbooleanOptional · Nullable—Whether the supplied leaf matches the current record.
matches_rootbooleanOptional · Nullable—Whether the leaf and path compute to the batch root.
otsobjectOptional · Nullable—OpenTimestamps status object; may be null while pending or unavailable.
patharray<object>Optional · Nullable—Merkle verification path.
rootstringOptional · Nullable—Merkle root for this UTC day's batch.

Historical state and signal CSV exports

Both CSV endpoints require export:data and data.export=full. A window can span at most 31 days and a file at most 100,000 data rows. Larger exports return 422 rather than silently truncating. Responses are text/csv with private, no-store and are suitable for streaming to storage.

GET

/v1/public/market/export/states.csv

operationId
market_public_states_csv_export
Authentication
Bearer API Key · export:data; data.export=full also required
Success response
200 · text/csv

Request parameters

API field table: GET /v1/public/market/export/states.csv
FieldLocationTypeRequirementConstraintsDescription
symbolquerystringRequiredlength 1..64Canonical engine coin symbol, for example BTCUSDT.
fromquerystringOptional · Nullablelength 0..64Inclusive window start in ISO 8601 UTC.
toquerystringOptional · Nullablelength 0..64Exclusive window end in ISO 8601 UTC.
curl
curl --fail-with-body --get "${API_BASE}/v1/public/market/export/states.csv" \
  -H "Authorization: Bearer ${FF_API_KEY}" \
  --data-urlencode "symbol=BTCUSDT" \
  --data-urlencode "from=2026-10-01T00:00:00Z" \
  --data-urlencode "to=2026-10-28T00:00:00Z" \
  --output market-states.csv

symbol, recorded_at, source, hour_at, stage, raw_stage, cluster, dump_score, ev_score, p_rally_ratio, chg24_pct, last_price, vol24_quote, vol_z, dist_ath_pct, funding_bps, oi_chg_24h_pct, impact_pct, level, delisted, primary_venue, summary_plain, low_revisit

The market CSV header order above was checked against backend STATE_COLUMNS. Nested objects are compact JSON in cells, and spreadsheet formula prefixes in text are escaped. Empty cells mean missing data and must not be filled with zero. Signal CSV uses backend SIGNAL_COLUMNS and is exported through /v1/public/signals/export.csv.

Webhook endpoints, signatures, and retries

Webhook management uses webhooks:manage, not a Cookie session. The secret in the creation response appears only once; store it immediately in a secret manager. Endpoints must be allowed public HTTPS URLs and cannot contain usernames or passwords.

POST

/v1/me/webhooks

operationId
notify_webhooks_create
Authentication
Bearer API Key · webhooks:manage
Success response
201 · application/json

Request body fields

API field table: POST /v1/me/webhooks
FieldTypeRequirementConstraintsDescription
urlstringRequiredlength 8..2000Public HTTPS receiver URL for the Webhook.

Response fields

API field table: POST /v1/me/webhooks
FieldTypeRequirementConstraintsDescription
created_atunspecifiedRequired—Resource creation time in ISO 8601 UTC.
idunspecifiedRequired—Resource UUID.
secretunspecifiedRequired—Webhook signing secret, returned only once at creation.
statusunspecifiedRequired—Current resource status.
urlunspecifiedRequired—Public HTTPS receiver URL for the Webhook.
curl
curl --request POST "${API_BASE}/v1/me/webhooks" \
  -H "Authorization: Bearer ${FF_API_KEY}" \
  -H "Content-Type: application/json" \
  --data '{"url":"<public-https-webhook-url>"}'
JSON
{
  "id": "<endpoint-uuid>",
  "url": "<public-https-webhook-url>",
  "status": "active",
  "created_at": "2026-10-28T00:00:00Z",
  "secret": "<shown-once-store-securely>"
}

Verify signatures

Do not add newlines, reorder, or reserialize the raw request body. The primary signed material is id.timestamp.body. Compute HMAC-SHA256 with the endpoint secret and use constant-time comparison with v1=<hex> in FF-Webhook-Signature. The timestamp window is five minutes. X-FF-Signature signs only the raw body for compatibility; new integrations should prioritize the primary signature.

FF-Webhook-Id · FF-Webhook-Timestamp · FF-Webhook-Signature: v1=<hex> · X-FF-Signature: sha256=<hex>

Python
import hashlib
import hmac
import os
import time

def verify_webhook(headers, raw_body: bytes) -> bool:
    delivery_id = headers["FF-Webhook-Id"]
    timestamp = headers["FF-Webhook-Timestamp"]
    signature = headers["FF-Webhook-Signature"]
    if abs(time.time() - int(timestamp)) > 300:
        return False
    material = delivery_id.encode() + b"." + timestamp.encode() + b"." + raw_body
    expected = hmac.new(
        os.environ["FF_WEBHOOK_SECRET"].encode(), material, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, "v1=" + expected)

The example reads its secret from FF_WEBHOOK_SECRET and contains no real secret. Production code should also reject missing or malformed headers, cap raw body size, and parse JSON only after verification succeeds.

Delivery and retries

Only a 2xx receiver response counts as success. After the initial failure, retries occur after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours, and 24 hours: seven attempts in total. The delivery is then marked failed. An endpoint with no success for three consecutive days is disabled and its owner is notified.

Deduplicate on FF-Webhook-Id and event id, and make receivers idempotent. The same event succeeds at most once per endpoint. Only events that occur after endpoint creation are delivered. Read delivery states through GET /v1/me/webhooks/{endpoint_id}/deliveries and revoke an endpoint with DELETE /v1/me/webhooks/{endpoint_id}.

WebSocket connections and subscriptions

Realtime streams use Centrifugo. First exchange the API Key over HTTP for a 600-second connection JWT, then obtain a 600-second subscription JWT for each private channel. Finally connect to the Centrifugo WebSocket address supplied by your deployment. The long-lived API Key appears only in the HTTP Authorization header.

POST

/v1/public/realtime/token

operationId
signals_public_realtime_token_create
Authentication
Bearer API Key · read:market or read:signals
Success response
200 · application/json

Response fields

API field table: POST /v1/public/realtime/token
FieldTypeRequirementConstraintsDescription
allowed_channelsarray<string>Required—Channel classes granted to this Key; does not replace per-channel subscription tokens.
expires_inintegerRequired—Issued lifetime of the short-lived JWT, currently 600 seconds.
tokenstringRequired—Short-lived Centrifugo JWT, not the long-lived API Key.
GET

/v1/public/realtime/subscribe-token

operationId
signals_public_realtime_subscribe_token_get
Authentication
Bearer API Key · read:market or read:signals
Success response
200 · application/json

Request parameters

API field table: GET /v1/public/realtime/subscribe-token
FieldLocationTypeRequirementConstraintsDescription
channelquerystringRequiredlength 1..160Full Centrifugo channel to subscribe to.

Response fields

API field table: GET /v1/public/realtime/subscribe-token
FieldTypeRequirementConstraintsDescription
allowed_channelsarray<string>Required—Channel classes granted to this Key; does not replace per-channel subscription tokens.
channelstringRequired—Full Centrifugo channel to subscribe to.
expires_inintegerRequired—Issued lifetime of the short-lived JWT, currently 600 seconds.
tokenstringRequired—Short-lived Centrifugo JWT, not the long-lived API Key.
Scopes and channel allowlists
ScopeChannels
read:marketpub:market · pub:lists · pub:coins · live:market · live:lists · live:coins · live:coin.{SYMBOL}
read:signalssig:{stream_code}; the stream must exist
curl
curl --request POST "${API_BASE}/v1/public/realtime/token" \
  -H "Authorization: Bearer ${FF_API_KEY}"

curl --get "${API_BASE}/v1/public/realtime/subscribe-token" \
  -H "Authorization: Bearer ${FF_API_KEY}" \
  --data-urlencode "channel=live:coin.BTCUSDT"
JSON
{
  "token": "<short-lived-jwt>",
  "expires_in": 600,
  "allowed_channels": ["live:*"],
  "channel": "live:coin.BTCUSDT"
}
TypeScript
import { createApiKeyTokenSource, RealtimeClient } from "@ff/realtime";

const tokens = createApiKeyTokenSource({
  apiBaseUrl: process.env.API_BASE!,
  apiKey: process.env.FF_API_KEY!,
});
// API Key 自动使用 connect.data.token / subscribe.data.token;
// 普通用户 JWT 才使用原生 getToken / getSubscribeToken。
const client = new RealtimeClient({
  url: process.env.FF_REALTIME_URL!,
  ...tokens,
});
const stop = client.listen("live:coin.BTCUSDT", (ctx) => {
  console.log(ctx.data);
});

Each Key can hold at most 10 unexpired connection-token leases; subscription tokens do not consume these leases. Obtain a new connection token after the old connection expires rather than rotating early. This is an issuance-side lease limit, not a count of real online connections.

The example reuses the repository's @ff/realtime package and runs on a trusted server or local program. A revoked Key cannot obtain new tokens. Already-issued JWTs are stateless and can live until their original exp (600 seconds), so immediate disconnection is not guaranteed. user:* and admin:* channels are not available to API Keys.

Current open endpoint directory

This table enumerates real OpenAPI operations under /v1/public at build time. The specification is authoritative for operationIds, methods, and paths. New public endpoints enter the directory when the shared specification is regenerated; authentication metadata still needs review against backend routes.

API endpoint directory
MethodPathGroupAuthenticationoperationId
GET/v1/public/checkup/reports/{report_id}CheckupsBearer API Key · read:checkupcheckup_public_report_get
GET/v1/public/checkup/symbols/{symbol}CheckupsAnonymous; a separate IP rate limit may applycheckup_public_symbol_get
GET/v1/public/checkups/{symbol}CheckupsBearer API Key · read:checkupcheckup_public_symbol_full
GET/v1/public/checkups/{symbol}/latestCheckupsBearer API Key · read:checkupcheckup_public_symbol_latest
GET/v1/public/calibrationMarket dataBearer API Key · read:marketmarket_public_calibration
GET/v1/public/coins/{symbol}Market dataBearer API Key · read:marketmarket_public_coin_get
GET/v1/public/coins/{symbol}/predictionsMarket dataBearer API Key · read:marketmarket_public_coin_predictions
GET/v1/public/market/export/states.csvMarket dataBearer API Key · export:data; data.export=full also requiredmarket_public_states_csv_export
GET/v1/public/radar/listsMarket dataBearer API Key · read:marketmarket_public_radar_lists
GET/v1/public/affiliates/{slug}Other public resourcesAnonymous; a separate IP rate limit may applygrowth_public_affiliates_get
GET/v1/public/affiliates/{slug}/botOther public resourcesAnonymous; a separate IP rate limit may applygrowth_public_affiliate_bot_get
GET/v1/public/live/certifications/{token}Other public resourcesAnonymous; a separate IP rate limit may applylive_public_certification_get
GET/v1/public/proofsPublic proofsAnonymous; a separate IP rate limit may applysignals_public_proofs_list
GET/v1/public/proofs/{day}Public proofsAnonymous; a separate IP rate limit may applysignals_public_proofs_get
POST/v1/public/proofs/verifyPublic proofsAnonymous; a separate IP rate limit may applysignals_public_proofs_verify
GET/v1/public/realtime/subscribe-tokenRealtime tokensBearer API Key · read:market or read:signalssignals_public_realtime_subscribe_token_get
POST/v1/public/realtime/tokenRealtime tokensBearer API Key · read:market or read:signalssignals_public_realtime_token_create
GET/v1/public/signalsSignalsBearer API Key · read:signalssignals_public_list
GET/v1/public/signals/{stream}SignalsBearer API Key · read:signalssignals_public_stream_list
GET/v1/public/signals/export.csvSignalsBearer API Key · export:data; data.export=full also requiredsignals_public_csv_export

Related management and session endpoints

API Key management, predictions, and Webhooks are not all under /v1/public, so they are listed separately to preserve their actual paths.

API endpoint directory
MethodPathGroupAuthenticationoperationId
POST/v1/me/api-keysAccount and API KeysCookie session; writes also require CSRFauth_api_keys_create
GET/v1/coins/{symbol}/predictionsMarket dataAnonymous; a separate IP rate limit may applycoin_predictions_v1_coins__symbol__predictions_get
GET/v1/me/webhooksWebhooksBearer API Key · webhooks:managenotify_webhooks_list
POST/v1/me/webhooksWebhooksBearer API Key · webhooks:managenotify_webhooks_create
DELETE/v1/me/webhooks/{endpoint_id}WebhooksBearer API Key · webhooks:managenotify_webhooks_delete
GET/v1/me/webhooks/{endpoint_id}/deliveriesWebhooksBearer API Key · webhooks:managenotify_webhooks_deliveries_list

Admin, internal ingest, node control-plane, and management endpoints omitted here are not open APIs. Inclusion in this directory does not mean an external production hostname has passed acceptance or is reachable from your network.