Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Crypto Data Regimes API
description: 'Real-time crypto market intelligence API. Built for AI agents: gasless USDC payments via x402 protocol, one-call onboarding, and 180+ endpoints for prices, derivatives, funding, and sentiment.'
version: '2026-10-28'
servers:
- url: https://cryptodataapi.com
tags:
- name: Regimes
description: Long-horizon 10-state market-cycle taxonomy and the current detected regime.
paths:
/api/v1/regimes:
get:
tags:
- Regimes
summary: Get Regimes
description: 'The 10-state long-horizon regime model + the current detected regime.
``regimes`` is the stable taxonomy (id, machine ``regime`` id, display name,
description, typical duration and directional bias). ``current`` is the live
classification with a ``rationale``, the inspectable ``signals`` that drove
it, and — where applicable — an internal ``stage`` (Distribution) or
``euphoria_score`` (Speculative Euphoria).
**Committed vs live.** ``current.regime``/``id``/``name``/``rationale`` are the
COMMITTED regime: an anti-churn dwell gate holds it until a new candidate is
the raw classification for ``pending.needed`` consecutive refreshes. But
``signals`` are always read fresh, so mid-turn they can stop supporting the
committed regime — that is expected, not stale data. ``current.raw`` gives the
live ungated classification and ``raw.matches_committed`` tells you the two
disagree; ``current.pending`` shows how far the successor has confirmed.
**Stability.** ``pending`` is null whenever the live read already agrees with
the committed regime — correct, but it means a consumer watching for a turn
sees a field that blinks in and out. ``current.stability`` is always present
and always numeric: ``raw_agreement`` decays as conditions drift,
``confirmations_against``/``needed`` track a successor, and ``locked_for_s``
is the HARD number — how long the dwell floor mechanically guarantees the
committed regime survives. ``current.thresholds`` gives the distance from
every numeric cutoff in the cascade to flipping, so hysteresis can be built
on published boundaries instead of guesses.
``typical_duration`` describes the real-world cycle phase, NOT a guaranteed
dwell — but the dwell floor is now SCALED to it: a "Weeks-Months" state
(#2/#4/#6/#8) must be held 48h before anything may replace it, "Weeks" 24h,
"Days-Weeks" 12h, and #1 Structural Shock only 2h because it is an emergency
override. Read the live value from ``stability.dwell_floor_s``.
``/regimes/history`` returns the committed transition sequence.'
operationId: get_regimes_api_v1_regimes_get
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/RegimesResponse'
security:
- APIKeyHeader: []
/api/v1/regimes/history:
get:
tags:
- Regimes
summary: Get Regime History
description: 'Committed long-horizon regime transitions over a window (Pro Plus).
``/regimes`` publishes only what is committed right now, so the sequence that
produced it could not be reconstructed from this API at all. Each entry here
is one committed run: which regime, the exact instant it committed, when the
next one replaced it, and how long it held.
**``committed_at`` is exact.** It comes from the ``in_regime_since`` stamped
at commit time and carried in every archived sample — not from the ~25-min
sample that first observed the change. And because every committed regime is
now protected by a minimum-dwell floor of at least 2h, no transition can hide
between two samples.
**Coverage starts 2026-08-07 and cannot be backfilled.** The published regime
is a stateful commit through the anti-churn dwell gate, not a pure function
of the archived signals — replaying older inputs would produce a sequence
that was never actually served. ``coverage_start`` reports the true start.
Not to be confused with ``/quant/regimes/history``, which is the short-horizon
6-state HMM''s hourly probability Parquet. This is the 10-state cycle model.'
operationId: get_regime_history_api_v1_regimes_history_get
security:
- APIKeyHeader: []
parameters:
- name: from
in: query
required: false
schema:
type: string
description: Window start, inclusive (ISO-8601 or unix ms). Defaults to 30 days ago.
title: From
description: Window start, inclusive (ISO-8601 or unix ms). Defaults to 30 days ago.
- name: to
in: query
required: false
schema:
type: string
description: Window end, EXCLUSIVE (ISO-8601 or unix ms). Defaults to now.
title: To
description: Window end, EXCLUSIVE (ISO-8601 or unix ms). Defaults to now.
- name: limit
in: query
required: false
schema:
type: integer
maximum: 25000
minimum: 1
description: Max archive samples to scan (~57/day), not transitions returned.
default: 5000
title: Limit
description: Max archive samples to scan (~57/day), not transitions returned.
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/RegimeHistoryResponse'
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
x-timeout-seconds: 30
/api/v1/regimes/current:
get:
tags:
- Regimes
summary: Get Current
description: 'Just the current long-horizon regime — the trimmed companion to ``/regimes``.
Same classification as the ``current`` block above, without the taxonomy.'
operationId: get_current_api_v1_regimes_current_get
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/CurrentRegime'
security:
- APIKeyHeader: []
x-price-usdc: '0.01'
x-payment: x402
x-payment-route-id: regimes_current
components:
schemas:
RegimeThresholds:
properties:
nearest:
description: The measured check with the smallest distance
$ref: '#/components/schemas/ThresholdCheck'
checks:
items:
$ref: '#/components/schemas/ThresholdCheck'
type: array
title: Checks
type: object
required:
- checks
title: RegimeThresholds
description: 'Distance to every numeric boundary in the cascade — the raw material for
client-side hysteresis.
The two CATEGORICAL inputs (``quant_label``, ``meme_season``) have no
distance by construction; read them from ``signals``.'
RegimeTransition:
properties:
id:
title: Id
type:
- integer
- 'null'
regime:
title: Regime
type:
- string
- 'null'
anchor:
title: Anchor
type:
- string
- 'null'
name:
title: Name
type:
- string
- 'null'
committed_at:
type: string
title: Committed At
description: ISO-8601 instant the regime COMMITTED, read from the snapshot's own in_regime_since — not the sample that first observed it, so this is exact rather than rounded to the archive cadence
ended_at:
title: Ended At
description: commit instant of the NEXT regime; null while this one is current
type:
- string
- 'null'
dwell_seconds:
title: Dwell Seconds
description: Held duration; measured to now for the open final run
type:
- integer
- 'null'
rationale:
title: Rationale
type:
- string
- 'null'
stage:
title: Stage
type:
- string
- 'null'
euphoria_score:
title: Euphoria Score
type:
- integer
- 'null'
first_observed_at:
type: string
title: First Observed At
description: First archived sample carrying this run
last_observed_at:
type: string
title: Last Observed At
description: Last archived sample carrying this run
observations:
type: integer
title: Observations
description: Archived samples covering this run
type: object
required:
- committed_at
- first_observed_at
- last_observed_at
- observations
title: RegimeTransition
description: One committed run of a regime — when it was entered, and for how long.
RegimeStability:
properties:
score:
type: number
title: Score
description: '0-1 blend: 0.6 * raw_agreement + 0.4 * (1 - confirmation pressure). Excludes locked_for_s deliberately — a hard guarantee and a soft estimate do not belong in one number.'
raw_agreement:
type: number
title: Raw Agreement
description: Fraction of the last raw_samples ungated classifications that matched the committed regime. Decays smoothly as conditions drift, well before any candidate confirms.
raw_samples:
type: integer
title: Raw Samples
description: Samples currently in the window
raw_window:
type: integer
title: Raw Window
description: Window size in samples (~15 min each)
confirmations_against:
type: integer
title: Confirmations Against
description: Consecutive raw samples the current successor has accumulated (0 if none)
confirmations_needed:
type: integer
title: Confirmations Needed
description: Consecutive samples a successor must accumulate — populated even with no candidate, so the pair is always interpretable
candidate:
title: Candidate
description: Anchor of the pending successor, or null
type:
- string
- 'null'
held_s:
title: Held S
description: Seconds the committed regime has been held
type:
- integer
- 'null'
dwell_floor_s:
type: integer
title: Dwell Floor S
description: This regime's own minimum-hold floor, scaled to its catalog typical_duration (see /regimes typical_duration)
locked_for_s:
type: integer
title: Locked For S
description: Seconds the committed regime is GUARANTEED to survive under the dwell floor. 0 means a confirmed successor could commit on the next refresh. Structural Shock can still pre-empt this.
type: object
required:
- score
- raw_agreement
- raw_samples
- raw_window
- confirmations_against
- confirmations_needed
- dwell_floor_s
- locked_for_s
title: RegimeStability
description: 'How firmly the committed regime is holding — always present, always numeric.
``pending`` is null exactly when the live cascade agrees with the committed
regime, so a consumer polling for "is a turn brewing" gets a field that
blinks in and out of existence and carries no signal on a hold. This block
is the continuous companion: it is emitted on every response, candidate or
not, so it can be differenced, thresholded, or fed to a risk sizer directly.
``locked_for_s`` is the only HARD number here — the minimum-dwell floor
mechanically prevents any change for that long. The one exception is a
Structural Shock override, which is exempt from the floor by design.'
RegimeInfo:
properties:
id:
type: integer
title: Id
description: Stable 1-10 ordinal, roughly cycle order
regime:
type: string
title: Regime
description: Machine id — the API contract (e.g. established_bear)
anchor:
type: string
title: Anchor
description: Slug matching the /crypto-market-regimes web page section id
name:
type: string
title: Name
description: Human display name
description:
type: string
title: Description
typical_duration:
type: string
title: Typical Duration
directional_bias:
type: string
title: Directional Bias
type: object
required:
- id
- regime
- anchor
- name
- description
- typical_duration
- directional_bias
title: RegimeInfo
description: One entry in the 10-state long-horizon regime taxonomy.
HTTPValidationError:
properties:
detail:
items:
$ref: '#/components/schemas/ValidationError'
type: array
title: Detail
type: object
title: HTTPValidationError
ValidationError:
properties:
loc:
items:
anyOf:
- type: string
- type: integer
type: array
title: Location
msg:
type: string
title: Message
type:
type: string
title: Error Type
input:
title: Input
ctx:
type: object
title: Context
type: object
required:
- loc
- msg
- type
title: ValidationError
ThresholdCheck:
properties:
signal:
type: string
title: Signal
description: Key in `signals` this check reads
op:
type: string
title: Op
description: Comparison the cascade applies (>=, >, <=, <)
cutoff:
type: number
title: Cutoff
value:
title: Value
description: Live value, or null if the feed is down
type:
- number
- 'null'
holds:
title: Holds
description: Whether the check passes right now
type:
- boolean
- 'null'
distance:
title: Distance
description: Absolute move required to cross the cutoff, in the signal's own units. Does NOT indicate direction of travel.
type:
- number
- 'null'
gates:
type: string
title: Gates
description: What crossing puts in play — a regime anchor, or condition:<state> for the health-score cutoffs that drive the cascade's dominant input
type: object
required:
- signal
- op
- cutoff
- gates
title: ThresholdCheck
description: One numeric cutoff the classifier cascade tests, and how far it is from flipping.
RegimesResponse:
properties:
current:
$ref: '#/components/schemas/CurrentRegime'
regimes:
items:
$ref: '#/components/schemas/RegimeInfo'
type: array
title: Regimes
count:
type: integer
title: Count
as_of:
type: string
title: As Of
type: object
required:
- current
- regimes
- count
- as_of
title: RegimesResponse
description: '`/api/v1/regimes` — current detection plus the full taxonomy.'
RawClassification:
properties:
anchor:
title: Anchor
type:
- string
- 'null'
regime:
title: Regime
type:
- string
- 'null'
name:
title: Name
type:
- string
- 'null'
id:
title: Id
type:
- integer
- 'null'
matches_committed:
type: boolean
title: Matches Committed
description: False when the live cascade disagrees with the committed regime
type: object
required:
- matches_committed
title: RawClassification
description: 'What the cascade classifies RIGHT NOW, before the anti-churn dwell gate.
The published regime is the COMMITTED one, which by design lags the live
inputs — so ``signals`` can stop meeting the committed regime''s entry
condition while that regime is still served. Without this block that reads
as contradictory data: a consumer sees ``rationale`` saying "a security
shock is active" next to a ``security_stress`` below the trigger, with no
way to tell the difference between "stale by design" and "broken".
``matches_committed`` false is normal and expected — it means a turn is
being evaluated; read ``pending.count``/``needed`` for how far along it is.'
RegimeHistoryResponse:
properties:
transitions:
items:
$ref: '#/components/schemas/RegimeTransition'
type: array
title: Transitions
count:
type: integer
title: Count
from:
type: string
title: From
description: Start of the requested window (inclusive)
to:
type: string
title: To
description: End of the requested window (exclusive)
coverage_start:
title: Coverage Start
description: Earliest archived snapshot. Recording began 2026-08-07 and CANNOT be backfilled — the published regime is a stateful commit through the dwell gate, so replaying older signals would invent a sequence that was never served. A `from` earlier than this returns nothing for the uncovered part.
type:
- string
- 'null'
sample_interval_seconds:
type: integer
title: Sample Interval Seconds
description: Archive cadence. Every committed regime is protected by a dwell floor of at least 2h, well above this, so no transition can fall between samples.
truncated:
type: boolean
title: Truncated
description: True when `limit` clipped the window. Rows are read oldest-first, so the RECENT end is what is missing — narrow the window and re-request.
type: object
required:
- transitions
- count
- from
- to
- sample_interval_seconds
- truncated
title: RegimeHistoryResponse
description: '`/api/v1/regimes/history` — the committed transition sequence.'
PendingRegime:
properties:
anchor:
type: string
title: Anchor
regime:
type: string
title: Regime
name:
type: string
title: Name
count:
type: integer
title: Count
description: Consecutive raw samples seen so far
needed:
type: integer
title: Needed
description: Consecutive samples required to commit
since:
title: Since
description: ISO ts the candidate first appeared
type:
- string
- 'null'
dwell_blocked_s:
type: integer
title: Dwell Blocked S
description: Seconds still owed on the minimum-dwell floor. When >0 the candidate is FULLY confirmed (count >= needed) and is waiting only for the committed regime to satisfy its minimum hold — which is why count can sit above needed without committing.
default: 0
type: object
required:
- anchor
- regime
- name
- count
- needed
title: PendingRegime
description: 'A candidate regime accumulating confirmations but not yet committed.
Surfaced so a consumer can see a turn brewing before the committed regime
actually changes (the anti-churn dwell gate requires ``needed`` consecutive
samples before a switch).'
CurrentRegime:
properties:
regime:
title: Regime
description: Machine id, null on cold start
type:
- string
- 'null'
id:
title: Id
type:
- integer
- 'null'
anchor:
title: Anchor
type:
- string
- 'null'
name:
title: Name
type:
- string
- 'null'
rationale:
title: Rationale
description: Why this regime was selected
type:
- string
- 'null'
stage:
title: Stage
description: Sub-stage for Distribution (early_distribution|active_deleveraging) and Speculative Euphoria (alt_expansion|blow_off)
type:
- string
- 'null'
stage_label:
title: Stage Label
description: Human label for the sub-stage
type:
- string
- 'null'
euphoria_score:
title: Euphoria Score
description: 0-100 froth gauge, present only for Speculative Euphoria
type:
- integer
- 'null'
signals:
additionalProperties: true
type: object
title: Signals
description: 'The classifier inputs (health scores, condition, BTC dominance, volatility / meme / security overlays, OI, liquidations) — transparency. ALWAYS LIVE: these are read at `as_of`, whereas regime/id/name/rationale describe the COMMITTED regime, which the dwell gate holds until a new candidate confirms. Compare against `raw` to see the two diverge.'
raw:
description: The live, ungated classification — what the cascade says about `signals` right now. Null only on a cold start.
$ref: '#/components/schemas/RawClassification'
as_of:
title: As Of
description: ISO-8601 timestamp of the classification
type:
- string
- 'null'
in_regime_since:
title: In Regime Since
description: ISO-8601 ts the current committed regime was ENTERED — advances only when the regime actually changes, so consumers can show how long it has held
type:
- string
- 'null'
pending:
description: Candidate regime awaiting confirmation by the anti-churn dwell gate. Null exactly when the live cascade already agrees with the committed regime (identical to `raw.matches_committed` being true) — nothing is accumulating, so there is no candidate to describe. For a field that is always populated, read `stability`.
$ref: '#/components/schemas/PendingRegime'
stability:
description: Continuous stability of the committed regime — always present once the first refresh lands, candidate or not
$ref: '#/components/schemas/RegimeStability'
thresholds:
description: Distance from each cascade cutoff to flipping, for building client-side hysteresis without guessing where the boundaries are
$ref: '#/components/schemas/RegimeThresholds'
type: object
title: CurrentRegime
description: The single regime the market is currently classified into.
securitySchemes:
APIKeyHeader:
type: apiKey
in: header
name: X-API-Key