{"info":{"version":"1.0.0","description":"Write trading-signal rules as JSON and let them run.\n\nStart with GET /client/api/capabilities, resolve symbols through GET\n/client/api/markets, and POST /client/api/preflight before creating a rule.\nGET /client/api/ohlcv reads market data without creating alerts.\n/client/api/signal-baskets supports basket.v1 over fixed symbols or top-N\nvolume markets. A basket costs one signal slot per member.\n\nYou are most likely reading this because someone pointed their AI at it.\nThe intended loop is: read the DSL schema, write a rule, `POST` it to\n`/client/api/rules/validate`, correct whatever comes back, then `POST` it\nto `/client/api/rules`. Validation errors are structured — `path`, `code`,\n`expected`, `got`, `suggestion` — and every error in the document is\nreturned at once, so the loop converges in one or two round trips rather\nthan one error at a time.\n\n**There are two kinds of rule, and they are different documents.**\n\nA **coin watcher** (`dsl_version: \"watcher.v1\"`, at\n`/client/api/rules`) is a condition tree over on-chain coins it discovers\nfor itself: \"any Solana coin over $100k liquidity that jumps 15% in an\nhour\". Read `/client/api/vocabulary` first.\n\nA **signal alert** (`dsl_version: \"signal.v1\"`, at\n`/client/api/signal-alerts`) names one exchange-listed market and one\nclassical technical setup on one timeframe: \"RSI crosses into oversold on\nthe daily, SOL-USD on Coinbase\". The setups are a curated closed list, not\na formula builder. Read `/client/api/signal-alerts/schema` first.\n\nPick by what you are watching. A named market on a venue is a signal\nalert; a coin you have not chosen yet is a watcher. Both classes use the\nsame key, the same `rules:read` / `rules:write` scopes, the same response\nenvelope, the same six-key validation errors and the same tier limits —\nso a caller learns this surface once and writes either.\n\n**Authentication.** Every endpoint except this document and the docs page\nneeds a key sent as `Authorization: Bearer <key>`. Keys are issued in the\nweb app and the plaintext is shown exactly once. A key carries explicit\nscopes; an endpoint returns `403` naming the scope it needed.\n\n**The DSL is versioned and the version is a contract.** Every rule\ndocument declares `dsl_version` — `watcher.v1` for a watcher,\n`signal.v1` for a signal alert. The two version\nindependently, on purpose. A stored rule keeps meaning what it meant when\nit was accepted; a table changing is a new version, never an edit in\nplace.\n\n**Published is not the same as available.** Every field in the watcher\nvocabulary carries an `available` flag read at the moment this document\nwas built. A field with `available: false` is part of this version and\nwill be accepted, but nothing on this deployment is producing a value for\nit, so a rule using it stores and then holds on every pass instead of\nfiring. Each one carries a sentence saying why. Currently unavailable: `attention_mentions`, `attention_ratio`, `attention_z`. Prefer a rule that does not need them until they read as available.\n\nSignal alerts answer the same question at a different granularity, and\nanswer it live: a setup is available on a *market* or not, depending on\nhow much history and liquidity that market has. That cannot be published\nas a flag here — it is true of one market at one moment — so it has its\nown endpoint, `/client/api/signal-alerts/availability`. Ask it before you\narm a weekly moving-average cross, or the first thing you learn will be\nfour years of silence.\n\n**What a rule is and is not.** A rule reports that a measurement crossed a\nline, and reports its own stamped record of what happened afterwards at\n+1h and +24h. It is not advice, not a prediction, and this API never\nplaces an order — there is no order endpoint, on purpose.\n\nThere is also an MCP endpoint at `/client/api/mcp` carrying the same\noperations as tools, for clients that speak Model Context Protocol.\n","title":"DMTrading Rules API","x-dsl-version":"watcher.v1","x-signal-dsl-version":"signal.v1"},"components":{"schemas":{"SignalAlertFire":{"type":"object","properties":{"id":{"type":"integer"},"values":{"type":"object","description":"The indicator readings at that close — what made the condition true, so \"why did this fire\" is answerable without re-running anything."},"exchange":{"type":"string","enum":["coinbase","binanceus","bybit"]},"setup":{"type":"string","enum":["ltf_hf_buy","ltf_hf_sell","rsi_oversold","rsi_recovery","rsi_overbought","golden_cross","death_cross","price_reclaims_ma","price_loses_ma","bollinger_lower","bollinger_upper","macd_bullish","macd_bearish","msb_bullish","msb_bearish"]},"symbol":{"type":"string"},"plan":{"type":["object","null"],"description":"Fully resolved decimal plan stamped when this fire was recorded."},"bucket_start":{"type":"string","format":"date-time","description":"The closed bar the alert fired on."},"plan_error":{"type":["object","null"],"description":"Stable code and explanation when plan_status is unresolved."},"plan_status":{"type":"string","enum":["resolved","absent","unresolved"]},"price":{"type":["string","null"],"description":"Decimal as a string."},"rule_id":{"type":"integer"},"timeframe":{"type":"string","enum":["m15","h1","h4","h12","d1","w1"]},"note":{"type":["string","null"],"description":"The alert's note, as it was when it fired."},"chart_path":{"type":"string","description":"In-app link to the market's chart with that bar marked."},"outcomes":{"type":"object","description":"Keyed by horizon. A horizon with no row yet is null.","properties":{"h1":{"$ref":"#/components/schemas/Outcome"},"h24":{"$ref":"#/components/schemas/Outcome"}}},"basket_id":{"type":["integer","null"]}}},"WatcherRule":{"$defs":{"all":{"additionalProperties":false,"description":"Every listed condition must hold.","properties":{"all":{"items":{"$ref":"#/$defs/condition"},"maxItems":16,"minItems":1,"type":"array"}},"required":["all"],"type":"object"},"any":{"additionalProperties":false,"description":"At least one listed condition must hold.","properties":{"any":{"items":{"$ref":"#/$defs/condition"},"maxItems":16,"minItems":1,"type":"array"}},"required":["any"],"type":"object"},"cmp_above":{"additionalProperties":false,"description":"left is strictly greater than right","properties":{"above":{"additionalProperties":false,"properties":{"left":{"description":"A field this operator may be used on. Whether the field currently has a value is a separate question — see `x-unavailable` on `#/$defs/field` and the `available` flag in `x-dsl-vocabulary`.","enum":["liquidity_usd","pool_age_hours","volume_24h_usd","price_usd","price_change_1h_pct","price_change_6h_pct","price_change_24h_pct","attention_mentions","attention_z","attention_ratio"],"type":"string"},"right":{"$ref":"#/$defs/threshold"}},"required":["left","right"],"type":"object"}},"required":["above"],"type":"object"},"cmp_below":{"additionalProperties":false,"description":"left is strictly less than right","properties":{"below":{"additionalProperties":false,"properties":{"left":{"description":"A field this operator may be used on. Whether the field currently has a value is a separate question — see `x-unavailable` on `#/$defs/field` and the `available` flag in `x-dsl-vocabulary`.","enum":["liquidity_usd","pool_age_hours","volume_24h_usd","price_usd","price_change_1h_pct","price_change_6h_pct","price_change_24h_pct","attention_mentions","attention_z","attention_ratio"],"type":"string"},"right":{"$ref":"#/$defs/threshold"}},"required":["left","right"],"type":"object"}},"required":["below"],"type":"object"},"cmp_between":{"additionalProperties":false,"description":"value is within [low, high], both bounds inclusive","properties":{"between":{"additionalProperties":false,"properties":{"high":{"$ref":"#/$defs/threshold"},"low":{"$ref":"#/$defs/threshold"},"value":{"description":"A field this operator may be used on. Whether the field currently has a value is a separate question — see `x-unavailable` on `#/$defs/field` and the `available` flag in `x-dsl-vocabulary`.","enum":["liquidity_usd","pool_age_hours","volume_24h_usd","price_usd","price_change_1h_pct","price_change_6h_pct","price_change_24h_pct","attention_mentions","attention_z","attention_ratio"],"type":"string"}},"required":["value","low","high"],"type":"object"}},"required":["between"],"type":"object"},"cmp_cross_above":{"additionalProperties":false,"description":"left was at or below right on the previous bar and is above it now","properties":{"cross_above":{"additionalProperties":false,"properties":{"left":{"description":"A field this operator may be used on. Whether the field currently has a value is a separate question — see `x-unavailable` on `#/$defs/field` and the `available` flag in `x-dsl-vocabulary`.","enum":["pool_age_hours","price_change_1h_pct","price_change_6h_pct","price_change_24h_pct","attention_mentions","attention_z","attention_ratio"],"type":"string"},"right":{"$ref":"#/$defs/threshold"}},"required":["left","right"],"type":"object"}},"required":["cross_above"],"type":"object"},"cmp_cross_below":{"additionalProperties":false,"description":"left was at or above right on the previous bar and is below it now","properties":{"cross_below":{"additionalProperties":false,"properties":{"left":{"description":"A field this operator may be used on. Whether the field currently has a value is a separate question — see `x-unavailable` on `#/$defs/field` and the `available` flag in `x-dsl-vocabulary`.","enum":["price_change_1h_pct","price_change_6h_pct","price_change_24h_pct","attention_mentions","attention_z","attention_ratio"],"type":"string"},"right":{"$ref":"#/$defs/threshold"}},"required":["left","right"],"type":"object"}},"required":["cross_below"],"type":"object"},"condition":{"description":"A combinator or a single comparison. Exactly one key.","oneOf":[{"$ref":"#/$defs/all"},{"$ref":"#/$defs/any"},{"$ref":"#/$defs/not"},{"$ref":"#/$defs/cmp_above"},{"$ref":"#/$defs/cmp_below"},{"$ref":"#/$defs/cmp_between"},{"$ref":"#/$defs/cmp_cross_above"},{"$ref":"#/$defs/cmp_cross_below"}]},"field":{"description":"A measured field. Comparing two fields is not in the grammar. A field named in `x-unavailable` is accepted and stored but produces no value on this deployment, so a rule using it holds on every pass rather than firing; availability is read when this document is built, not fixed by the DSL version.","enum":["liquidity_usd","pool_age_hours","volume_24h_usd","price_usd","price_change_1h_pct","price_change_6h_pct","price_change_24h_pct","attention_mentions","attention_z","attention_ratio"],"type":"string","x-unavailable":{"attention_mentions":"No X credential is configured on this deployment, so no attention samples are being collected and this field is nil for every coin. A rule using it is accepted and stored, and holds on every pass until the source is connected — at which point it starts firing with no change to this contract and no new dsl_version.","attention_ratio":"No X credential is configured on this deployment, so no attention samples are being collected and this field is nil for every coin. A rule using it is accepted and stored, and holds on every pass until the source is connected — at which point it starts firing with no change to this contract and no new dsl_version.","attention_z":"No X credential is configured on this deployment, so no attention samples are being collected and this field is nil for every coin. A rule using it is accepted and stored, and holds on every pass until the source is connected — at which point it starts firing with no change to this contract and no new dsl_version."}},"not":{"additionalProperties":false,"properties":{"not":{"$ref":"#/$defs/condition"}},"required":["not"],"type":"object"},"threshold":{"description":"A number in the field's own unit, or a unit object such as {\"value\": 5, \"unit\": \"days\"}. Which unit names a field accepts depends on the field — see `units` in the vocabulary table. The validator rejects a mismatch with an `invalid_unit` error naming the set.","oneOf":[{"type":"number"},{"additionalProperties":false,"properties":{"unit":{"enum":["b","count","days","hours","k","m","minutes","percent","ratio","sigma","usd","weeks","x"],"type":"string"},"value":{"type":"number"}},"required":["value","unit"],"type":"object"}]}},"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"description":"One rule document. Every key is closed vocabulary except \"name\" and \"note\", which are capped free text and are scrubbed of control and invisible characters before they are stored.","properties":{"dsl_version":{"const":"watcher.v1","description":"The vocabulary this rule was written against."},"name":{"description":"Short label. Optional here; required when the rule is created.","maxLength":80,"minLength":1,"type":"string"},"note":{"description":"Free text carried into every alert this rule sends.","maxLength":500,"type":"string"},"universe":{"additionalProperties":false,"description":"Which coins are considered at all. Naming a chain is the single largest reduction in what a rule costs to evaluate; omitting it scans every chain.","properties":{"chain":{"description":"Which chain the coin trades on. Give one chain as a string or several as an array. Naming a chain is the single largest reduction in a rule's evaluation cost; omitting it scans every chain.","oneOf":[{"enum":["base","robinhood","solana"],"type":"string"},{"items":{"enum":["base","robinhood","solana"],"type":"string"},"minItems":1,"type":"array"}]},"gate_passed":{"description":"True once the coin has cleared the mechanical liquidity, age and staleness gate. A coin we have not checked yet reads as false, never as true.","type":"boolean"},"trending":{"description":"True while the coin appears on a data aggregator's trending list. This is a statement about that aggregator's output, computed by methods it does not publish, not an independent measurement of the market.","type":"boolean"}},"type":"object"},"when":{"$ref":"#/$defs/condition"}},"required":["dsl_version","when"],"title":"Coin watcher rule","type":"object","x-dsl-version":"watcher.v1"},"AvailabilityEnvelope":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Availability"}}},"EntitlementError":{"type":"object","description":"`402` — the request was well formed and authorised, and the only thing\nmissing is capacity. Never `403`: nothing about the key was wrong. The\n`entitlement` block names the tier, the limit, what is in use and what\nwould raise it, because a caller that cannot tell its user *why* is the\nexact failure this product exists to remove.\n","properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"const":"entitlement_exceeded","type":"string"},"message":{"type":"string"},"dsl_version":{"type":"string"},"entitlement":{"type":"object"}}}}},"CreateSignalAlertRequest":{"type":"object","description":"`note` may be given here or inside the document; the document is where it belongs, and an outside one is folded in before validation so it is scrubbed and length-checked either way. Everything else here is delivery configuration and is not part of the DSL. There is no `name`: see `SignalAlert.name`.","required":["rule"],"properties":{"rule":{"$ref":"#/components/schemas/SignalAlertRule"},"channel_ids":{"type":["array","null"],"description":"Verified alert channels to deliver on. Omit or null for every verified channel; an empty array means none.","items":{"type":"integer"}},"cooldown_seconds":{"type":"integer","description":"Minimum gap between two fires of this alert.","minimum":0},"one_shot":{"type":"boolean","description":"Fire once, then stop."},"note":{"type":"string","maxLength":280}}},"Availability":{"type":"object","properties":{"exchange":{"type":"string","enum":["coinbase","binanceus","bybit"]},"symbol":{"type":"string","description":"The venue's own spelling, not the one sent."},"exchange_label":{"type":"string"},"setups":{"type":"array","items":{"$ref":"#/components/schemas/AvailabilitySetup"}}}},"Setup":{"type":"object","description":"One curated structure an alert may watch.","properties":{"id":{"type":"string","enum":["ltf_hf_buy","ltf_hf_sell","rsi_oversold","rsi_recovery","rsi_overbought","golden_cross","death_cross","price_reclaims_ma","price_loses_ma","bollinger_lower","bollinger_upper","macd_bullish","macd_bearish","msb_bullish","msb_bearish"]},"label":{"type":"string"},"params":{"type":"array","items":{"type":"object"}},"warmup":{"type":"array","description":"Closed bars needed, per combination of this setup's params — a single number would be wrong for the moving-average setups, where 50 and 200 differ by 150 bars.","items":{"type":"object"}},"side":{"type":"string","enum":["buy_watch","sell_watch"],"description":"Which side the structure signals. A structure signals one side, and offering the other would teach a false reading. It is not an instruction to trade that side."},"timeframes":{"type":"array","description":"The timeframes this setup is defined on, and the only ones it accepts.","items":{"type":"string","enum":["m15","h1","h4","h12","d1","w1"]}},"learn":{"type":"string","description":"What the structure means, in plain English, advice-free. This is the field that lets a reader pick the setup that answers the question it was actually asked."},"plan_refs":{"type":"array","description":"Price measurements this setup permits in plan entry and stop refs.","items":{"type":"string"}},"side_label":{"type":"string"}}},"VocabularyEnvelope":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Vocabulary"}}},"FireList":{"type":"object","properties":{"count":{"type":"integer"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Fire"}},"rule_id":{"type":"integer"}}},"Error":{"type":"object","description":"Every failure has this shape. A response carries exactly one of `data` and\n`error`, so a caller branches on which key is present without knowing which\nendpoint it called or which layer refused it. `dsl_version` is echoed on\nevery error, including ones that have nothing to do with a document, so a\ncaller written against an older vocabulary can tell whether it is failing\non its own JSON or on a schema that moved underneath it.\n","properties":{"error":{"type":"object","required":["code","message","dsl_version"],"properties":{"code":{"type":"string","enum":["unauthorized","forbidden","not_found","invalid_rule","invalid_request","entitlement_exceeded","rejected","rate_limited","not_ready","upstream_unavailable","idempotency_conflict","invalid_idempotency_key"]},"message":{"type":"string"},"dsl_version":{"type":"string"}}}}},"Asset":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":["string","null"]},"symbol":{"type":["string","null"]},"chain":{"type":"string","enum":["base","robinhood","solana"]},"contract_address":{"type":"string"}}},"SignalAlertValidateEnvelope":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SignalAlertValidateResult"}}},"RuleClass":{"type":"object","properties":{"reason":{"type":"string","description":"Present only when `creatable` is false: where the class is created."},"endpoint":{"type":["string","null"]},"dsl_version":{"type":["string","null"],"enum":["watcher.v1","signal.v1",null]},"creatable":{"type":"boolean"}}},"SignalAlertValidateResult":{"type":"object","description":"Nothing was saved. `available` is deliberately absent: whether this setup can run on this market today costs a full candle load to answer and is what `/client/api/signal-alerts/availability` is for.","properties":{"valid":{"const":true,"type":"boolean"},"summary":{"type":"string","description":"One deterministic plain-English sentence, generated from the canonical alert by code rather than by a model."},"warmup":{"$ref":"#/components/schemas/SignalWarmup"},"rule":{"$ref":"#/components/schemas/SignalAlertRule","description":"The canonical form — the venue's spelling of the symbol, the setup's defaults filled in. This, not what you sent, is what gets stored."},"dsl_version":{"const":"signal.v1","type":"string"}}},"SignalAlertEnvelope":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SignalAlert"}}},"SignalAlertRule":{"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"allOf":[{"if":{"properties":{"setup":{"const":"ltf_hf_buy"}},"required":["setup"]},"then":{"properties":{"params":{"additionalProperties":false,"description":"This setup declares no params.","properties":{},"type":"object"},"timeframe":{"enum":["m15"]}}}},{"if":{"properties":{"setup":{"const":"ltf_hf_sell"}},"required":["setup"]},"then":{"properties":{"params":{"additionalProperties":false,"description":"This setup declares no params.","properties":{},"type":"object"},"timeframe":{"enum":["m15"]}}}},{"if":{"properties":{"setup":{"const":"rsi_oversold"}},"required":["setup"]},"then":{"properties":{"params":{"additionalProperties":false,"description":"This setup declares no params.","properties":{},"type":"object"},"timeframe":{"enum":["m15","h1","h4","h12","d1","w1"]}}}},{"if":{"properties":{"setup":{"const":"rsi_recovery"}},"required":["setup"]},"then":{"properties":{"params":{"additionalProperties":false,"description":"This setup declares no params.","properties":{},"type":"object"},"timeframe":{"enum":["m15","h1","h4","h12","d1","w1"]}}}},{"if":{"properties":{"setup":{"const":"rsi_overbought"}},"required":["setup"]},"then":{"properties":{"params":{"additionalProperties":false,"description":"This setup declares no params.","properties":{},"type":"object"},"timeframe":{"enum":["m15","h1","h4","h12","d1","w1"]}}}},{"if":{"properties":{"setup":{"const":"golden_cross"}},"required":["setup"]},"then":{"properties":{"params":{"additionalProperties":false,"description":"This setup declares no params.","properties":{},"type":"object"},"timeframe":{"enum":["d1","w1"]}}}},{"if":{"properties":{"setup":{"const":"death_cross"}},"required":["setup"]},"then":{"properties":{"params":{"additionalProperties":false,"description":"This setup declares no params.","properties":{},"type":"object"},"timeframe":{"enum":["d1","w1"]}}}},{"if":{"properties":{"setup":{"const":"price_reclaims_ma"}},"required":["setup"]},"then":{"properties":{"params":{"additionalProperties":false,"properties":{"period":{"default":50,"description":"Moving average","enum":[50,200],"type":"integer"}},"type":"object"},"timeframe":{"enum":["h4","h12","d1","w1"]}}}},{"if":{"properties":{"setup":{"const":"price_loses_ma"}},"required":["setup"]},"then":{"properties":{"params":{"additionalProperties":false,"properties":{"period":{"default":50,"description":"Moving average","enum":[50,200],"type":"integer"}},"type":"object"},"timeframe":{"enum":["h4","h12","d1","w1"]}}}},{"if":{"properties":{"setup":{"const":"bollinger_lower"}},"required":["setup"]},"then":{"properties":{"params":{"additionalProperties":false,"description":"This setup declares no params.","properties":{},"type":"object"},"timeframe":{"enum":["h1","h4","h12","d1"]}}}},{"if":{"properties":{"setup":{"const":"bollinger_upper"}},"required":["setup"]},"then":{"properties":{"params":{"additionalProperties":false,"description":"This setup declares no params.","properties":{},"type":"object"},"timeframe":{"enum":["h1","h4","h12","d1"]}}}},{"if":{"properties":{"setup":{"const":"macd_bullish"}},"required":["setup"]},"then":{"properties":{"params":{"additionalProperties":false,"description":"This setup declares no params.","properties":{},"type":"object"},"timeframe":{"enum":["h4","h12","d1","w1"]}}}},{"if":{"properties":{"setup":{"const":"macd_bearish"}},"required":["setup"]},"then":{"properties":{"params":{"additionalProperties":false,"description":"This setup declares no params.","properties":{},"type":"object"},"timeframe":{"enum":["h4","h12","d1","w1"]}}}},{"if":{"properties":{"setup":{"const":"msb_bullish"}},"required":["setup"]},"then":{"properties":{"params":{"additionalProperties":false,"description":"This setup declares no params.","properties":{},"type":"object"},"timeframe":{"enum":["m15","h1","h4","h12","d1","w1"]}}}},{"if":{"properties":{"setup":{"const":"msb_bearish"}},"required":["setup"]},"then":{"properties":{"params":{"additionalProperties":false,"description":"This setup declares no params.","properties":{},"type":"object"},"timeframe":{"enum":["m15","h1","h4","h12","d1","w1"]}}}}],"description":"One signal-alert document. `setup`, `exchange`, `symbol` and `timeframe` are required, and for this class those four **are** the rule — which is why they sit in the document rather than beside it. Delivery settings (`channel_ids`, `cooldown_seconds`, `one_shot`) are columns on the alert and belong outside it.","properties":{"dsl_version":{"const":"signal.v1","description":"The setup catalog this alert was written against."},"exchange":{"description":"The venue the market trades on.","enum":["coinbase","binanceus","bybit"],"type":"string"},"note":{"description":"Free text carried into every alert this rule sends. Scrubbed of control and invisible characters before it is stored. Not part of the condition, and not the alert's name — there is no name to set, because the label is generated from the rule itself.","maxLength":280,"type":"string"},"params":{"description":"The chosen setup's declared params. Most setups declare none and accept only an empty object; the moving-average setups take a period. An omitted param is filled from the setup's default. A value outside the declared options is an error rather than a silent correction, so an author learns what the setup offers.","type":"object"},"plan":{"type":"object","required":["side","entry","stop","targets"],"additionalProperties":false,"properties":{"entry":{"type":"object","additionalProperties":false,"properties":{"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"ref":{"type":"string"},"offset_abs":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"offset_pct":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["ref"]},{"not":{"required":["ref"]},"required":["value"]}]},"stop":{"type":"object","additionalProperties":false,"properties":{"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"ref":{"type":"string"},"offset_abs":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"offset_pct":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["ref"]},{"not":{"required":["ref"]},"required":["value"]}]},"labels":{"type":"object","additionalProperties":false,"properties":{"entry":{"type":"string","maxLength":24,"minLength":1},"stop":{"type":"string","maxLength":24,"minLength":1},"r":{"type":"string","maxLength":24,"minLength":1}}},"side":{"type":"string","enum":["long","short"]},"targets":{"type":"array","items":{"type":"object","required":["id"],"additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,15}$"},"label":{"type":"string","maxLength":24,"minLength":1},"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"r":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["r"]},{"not":{"required":["r"]},"required":["value"]}]},"maxItems":5,"minItems":1}},"description":"Optional user-authored entry, stop and target geometry. References resolve from the fire's exact decimal measurements; this records levels and never places orders."},"setup":{"description":"Which curated structure to watch. Closed list: this is not a formula builder, and a setup that is not here has no representation. Every setup's plain-English explainer is in `x-signal-vocabulary.setups[].learn` on this document and at `/client/api/signal-alerts/schema` — read it before choosing, because the ids alone let you write a valid alert rather than the right one.","enum":["ltf_hf_buy","ltf_hf_sell","rsi_oversold","rsi_recovery","rsi_overbought","golden_cross","death_cross","price_reclaims_ma","price_loses_ma","bollinger_lower","bollinger_upper","macd_bullish","macd_bearish","msb_bullish","msb_bearish"],"type":"string"},"symbol":{"description":"A market listed on that venue, spelled the way that venue spells it — the same pair is \"SOL-USD\" on one venue and \"SOLUSDT\" on another, so a symbol is only meaningful next to its exchange. Matching ignores case, and the stored form is the venue's own spelling. The one open value in this document: it is resolved against the venue's market list, not against an enum here.","type":"string"},"timeframe":{"description":"The candle timeframe the setup is evaluated on, at that bar's close. The chosen setup's own list is the narrower constraint — see the per-setup branches below.","enum":["m15","h1","h4","h12","d1","w1"],"type":"string"}},"required":["dsl_version","setup","exchange","symbol","timeframe"],"title":"Signal alert","type":"object","x-dsl-version":"signal.v1"},"SignalAlertList":{"type":"object","properties":{"count":{"type":"integer"},"data":{"type":"array","items":{"$ref":"#/components/schemas/SignalAlert"}}}},"UsageEnvelope":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Usage"}}},"RuleList":{"type":"object","properties":{"count":{"type":"integer"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Rule"}}}},"RuleClasses":{"type":"object","description":"Which of the three entitlement classes this API can actually create,\nwhere, and against which `dsl_version`.\n\n`limits`, `used` and `remaining` count all three because the entitlement\ndoes. Only two have a door on this surface: price alerts are created in\nthe web app and nowhere else, and `creatable: false` with a null endpoint\nsays so. A budget with no endpoint behind it is a capability claim this\nAPI cannot honour, and the reader here is a program — it would see\nremaining price alerts and go looking for the route.\n","properties":{"price_alerts":{"$ref":"#/components/schemas/RuleClass"},"signal_alerts":{"$ref":"#/components/schemas/RuleClass"},"coin_watchers":{"$ref":"#/components/schemas/RuleClass"}}},"AvailabilityTimeframe":{"type":"object","description":"Whether this setup can evaluate on this timeframe for this market right\nnow. When it cannot, `reason` is a code to branch on, `short` and `detail`\nare the sentences a person is shown, and the facts behind the refusal are\nalongside — so a caller never has to parse English to learn how far short\na market is.\n\n`liquidity_unknown` is its own reason on purpose: a liquidity read that\nfailed is unknown, not zero, and reporting it as \"not liquid enough\" would\nbe an answer we cannot support.\n","properties":{"id":{"type":"string","enum":["m15","h1","h4","h12","d1","w1"]},"label":{"type":"string"},"reason":{"type":["string","null"],"enum":["insufficient_history","liquidity_gated","liquidity_reduced","liquidity_unknown","market_offline","timeframe_not_supported","unknown_setup",null],"description":"Null when available."},"short":{"type":["string","null"]},"available":{"type":"boolean"},"detail":{"type":["string","null"]},"bars_held":{"type":"integer","description":"With `insufficient_history` only: closed bars this market has."},"bars_needed":{"type":"integer","description":"With `insufficient_history` only: closed bars the setup warms up on."},"notional_usd_30d":{"type":["string","null"],"description":"With a liquidity reason only. Decimal as a string."},"threshold_usd_30d":{"type":["string","null"],"description":"With a liquidity reason only. Decimal as a string."}}},"Fire":{"type":"object","properties":{"id":{"type":"integer"},"bucket_start":{"type":"string","format":"date-time","description":"The closed bar the rule fired on."},"price":{"type":["string","null"],"description":"Decimal as a string."},"rule_id":{"type":"integer"},"asset":{"$ref":"#/components/schemas/Asset"},"liquidity_usd":{"type":["string","null"],"description":"Decimal as a string."},"note":{"type":["string","null"],"description":"The rule's note, as it was when it fired."},"facts":{"type":"object","description":"Every operand the rule could have read at that bar, not only the ones that were true — enough to answer \"why this coin\" without re-running anything."},"chart_path":{"type":"string","description":"In-app link to the coin's chart with that bar marked."},"outcomes":{"type":"object","description":"Keyed by horizon. A horizon with no row yet is null.","properties":{"h1":{"$ref":"#/components/schemas/Outcome"},"h24":{"$ref":"#/components/schemas/Outcome"}}}}},"KeyUsage":{"type":"object","description":"This key. Never the key material — only the display prefix.","properties":{"label":{"type":["string","null"]},"prefix":{"type":"string","description":"The twelve-character display stub, which begins `dmt_live_`. Enough to tell two keys apart and nothing else."},"scopes":{"type":"array","items":{"type":"string","enum":["rules:read","rules:write","market:read"]}},"last_used_at":{"type":["string","null"],"format":"date-time"},"usage_count":{"type":"integer"}}},"RuleCounts":{"type":"object","properties":{"price_alerts":{"type":"integer"},"signal_alerts":{"type":"integer"},"coin_watchers":{"type":"integer"}}},"Rule":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"status":{"type":"string","enum":["active","paused","gated","triggered"],"description":"`gated` means the system suspended it; `gated_reason` always says why."},"source":{"type":"string","enum":["api","ui"]},"inserted_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"summary":{"type":"string"},"rule":{"$ref":"#/components/schemas/WatcherRule"},"channel_ids":{"type":["array","null"],"items":{"type":"integer"}},"fires":{"type":"array","description":"Present on the single-rule read only: the most recent fires inline. The full, paginated history is at `/rules/{id}/fires`.","items":{"$ref":"#/components/schemas/Fire"}},"cooldown_seconds":{"type":"integer"},"dsl_version":{"type":"string"},"one_shot":{"type":"boolean"},"last_fired_at":{"type":["string","null"],"format":"date-time"},"gated_reason":{"type":["string","null"]},"note":{"type":["string","null"]},"once_per_asset":{"type":"boolean"},"track_record":{"$ref":"#/components/schemas/TrackRecord"}}},"Outcome":{"type":["object","null"],"properties":{"status":{"type":"string","enum":["pending","stamped","unavailable"],"description":"`unavailable` is not zero — see the fires endpoint."},"basis":{"type":["string","null"],"description":"Which price series both ends were read from."},"note":{"type":["string","null"],"description":"Why it could not be scored, when it could not be."},"due_at":{"type":"string","format":"date-time"},"price_then":{"type":["string","null"],"description":"The confirmed close at the horizon, as a decimal string."},"return_pct":{"type":["string","null"],"description":"Percent, as a decimal string."},"stamped_at":{"type":["string","null"],"format":"date-time"}}},"SetupCatalogEnvelope":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SetupCatalog"}}},"RuleEnvelope":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Rule"}}},"ValidateEnvelope":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ValidateResult"}}},"Deleted":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"integer"},"deleted":{"const":true,"type":"boolean"}}}}},"SignalAlertValidateRequest":{"description":"Either the signal-alert document itself, or the document under a `rule` key alongside delivery settings. Both are accepted, for the reason the watcher equivalent gives.","oneOf":[{"$ref":"#/components/schemas/SignalAlertRule"},{"$ref":"#/components/schemas/CreateSignalAlertRequest"}]},"Vocabulary":{"type":"object","description":"The field table, grammar, document skeleton and structural limits — the same content as the `x-dsl-vocabulary` block on this document, plus the cost model and the three notes a first-time reader needs.","properties":{"fields":{"type":"array","items":{"$ref":"#/components/schemas/VocabularyField"}},"document":{"type":"object","description":"A skeleton document to copy."},"operators":{"type":"object"},"unavailable_fields":{"type":"object","description":"Fields this deployment is not producing a value for, as name to reason. The same truth as the per-field `available` flag, in one lookup. Empty when everything is collected."},"dsl_version":{"const":"watcher.v1","type":"string"},"limits":{"type":"object"},"error_codes":{"type":"array","items":{"type":"string","enum":["ambiguous_node","empty","invalid_range","invalid_type","invalid_unit","invalid_value","missing_key","not_an_object","out_of_range","too_deep","too_expensive","too_long","too_many_conditions","too_many_keys","too_many_nodes","unknown_field","unknown_key","unknown_operator","unsupported_operator","wrong_dsl_version","wrong_scope"]}},"chains":{"type":"array","items":{"type":"string","enum":["base","robinhood","solana"]}},"cost":{"type":"object","description":"The unit, the ceiling, the formula, and the levers that reduce it."},"combinators":{"type":"array","items":{"type":"string"}},"notes":{"type":"array","items":{"type":"string"}}}},"ValidateResult":{"type":"object","properties":{"valid":{"const":true,"type":"boolean"},"summary":{"type":"string","description":"One deterministic plain-English sentence describing when the rule fires. Generated by code, not by a model, so it reads the same in a year and is available whether or not anything else is."},"rule":{"$ref":"#/components/schemas/WatcherRule","description":"The canonical form. This, not what you sent, is what gets stored."},"dsl_version":{"type":"string"},"cost":{"$ref":"#/components/schemas/RuleCost"}}},"JsonRpcRequest":{"type":"object","required":["jsonrpc","method"],"properties":{"id":{"type":["string","integer","null"],"description":"Omit for a notification; a notification gets no response."},"params":{"type":"object"},"method":{"type":"string","enum":["initialize","notifications/initialized","ping","tools/list","tools/call"]},"jsonrpc":{"const":"2.0","type":"string"}}},"SignalWarmup":{"type":"object","description":"What this alert needs before it can evaluate at all, stated in the only\nunit that is true for it: closed bars on its own timeframe. This is the\nsignal-alert answer to a watcher's `cost` — a watcher chooses how many\nassets to scan and is priced in asset-hours; an alert has one market and\none timeframe and is bounded by history instead.\n\nThe same 260 bars is a fortnight on the hourly and five years on the\nweekly, which is exactly the difference worth reading before arming\nsomething and waiting. `bars` is null when the setup could not be read,\nwhich is not the same as needing none.\n","properties":{"unit":{"type":"string"},"timeframe":{"type":["string","null"],"enum":["m15","h1","h4","h12","d1","w1",null]},"bars":{"type":["integer","null"]},"timeframe_label":{"type":["string","null"]}}},"ValidationErrors":{"type":"object","description":"The structured rejection, at `422`. `errors` holds **every** problem in the\nrequest, not the first — an author correcting one error per round trip is\nslow, and worse, may fix an early error in a way that only reveals a later\none.\n\n`invalid_rule` is the DSL validator refusing the document;\n`invalid_request` is the save layer refusing what surrounds it (a missing\nname, a `channel_ids` that will not cast). Both render into the same\nsix-key error shape, so there is one structure to parse rather than two.\n","properties":{"error":{"type":"object","required":["code","message","errors"],"properties":{"code":{"type":"string","enum":["invalid_rule","invalid_request"]},"message":{"type":"string"},"errors":{"type":"array","items":{"$ref":"#/components/schemas/ValidationError"}},"dsl_version":{"type":"string"}}}}},"SignalAlertFireList":{"type":"object","properties":{"count":{"type":"integer"},"data":{"type":"array","items":{"$ref":"#/components/schemas/SignalAlertFire"}},"rule_id":{"type":"integer"}}},"ValidateRequest":{"description":"Either the rule document itself, or the document under a `rule` key\nalongside delivery settings. The first is what a model naturally emits\nafter reading the vocabulary, whose skeleton *is* a document; the second\nis what a script sends. Both are accepted, on purpose — refusing either\nwould fail the obvious first attempt on a technicality that has nothing to\ndo with the rule.\n","oneOf":[{"$ref":"#/components/schemas/WatcherRule"},{"$ref":"#/components/schemas/CreateRuleRequest"}]},"AvailabilitySetup":{"type":"object","properties":{"id":{"type":"string","enum":["ltf_hf_buy","ltf_hf_sell","rsi_oversold","rsi_recovery","rsi_overbought","golden_cross","death_cross","price_reclaims_ma","price_loses_ma","bollinger_lower","bollinger_upper","macd_bullish","macd_bearish","msb_bullish","msb_bearish"]},"label":{"type":["string","null"]},"side":{"type":["string","null"],"enum":["buy_watch","sell_watch",null]},"timeframes":{"type":"array","items":{"$ref":"#/components/schemas/AvailabilityTimeframe"}}}},"VocabularyField":{"type":"object","description":"One field a rule may reference.","properties":{"max":{"type":["number","null"]},"min":{"type":["number","null"]},"name":{"type":"string","enum":["attention_mentions","attention_ratio","attention_z","chain","gate_passed","liquidity_usd","pool_age_hours","price_change_1h_pct","price_change_24h_pct","price_change_6h_pct","price_usd","trending","volume_24h_usd"]},"scope":{"type":"string","enum":["universe","condition"],"description":"`universe` fields select which coins are considered at all; `condition` fields are measured per coin and compared inside `when`."},"type":{"type":"string","enum":["number","integer","boolean","enum"]},"unit":{"type":["string","null"]},"values":{"type":["array","null"]},"description":{"type":"string"},"units":{"type":"array","items":{"type":"string"}},"available":{"type":"boolean","description":"Whether this deployment is producing a value for the field right now. False does not mean the field is invalid — it is part of this dsl_version and will be accepted — it means a rule using it stores and then holds on every pass instead of firing. Read at request time, so it can change without the version changing."},"operators":{"type":"array","items":{"type":"string","enum":["above","below","between","cross_above","cross_below","is","one_of"]}},"history_hours":{"type":"integer","description":"Per-coin history the field needs before it means anything. Drives what a rule costs to evaluate."},"unavailable_reason":{"type":["string","null"],"description":"Why there is no value, or null when there is one."}}},"RuleCost":{"type":"object","description":"What one evaluation of this rule implies, in asset-hours: coins considered times the history its most demanding field needs.","properties":{"unit":{"const":"asset-hours","type":"string"},"units":{"type":"integer"},"ceiling":{"type":"integer"},"assets":{"type":"integer"},"drivers":{"type":"array","items":{"type":"string"}},"history_hours":{"type":"integer"}}},"TrackRecord":{"type":"object","description":"This rule's own stamped record at `+24h`, and nothing else. `n` is the\nnumber of **scored** fires — the population the rate is computed over —\nbecause a hit rate over three fires and one over thirty are different\nclaims. `pending` and `unavailable` sit beside it so the omissions are\nvisible rather than silent, and `caveat` states the limitation in a\nsentence while the sample is small.\n\nDo not quote `hit_rate_24h` without `n`. A rate with no sample size is the\none number in this API that can mislead on its own.\n","properties":{"pending":{"type":"integer"},"n":{"type":"integer","description":"Scored fires — the population behind the rate."},"unavailable":{"type":"integer"},"fires":{"type":"integer","description":"Total fires, scored or not."},"caveat":{"type":["string","null"],"description":"The limitation, in one sentence, or null when there is none."},"horizon":{"const":"24h","type":"string"},"bases":{"type":"object","description":"Which price bases the returns were measured on."},"hit_rate_24h":{"type":["number","null"],"description":"Share of scored fires higher 24h later. Null when nothing is scored."},"median_24h":{"type":["string","null"],"description":"Median 24h return, percent, as a decimal string."},"sufficient":{"type":"boolean","description":"Whether `n` has reached the size below which a rate is not worth quoting."}}},"CreateRuleRequest":{"type":"object","description":"`name` and `note` may be given here or inside the rule document; the top level wins. Everything else is delivery configuration and is not part of the DSL.","required":["rule"],"properties":{"name":{"type":"string","maxLength":80,"minLength":1},"rule":{"$ref":"#/components/schemas/WatcherRule"},"channel_ids":{"type":["array","null"],"description":"Verified alert channels to deliver on. Omit or null for every verified channel; an empty array means none.","items":{"type":"integer"}},"cooldown_seconds":{"type":"integer","description":"Rate limit across the whole rule, so a rule that suddenly matches forty coins does not send forty messages.","minimum":0},"one_shot":{"type":"boolean","description":"Fire once, then stop."},"note":{"type":"string","maxLength":500},"once_per_asset":{"type":"boolean","description":"Report each coin at most once, ever. This is what \"tell me when a coin first does X\" actually means."}}},"JsonRpcResponse":{"type":"object","required":["jsonrpc","id"],"properties":{"error":{"type":"object","properties":{"code":{"type":"integer"},"data":{"type":"object"},"message":{"type":"string"}}},"id":{"type":["string","integer","null"]},"result":{"type":"object"},"jsonrpc":{"const":"2.0","type":"string"}}},"Usage":{"type":"object","properties":{"used":{"$ref":"#/components/schemas/RuleCounts"},"api_key":{"$ref":"#/components/schemas/KeyUsage"},"remaining":{"$ref":"#/components/schemas/RuleCounts"},"wallet":{"type":["string","null"]},"dsl_version":{"type":"string"},"limits":{"$ref":"#/components/schemas/RuleCounts"},"unknown_balance":{"type":"boolean","description":"True when a wallet exists and could not be read. Limits then show the fail-closed floor, which is not a statement about holdings."},"tier":{"type":"string"},"nsf_balance":{"type":["string","null"],"description":"Decimal as a string. Null when there is no wallet, or none readable."},"rule_classes":{"$ref":"#/components/schemas/RuleClasses"}}},"ValidationError":{"type":"object","description":"One problem. All six keys are always present. Both rule classes emit this exact shape, so one parser reads both; the `code` enum is therefore the union of the two validators' sets, and `x-validation-error-codes` on this document splits it by `dsl_version` for a caller that only writes one class.","required":["path","code","message","expected","got","suggestion"],"properties":{"code":{"type":"string","enum":["ambiguous_node","empty","invalid_plan_offset","invalid_plan_target","invalid_range","invalid_type","invalid_unit","invalid_value","missing_key","not_an_object","out_of_range","plan_too_many_targets","too_deep","too_expensive","too_long","too_many_conditions","too_many_keys","too_many_nodes","unknown_field","unknown_key","unknown_market","unknown_operator","unknown_plan_ref","unsupported_operator","unsupported_timeframe","wrong_dsl_version","wrong_scope"]},"message":{"type":"string","description":"What is wrong, in one sentence."},"path":{"type":"string","description":"Where in the document, e.g. `when.all[1].above.right` or `params.period`."},"expected":{"description":"What would have been accepted here. Any JSON type."},"got":{"description":"What was found, reduced to its kind when it is large."},"suggestion":{"type":["string","null"],"description":"A concrete correction, or null when there is nothing useful to say."}}},"SignalAlert":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string","description":"The alert read back as a sentence, e.g. \"RSI crosses into oversold on\nthe 1 day — SOL-USD (Coinbase)\". **Generated, not stored.** There is\nno name column on a signal alert and no way to set one: a stored label\nis a second answer to \"what does this watch\" that can disagree with\nthe first. Identical to `summary`, which carries it under the name the\nwatcher class uses. Your own words go in `note`.\n"},"status":{"type":"string","enum":["active","paused","gated","triggered"],"description":"`gated` means the system suspended it; `gated_reason` always says why."},"state":{"type":["string","null"],"description":"The hysteresis state. `waiting_rearm` means the condition is still\ntrue and the alert is waiting for it to stop being true before it may\nfire again — published because it is the other reason an armed alert\ncan be silent, and without it `status: \"active\"` plus no recent fire\ncannot be told apart from \"it already told you\".\n"},"source":{"type":"string","enum":["api","ui"],"description":"Where the alert was created. Stamped by the server; not a field a request can set."},"inserted_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"summary":{"type":"string","description":"The same string as `name`."},"warmup":{"$ref":"#/components/schemas/SignalWarmup"},"rule":{"$ref":"#/components/schemas/SignalAlertRule","description":"The stored alert as its document — the same shape validation canonicalises to, so it can be resubmitted unchanged."},"channel_ids":{"type":["array","null"],"items":{"type":"integer"}},"cooldown_seconds":{"type":"integer"},"dsl_version":{"const":"signal.v1","type":"string"},"one_shot":{"type":"boolean"},"recent_fires":{"type":"array","description":"Present on the single-alert read only. The full, paginated history is at `/signal-alerts/{id}/fires`.","items":{"$ref":"#/components/schemas/SignalAlertFire"}},"last_fired_at":{"type":["string","null"],"format":"date-time"},"gated_reason":{"type":["string","null"]},"note":{"type":["string","null"]},"track_record":{"$ref":"#/components/schemas/TrackRecord"}}},"SetupCatalog":{"type":"object","description":"The signal-alert vocabulary — the same content as the `x-signal-vocabulary` block on this document.","properties":{"keys":{"type":"object","description":"What each document key means."},"document":{"type":"object","description":"A skeleton document to copy."},"timeframes":{"type":"array","items":{"type":"object"}},"dsl_version":{"const":"signal.v1","type":"string"},"limits":{"type":"object"},"exchanges":{"type":"array","items":{"type":"object"}},"setups":{"type":"array","items":{"$ref":"#/components/schemas/Setup"}},"warmup_unit":{"type":"string"}}}},"securitySchemes":{"bearerAuth":{"scheme":"bearer","type":"http","description":"An API key issued in the web app under API keys. Sent as `Authorization: Bearer dmt_live_…`. Never in a query parameter."}}},"paths":{"/client/api/condition-alerts":{"get":{"description":"List owned advanced conditions with revisions, persisted sequence state and evaluation health. Required scopes: rules:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[],"summary":"List owned advanced conditions with revisions, persisted sequence state and evaluation health. Required scopes: rules:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"alerts":{"type":"array","items":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"status":{"type":"string"},"state":{"type":"object"},"revision":{"type":"integer"},"summary":{"type":"string"},"rule":{"type":"object"},"channel_ids":{"type":["array","null"],"items":{"type":"integer"}},"evaluation":{"type":"object"},"cooldown_seconds":{"type":"integer"},"dsl_version":{"const":"condition.v1"},"one_shot":{"type":"boolean"}}}}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"list_condition_alerts","x-required-scopes":["rules:read"]},"post":{"description":"Save a condition.v1 document. A ready document becomes active; a valid blocked document is saved explicitly as a draft with its blockers. Required scopes: rules:write, market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[],"summary":"Save a condition.v1 document. A ready document becomes active; a valid blocked document is saved explicitly as a draft with its blockers. Required scopes: rules:write, market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"status":{"type":"string"},"state":{"type":"object"},"revision":{"type":"integer"},"summary":{"type":"string"},"rule":{"type":"object"},"channel_ids":{"type":["array","null"],"items":{"type":"integer"}},"evaluation":{"type":"object"},"cooldown_seconds":{"type":"integer"},"dsl_version":{"const":"condition.v1"},"one_shot":{"type":"boolean"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["rule"],"additionalProperties":false,"properties":{"channel_ids":{"type":"array","items":{"maximum":2147483647,"type":"integer","minimum":1}},"cooldown_seconds":{"maximum":2147483647,"type":"integer","minimum":0},"idempotency_key":{"type":"string","description":"Stable create retry key, shared with REST Idempotency-Key.","maxLength":128,"minLength":1},"one_shot":{"type":"boolean"},"rule":{"type":"object","required":["dsl_version","name","exchange","symbol","timeframe"],"additionalProperties":false,"properties":{"name":{"type":"string","maxLength":120,"minLength":1},"exchange":{"type":"string","enum":["coinbase","binanceus","bybit"]},"when":{"type":"object"},"params":{"type":"object"},"symbol":{"type":"string","maxLength":80,"minLength":1},"plan":{"type":"object","required":["side","entry","stop","targets"],"additionalProperties":false,"properties":{"entry":{"type":"object","additionalProperties":false,"properties":{"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"ref":{"type":"string"},"offset_abs":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"offset_pct":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["ref"]},{"not":{"required":["ref"]},"required":["value"]}]},"stop":{"type":"object","additionalProperties":false,"properties":{"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"ref":{"type":"string"},"offset_abs":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"offset_pct":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["ref"]},{"not":{"required":["ref"]},"required":["value"]}]},"labels":{"type":"object","additionalProperties":false,"properties":{"entry":{"type":"string","maxLength":24,"minLength":1},"stop":{"type":"string","maxLength":24,"minLength":1},"r":{"type":"string","maxLength":24,"minLength":1}}},"side":{"type":"string","enum":["long","short"]},"targets":{"type":"array","items":{"type":"object","required":["id"],"additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,15}$"},"label":{"type":"string","maxLength":24,"minLength":1},"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"r":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["r"]},{"not":{"required":["r"]},"required":["value"]}]},"maxItems":5,"minItems":1}}},"direction":{"type":"string","enum":["rise","fall","neutral"]},"sequence":{"type":"object"},"indicators":{"type":"object"},"dsl_version":{"type":"string","enum":["condition.v1"]},"timeframe":{"type":"string","enum":["m15","h1","h4","h12","d1","w1"]},"note":{"type":"string","maxLength":280},"rearm":{"type":"object"}},"oneOf":[{"required":["when"]},{"required":["sequence"]}]}}}}}},"operationId":"create_condition_alert","x-required-scopes":["rules:write","market:read"]}},"/client/api/signal-baskets/{id}":{"get":{"description":"Read one owned basket and its members. Member fire histories use get_signal_alert_fires with the returned rule IDs. Required scopes: rules:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"path","name":"id","required":true,"schema":{"maximum":2147483647,"type":"integer","minimum":1}}],"summary":"Read one owned basket and its members. Member fire histories use get_signal_alert_fires with the returned rule IDs. Required scopes: rules:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"name":{"type":"string"},"status":{"type":"string","enum":["active","paused"]},"members":{"type":"array","items":{"type":"object","description":"Signal alert representation with basket_id and basket_member_active; use id with the signal-alert fire endpoint."}},"revision":{"type":"integer"},"document":{"type":"object"},"member_symbols":{"type":"array","items":{"type":"string"}},"quota_unit":{"type":"string"},"readiness":{"type":"object"},"refreshed_at":{"type":["string","null"],"format":"date-time"},"selection":{"type":"object"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"get_signal_basket","x-required-scopes":["rules:read"]},"delete":{"description":"Delete your basket, its member alerts and their fire history. Required scopes: rules:write. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"path","name":"id","required":true,"schema":{"maximum":2147483647,"type":"integer","minimum":1}}],"summary":"Delete your basket, its member alerts and their fire history. Required scopes: rules:write. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"deleted":{"const":true}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"delete_signal_basket","x-required-scopes":["rules:write"]},"patch":{"description":"Patch one or more fields on an owned basket after preflight. expected_revision is required; stale edits return the current revision. Omitted fields retain their stored values, plan:null clears a plan, and a complete definition remains valid. Membership and delivery changes activate atomically and child alerts cannot be edited independently. Required scopes: rules:write, rules:read, market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"path","name":"id","required":true,"schema":{"maximum":2147483647,"type":"integer","minimum":1}}],"summary":"Patch one or more fields on an owned basket after preflight. expected_revision is required; stale edits return the current revision. Omitted fields retain their stored values, plan:null clears a plan, and a complete definition remains valid. Membership and delivery changes activate atomically and child alerts cannot be edited independently. Required scopes: rules:write, rules:read, market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"name":{"type":"string"},"status":{"type":"string","enum":["active","paused"]},"members":{"type":"array","items":{"type":"object","description":"Signal alert representation with basket_id and basket_member_active; use id with the signal-alert fire endpoint."}},"revision":{"type":"integer"},"document":{"type":"object"},"member_symbols":{"type":"array","items":{"type":"string"}},"quota_unit":{"type":"string"},"readiness":{"type":"object"},"refreshed_at":{"type":["string","null"],"format":"date-time"},"selection":{"type":"object"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"requestBody":{"description":"Partial basket patch. Supply expected_revision plus one or more basket fields; omitted fields retain their stored values.","required":true,"content":{"application/json":{"schema":{"type":"object","required":["expected_revision"],"additionalProperties":false,"properties":{"channel_ids":{"type":"array","items":{"maximum":2147483647,"type":"integer","minimum":1}},"cooldown_seconds":{"maximum":2147483647,"type":"integer","minimum":0},"dsl_version":{"type":"string","enum":["basket.v1"]},"exchange":{"type":"string","enum":["coinbase","binanceus","bybit"]},"expected_revision":{"maximum":2147483647,"type":"integer","minimum":1},"name":{"type":"string","maxLength":120,"minLength":1},"note":{"type":"string"},"one_shot":{"type":"boolean"},"params":{"type":"object"},"plan":{"description":"Set or replace the fire-time plan; null removes the stored plan.","oneOf":[{"type":"object","required":["side","entry","stop","targets"],"additionalProperties":false,"properties":{"entry":{"type":"object","additionalProperties":false,"properties":{"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"ref":{"type":"string"},"offset_abs":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"offset_pct":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["ref"]},{"not":{"required":["ref"]},"required":["value"]}]},"stop":{"type":"object","additionalProperties":false,"properties":{"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"ref":{"type":"string"},"offset_abs":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"offset_pct":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["ref"]},{"not":{"required":["ref"]},"required":["value"]}]},"labels":{"type":"object","additionalProperties":false,"properties":{"entry":{"type":"string","maxLength":24,"minLength":1},"stop":{"type":"string","maxLength":24,"minLength":1},"r":{"type":"string","maxLength":24,"minLength":1}}},"side":{"type":"string","enum":["long","short"]},"targets":{"type":"array","items":{"type":"object","required":["id"],"additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,15}$"},"label":{"type":"string","maxLength":24,"minLength":1},"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"r":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["r"]},{"not":{"required":["r"]},"required":["value"]}]},"maxItems":5,"minItems":1}}},{"type":"null"}]},"setup":{"type":"string","enum":["ltf_hf_buy","ltf_hf_sell","rsi_oversold","rsi_recovery","rsi_overbought","golden_cross","death_cross","price_reclaims_ma","price_loses_ma","bollinger_lower","bollinger_upper","macd_bullish","macd_bearish","msb_bullish","msb_bearish"]},"timeframe":{"type":"string","enum":["m15","h1","h4","h12","d1","w1"]},"universe":{"oneOf":[{"type":"object","required":["symbols"],"additionalProperties":false,"properties":{"symbols":{"type":"array","items":{"type":"string"},"maxItems":20,"minItems":1,"uniqueItems":true}}},{"type":"object","required":["top_n","sort"],"additionalProperties":false,"properties":{"exclude_bases":{"type":"array","items":{"type":"string"},"maxItems":50,"uniqueItems":true},"major_only":{"type":"boolean"},"min_volume_24h_usd":{"type":"string","description":"Optional exact decimal USD-equivalent 24h notional floor.","pattern":"^[0-9]+(?:\\.[0-9]+)?$"},"quote":{"type":"string","description":"Optional exact quote asset, for example USDT."},"sort":{"type":"string","enum":["volume_24h_usd"]},"top_n":{"maximum":20,"type":"integer","minimum":1}}}]}}}}}},"operationId":"update_signal_basket","x-required-scopes":["rules:write","rules:read","market:read"]}},"/client/api/mcp":{"post":{"description":"JSON-RPC 2.0 over HTTP. Methods: initialize, notifications/initialized, ping, tools/list, tools/call.\n\n**Both rule classes are here**, and a tool's name says which one it\nspeaks for.\n\nCoin watchers, mirroring the `/client/api/rules` endpoints:\n`get_vocabulary`, `validate_rule`, `create_rule`, `list_rules`,\n`get_rule`, `pause_rule`, `resume_rule`, `delete_rule`, `get_fires`.\n\nSignal alerts, mirroring `/client/api/signal-alerts`:\n`get_signal_setups`, `check_signal_availability`,\n`validate_signal_alert`, `create_signal_alert`, `list_signal_alerts`,\n`get_signal_alert`, `update_signal_alert`, `pause_signal_alert`,\n`resume_signal_alert`, `delete_signal_alert`,\n`get_signal_alert_fires`.\n\nAssistant and basket tools: get_capabilities, list_markets, get_ohlcv, get_ohlcv_batch, get_derivatives_series, get_derivatives_snapshot, get_market_levels, get_assistant_context, get_onchain_asset, prepare_market, get_market_preparation, preflight_rule, create_price_alert, list_price_alerts, get_price_alert, update_price_alert, pause_price_alert, resume_price_alert, delete_price_alert, get_price_alert_fires, preflight_condition_alert, create_condition_alert, list_condition_alerts, get_condition_alert, update_condition_alert, pause_condition_alert, resume_condition_alert, delete_condition_alert, get_condition_alert_fires, get_condition_alert_versions, replay_condition_alert, preflight_signal_basket, create_signal_basket, list_signal_baskets, get_signal_basket, update_signal_basket, pause_signal_basket, resume_signal_basket, delete_signal_basket.\n\nAnd `get_usage`, which covers the account both classes are counted\nagainst.\n\nThey are authorised by the same key and the same scopes, so a\n`rules:read` key cannot create a rule of either class through MCP\neither, and `tools/list` returns only the tools the presented key can\ncall. The two contract tools — `get_vocabulary` and\n`get_signal_setups` — need no scope beyond a valid key, because they\npublish what this engine speaks and disclose nothing about any account.\n`check_signal_availability` needs `market:read` and spends the same\nper-key allowance as `GET /client/api/signal-alerts/availability`: it\nis the same candle load, so it is one budget rather than one per\nprotocol.\n\nPoint an MCP client at this URL with the key as a bearer token.\n","summary":"Model Context Protocol endpoint","tags":["MCP"],"responses":{"200":{"description":"A JSON-RPC response object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcResponse"}}}},"202":{"description":"A JSON-RPC notification was accepted; no response body"},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcRequest"}}}}}},"/client/api/market-preparations/{id}":{"get":{"description":"Read one owned market-preparation request with requested depth, stored coverage, gaps, the latest engine-confirmed bar, progress and a retryable blocker. Required scopes: market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"path","name":"id","required":true,"schema":{"maximum":2147483647,"type":"integer","minimum":1}}],"summary":"Read one owned market-preparation request with requested depth, stored coverage, gaps, the latest engine-confirmed bar, progress and a retryable blocker. Required scopes: market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"status":{"type":"string","enum":["queued","running","ready","blocked","failed"]},"exchange":{"type":"string"},"progress":{"type":"object"},"started_at":{"type":["string","null"],"format":"date-time"},"coverage":{"type":"object"},"setup":{"type":"string"},"symbol":{"type":"string"},"confirmation":{"type":"string"},"completed_at":{"type":["string","null"],"format":"date-time"},"retryable":{"type":"boolean"},"blocker":{"type":["string","null"]},"timeframe":{"type":"string"},"attempts":{"type":"integer"},"requested_depth":{"type":"object"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"get_market_preparation","x-required-scopes":["market:read"]}},"/client/api/markets":{"get":{"description":"Find spot symbols. volume_24h_usd returns the curated top-20 USD-equivalent volume ranking (not order-book liquidity). sort=symbol searches all online instruments. Missing/stale catalogs are explicit. Required scopes: market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"query","name":"exchange","required":true,"schema":{"type":"string"}},{"in":"query","name":"limit","required":false,"schema":{"maximum":100,"type":"integer","minimum":1}},{"in":"query","name":"query","required":false,"schema":{"type":"string"}},{"in":"query","name":"sort","required":false,"schema":{"type":"string","enum":["volume_24h_usd","symbol"]}}],"summary":"Find spot symbols. volume_24h_usd returns the curated top-20 USD-equivalent volume ranking (not order-book liquidity). sort=symbol searches all online instruments. Missing/stale catalogs are explicit. Required scopes: market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"count":{"type":"integer"},"status":{"type":"string","enum":["available","stale","unavailable"]},"exchange":{"type":"string"},"sort":{"type":"string"},"markets":{"type":"array","items":{"type":"object","properties":{"symbol":{"type":"string"},"rank":{"type":["integer","null"]},"price":{"type":["string","null"],"description":"Exact decimal text; never a JSON float."},"base_asset":{"type":"string"},"price_increment":{"type":["string","null"],"description":"Exact decimal text; never a JSON float."},"quote_asset":{"type":"string"},"volume_24h":{"type":["string","null"],"description":"Exact decimal text; never a JSON float."},"volume_24h_quote":{"type":["string","null"],"description":"Exact decimal text; never a JSON float."},"volume_24h_unit":{"type":"string"}}}},"market_type":{"type":"string"},"ranking":{"type":"string"},"as_of":{"type":["string","null"],"format":"date-time"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"list_markets","x-required-scopes":["market:read"]}},"/client/api/capabilities":{"get":{"description":"Discover rule families, offered venues and catalog freshness, separate read/evaluation timeframes, account quota and delivery readiness. Start here; offered does not mean ready. Required scopes: rules:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[],"summary":"Discover rule families, offered venues and catalog freshness, separate read/evaluation timeframes, account quota and delivery readiness. Start here; offered does not mean ready. Required scopes: rules:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"operations":{"type":"array","items":{"type":"object"}},"delivery":{"type":"object","required":["ready","blockers","channels","transports"],"properties":{"ready":{"type":"boolean"},"channels":{"type":"array","items":{"type":"object"}},"blockers":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"channel_id":{"type":"integer"}}}},"transports":{"type":"array","items":{"type":"object"}}}},"account":{"type":"object"},"alert_plans":{"type":"object"},"basket_limit":{"type":"integer"},"basket_quota":{"type":"string"},"checked_at":{"type":["string","null"],"format":"date-time"},"condition_dsl":{"type":"object"},"derivatives":{"type":"object"},"evaluation_modes":{"type":"object"},"halted_reason":{"type":["string","null"]},"idempotency":{"type":"object"},"market_read_timeframes":{"type":"array","items":{"type":"string"}},"preflight_examples":{"type":"object"},"rule_versions":{"type":"array","items":{"type":"string"}},"signal_timeframes":{"type":"array","items":{"type":"string"}},"venues":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"market_type":{"type":"string"},"catalog_as_of":{"type":["string","null"],"format":"date-time"},"catalog_status":{"type":"string"},"market_count":{"type":"integer"}}}},"watcher_unavailable_fields":{"type":"object"},"workflow":{"type":"array","items":{"type":"string"}}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"get_capabilities","x-required-scopes":["rules:read"]}},"/client/api/signal-baskets":{"get":{"description":"List your signal baskets, desired membership, member rule IDs, readiness and retained history. Required scopes: rules:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[],"summary":"List your signal baskets, desired membership, member rule IDs, readiness and retained history. Required scopes: rules:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"baskets":{"type":"array","items":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"name":{"type":"string"},"status":{"type":"string","enum":["active","paused"]},"members":{"type":"array","items":{"type":"object","description":"Signal alert representation with basket_id and basket_member_active; use id with the signal-alert fire endpoint."}},"revision":{"type":"integer"},"document":{"type":"object"},"member_symbols":{"type":"array","items":{"type":"string"}},"quota_unit":{"type":"string"},"readiness":{"type":"object"},"refreshed_at":{"type":["string","null"],"format":"date-time"},"selection":{"type":"object"}}}}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"list_signal_baskets","x-required-scopes":["rules:read"]},"post":{"description":"Create a basket.v1 atomically after preflight. It uses one basket allowance plus one active-member evaluation unit per selected market; standalone signal slots are separate. top_n refreshes on successful catalog sync; symbols is fixed. one_shot applies per member. Requires rules:write, rules:read and market:read. Required scopes: rules:write, rules:read, market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"header","name":"Idempotency-Key","description":"Stable create retry key, scoped to this owner and operation across REST/MCP. Same normalized body replays the original 201 snapshot, including after deletion; a changed body returns 409. Receipts persist for the account lifetime. Read the resource for current status. Omission creates a new rule each time.","required":false,"schema":{"type":"string","pattern":"^[!-~]+$","maxLength":128,"minLength":1}}],"summary":"Create a basket.v1 atomically after preflight. It uses one basket allowance plus one active-member evaluation unit per selected market; standalone signal slots are separate. top_n refreshes on successful catalog sync; symbols is fixed. one_shot applies per member. Requires rules:write, rules:read and market:read. Required scopes: rules:write, rules:read, market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"201":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"name":{"type":"string"},"status":{"type":"string","enum":["active","paused"]},"members":{"type":"array","items":{"type":"object","description":"Signal alert representation with basket_id and basket_member_active; use id with the signal-alert fire endpoint."}},"revision":{"type":"integer"},"document":{"type":"object"},"member_symbols":{"type":"array","items":{"type":"string"}},"quota_unit":{"type":"string"},"readiness":{"type":"object"},"refreshed_at":{"type":["string","null"],"format":"date-time"},"selection":{"type":"object"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","dsl_version","setup","exchange","timeframe","universe"],"additionalProperties":false,"properties":{"channel_ids":{"type":"array","items":{"maximum":2147483647,"type":"integer","minimum":1}},"cooldown_seconds":{"maximum":2147483647,"type":"integer","minimum":0},"dsl_version":{"type":"string","enum":["basket.v1"]},"exchange":{"type":"string","enum":["coinbase","binanceus","bybit"]},"idempotency_key":{"type":"string","description":"Stable create retry key, shared with REST Idempotency-Key. Replays return the original snapshot; use get to read current status.","maxLength":128,"minLength":1},"name":{"type":"string","maxLength":120,"minLength":1},"note":{"type":"string"},"one_shot":{"type":"boolean"},"params":{"type":"object"},"plan":{"type":"object","required":["side","entry","stop","targets"],"additionalProperties":false,"properties":{"entry":{"type":"object","additionalProperties":false,"properties":{"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"ref":{"type":"string"},"offset_abs":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"offset_pct":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["ref"]},{"not":{"required":["ref"]},"required":["value"]}]},"stop":{"type":"object","additionalProperties":false,"properties":{"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"ref":{"type":"string"},"offset_abs":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"offset_pct":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["ref"]},{"not":{"required":["ref"]},"required":["value"]}]},"labels":{"type":"object","additionalProperties":false,"properties":{"entry":{"type":"string","maxLength":24,"minLength":1},"stop":{"type":"string","maxLength":24,"minLength":1},"r":{"type":"string","maxLength":24,"minLength":1}}},"side":{"type":"string","enum":["long","short"]},"targets":{"type":"array","items":{"type":"object","required":["id"],"additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,15}$"},"label":{"type":"string","maxLength":24,"minLength":1},"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"r":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["r"]},{"not":{"required":["r"]},"required":["value"]}]},"maxItems":5,"minItems":1}}},"setup":{"type":"string","enum":["ltf_hf_buy","ltf_hf_sell","rsi_oversold","rsi_recovery","rsi_overbought","golden_cross","death_cross","price_reclaims_ma","price_loses_ma","bollinger_lower","bollinger_upper","macd_bullish","macd_bearish","msb_bullish","msb_bearish"]},"timeframe":{"type":"string","enum":["m15","h1","h4","h12","d1","w1"]},"universe":{"oneOf":[{"type":"object","required":["symbols"],"additionalProperties":false,"properties":{"symbols":{"type":"array","items":{"type":"string"},"maxItems":20,"minItems":1,"uniqueItems":true}}},{"type":"object","required":["top_n","sort"],"additionalProperties":false,"properties":{"exclude_bases":{"type":"array","items":{"type":"string"},"maxItems":50,"uniqueItems":true},"major_only":{"type":"boolean"},"min_volume_24h_usd":{"type":"string","description":"Optional exact decimal USD-equivalent 24h notional floor.","pattern":"^[0-9]+(?:\\.[0-9]+)?$"},"quote":{"type":"string","description":"Optional exact quote asset, for example USDT."},"sort":{"type":"string","enum":["volume_24h_usd"]},"top_n":{"maximum":20,"type":"integer","minimum":1}}}]}}}}}},"operationId":"create_signal_basket","x-required-scopes":["rules:write","rules:read","market:read"]}},"/client/api/price-alerts/{id}/resume":{"post":{"description":"Resume one owned price alert; the next fresh observation seeds a new crossing baseline. Required scopes: rules:write. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"path","name":"id","required":true,"schema":{"maximum":2147483647,"type":"integer","minimum":1}}],"summary":"Resume one owned price alert; the next fresh observation seeds a new crossing baseline. Required scopes: rules:write. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"status":{"type":"string"},"revision":{"type":"integer"},"summary":{"type":"string"},"rule":{"type":"object"},"channel_ids":{"type":"array","items":{"type":"integer"}},"evaluation":{"type":"object"},"cooldown_seconds":{"type":"integer"},"dsl_version":{"const":"price.v1"},"one_shot":{"type":"boolean"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"resume_price_alert","x-required-scopes":["rules:write"]}},"/client/api/price-alerts":{"get":{"description":"List owned price alerts with exact thresholds, revisions and evaluation health. Required scopes: rules:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[],"summary":"List owned price alerts with exact thresholds, revisions and evaluation health. Required scopes: rules:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"alerts":{"type":"array","items":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"status":{"type":"string"},"revision":{"type":"integer"},"summary":{"type":"string"},"rule":{"type":"object"},"channel_ids":{"type":"array","items":{"type":"integer"}},"evaluation":{"type":"object"},"cooldown_seconds":{"type":"integer"},"dsl_version":{"const":"price.v1"},"one_shot":{"type":"boolean"}}}}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"list_price_alerts","x-required-scopes":["rules:read"]},"post":{"description":"Create an observed-tick exact Decimal price crossing or percent-move alert on one listed spot market. A crossing uses persisted before/after observations; missing or stale prices are reported as unknown. Use condition.v1 close_above, close_below, enter or leave for successor-confirmed closed-bar alerts. Required scopes: rules:write. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[],"summary":"Create an observed-tick exact Decimal price crossing or percent-move alert on one listed spot market. A crossing uses persisted before/after observations; missing or stale prices are reported as unknown. Use condition.v1 close_above, close_below, enter or leave for successor-confirmed closed-bar alerts. Required scopes: rules:write. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"status":{"type":"string"},"revision":{"type":"integer"},"summary":{"type":"string"},"rule":{"type":"object"},"channel_ids":{"type":"array","items":{"type":"integer"}},"evaluation":{"type":"object"},"cooldown_seconds":{"type":"integer"},"dsl_version":{"const":"price.v1"},"one_shot":{"type":"boolean"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["dsl_version","exchange","symbol","kind","direction","threshold"],"additionalProperties":false,"properties":{"channel_ids":{"type":"array","items":{"maximum":2147483647,"type":"integer","minimum":1}},"cooldown_seconds":{"maximum":2147483647,"type":"integer","minimum":0},"direction":{"type":"string","enum":["above","below"]},"dsl_version":{"type":"string","enum":["price.v1"]},"exchange":{"type":"string","enum":["coinbase","binanceus","bybit"]},"idempotency_key":{"type":"string","description":"Stable create retry key, shared with REST Idempotency-Key.","maxLength":128,"minLength":1},"kind":{"type":"string","enum":["price","percent"]},"mode":{"type":"string","enum":["observed_tick"],"description":"Optional explicit timing mode; defaults to observed_tick. Use condition.v1 for closed-bar evaluation."},"note":{"type":"string","maxLength":280},"one_shot":{"type":"boolean"},"symbol":{"type":"string"},"threshold":{"type":"string","description":"Exact positive decimal text; JSON numbers are rejected.","pattern":"^[0-9]+(?:\\.[0-9]+)?$"},"window_seconds":{"maximum":604800,"type":"integer","minimum":1}}}}}},"operationId":"create_price_alert","x-required-scopes":["rules:write"]}},"/client/api/signal-alerts/{id}":{"get":{"description":"The alert with its most recent fires inline, under `recent_fires`. The\nfull paginated history is at `/client/api/signal-alerts/{id}/fires`.\n\n`rules:read`. An alert belonging to someone else is `404`, never `403`,\nfor the reason the rules endpoints give.\n","parameters":[{"in":"path","name":"id","description":"Rule id","required":true,"schema":{"type":"integer"}}],"summary":"Fetch one signal alert","tags":["Signal alerts"],"responses":{"200":{"description":"The alert","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignalAlertEnvelope"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such alert on this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"description":"Permanent, and it takes the alert's fire history with it. `rules:write`.","parameters":[{"in":"path","name":"id","description":"Rule id","required":true,"schema":{"type":"integer"}}],"summary":"Delete a signal alert","tags":["Signal alerts"],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Deleted"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such alert on this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"description":"Any subset of the create body. A body carrying only delivery settings\nvalidates nothing, so changing a cooldown cannot fail because the\ncatalog tightened since the alert was accepted.\n\nA body carrying **any** document key is merged onto the stored document\nand the whole result re-validated. `{\"timeframe\": \"w1\"}` on a golden\ncross has to be checked against that setup's own timeframe list, and\nvalidating the fragment alone would report four required keys missing\nthat are sitting in the database.\n\nChanging the market, setup, timeframe or params re-arms the alert from\nthe current bar. Editing an alert consumes no new tier slot, so there is\nno `402` here.\n\nRequires the `rules:write` scope.\n","parameters":[{"in":"path","name":"id","description":"Rule id","required":true,"schema":{"type":"integer"}}],"summary":"Update a signal alert","tags":["Signal alerts"],"responses":{"200":{"description":"The updated alert","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignalAlertEnvelope"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such alert on this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The alert is invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrors"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSignalAlertRequest"}}}}}},"/client/api/rules/validate":{"post":{"description":"Validates a rule document and returns either its canonical form plus the\nplain-English sentence it renders as, or **every** error in it. Stores\nnothing, counts against no limit, and is the intended first call.\n\nThe body may be the document itself or the document under a `rule` key\n— both are accepted. Requires the `rules:read` scope.\n","summary":"Check a rule without storing it","tags":["DSL"],"responses":{"200":{"description":"The rule is valid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateEnvelope"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The rule is invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrors"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateRequest"}}}}}},"/client/api/signal-alerts/{id}/fires":{"get":{"description":"Newest first. Each fire carries the market, the closed bar it fired on,\nthe price at that close, the indicator readings that made the condition\ntrue (`values`), a chart link, and the stamped `+1h` / `+24h` outcomes.\n\nAn outcome is `pending` until its horizon arrives and `unavailable` when\nthere was no confirmed close to measure against — never `0`, for the\nreason the watcher fires endpoint gives.\n\nRequires the `rules:read` scope.\n","parameters":[{"in":"path","name":"id","description":"Rule id","required":true,"schema":{"type":"integer"}},{"in":"query","name":"limit","description":"Most fires to return (default 50, max 200)","required":false,"schema":{"maximum":200,"type":"integer","minimum":1}}],"summary":"What this signal alert has reported","tags":["Fires"],"responses":{"200":{"description":"The fire history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignalAlertFireList"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such alert on this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/client/api/rules":{"get":{"description":"Newest first, each with its summary and track record. `rules:read`.","summary":"List your rules","tags":["Rules"],"responses":{"200":{"description":"Your rules","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RuleList"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"description":"Validates the document, stores it, and starts evaluating it on the next\npass. A new rule **does** report coins that already match — that is\nusually the question being asked — so pair a universe-wide rule with\n`once_per_asset` unless you want the current matches repeated.\n\nThe body may be the document itself or the document under a `rule` key\nalongside delivery settings — both are accepted.\n\n`422` carries the same structured error list as\n`/client/api/rules/validate`. `402` means the account's tier has no free\nslot of this rule class, and its body names the tier, the limit and what\nwould raise it; `/client/api/usage` reports the same thing on demand.\n\nRequires the `rules:write` scope.\n","parameters":[{"in":"header","name":"Idempotency-Key","description":"Stable create retry key, scoped to this owner and operation across REST/MCP. Same normalized body replays the original 201 snapshot, including after deletion; a changed body returns 409. Receipts persist for the account lifetime. Read the resource for current status. Omission creates a new rule each time.","required":false,"schema":{"type":"string","pattern":"^[!-~]+$","maxLength":128,"minLength":1}}],"summary":"Create a rule","tags":["Rules"],"responses":{"201":{"description":"The rule as stored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RuleEnvelope"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"No free slot in this tier","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntitlementError"}}}},"403":{"description":"The key lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation errors or invalid_idempotency_key; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRuleRequest"}}}}}},"/client/api/condition-alerts/{id}/versions":{"get":{"description":"Read immutable condition logic revisions. Required scopes: rules:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"path","name":"id","required":true,"schema":{"maximum":2147483647,"type":"integer","minimum":1}}],"summary":"Read immutable condition logic revisions. Required scopes: rules:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"versions":{"type":"array","items":{"type":"object"}},"rule_id":{"maximum":2147483647,"type":"integer","minimum":1}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"get_condition_alert_versions","x-required-scopes":["rules:read"]}},"/client/api/rules/{id}/resume":{"post":{"description":"Re-activates a paused rule, a system-gated one, or a spent one-shot, and\nclears the gate reason. If the condition that gated it still holds, the\nsystem gates it again on the next pass and records the reason afresh.\n`rules:write`.\n","parameters":[{"in":"path","name":"id","description":"Rule id","required":true,"schema":{"type":"integer"}}],"summary":"Resume a rule","tags":["Rules"],"responses":{"200":{"description":"The active rule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RuleEnvelope"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such rule on this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/client/api/vocabulary":{"get":{"description":"Everything needed to write a rule: the field table with types, units,\nbounds and the operators each field accepts; the grammar; the structural\nlimits; and the JSON Schema itself. Read this before writing a rule —\nthe vocabulary is closed, and a field that is not in it is rejected\nrather than ignored.\n\nRequires only a valid key; no scope.\n","summary":"The rule vocabulary and JSON Schema","tags":["DSL"],"responses":{"200":{"description":"The vocabulary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VocabularyEnvelope"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/client/api/ping":{"get":{"description":"Unauthenticated liveness probe.","summary":"Health check","tags":["Account"],"security":[],"responses":{"200":{"description":"Service is up","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/client/api/derivatives/snapshot":{"get":{"description":"Read a bounded public Bybit funding, open-interest, USD open-interest and perp/spot-basis snapshot for up to 20 explicitly named spot symbols. Stale fields are null with blockers. Required scopes: market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"query","name":"exchange","required":true,"schema":{"type":"string","enum":["bybit"]}},{"in":"query","name":"symbols","required":true,"schema":{"oneOf":[{"type":"string","description":"Comma-separated symbols for REST GET."},{"type":"array","items":{"type":"string"},"maxItems":20,"minItems":1,"uniqueItems":true}]}}],"summary":"Read a bounded public Bybit funding, open-interest, USD open-interest and perp/spot-basis snapshot for up to 20 explicitly named spot symbols. Stale fields are null with blockers. Required scopes: market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"exchange":{"type":"string"},"stale":{"type":"boolean"},"markets":{"type":"array","items":{"type":"object"}},"market_type":{"type":"string"},"as_of":{"type":["string","null"],"format":"date-time"},"blockers":{"type":"array","items":{"type":"object"}}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"get_derivatives_snapshot","x-required-scopes":["market:read"]}},"/client/api/signal-alerts/{id}/resume":{"post":{"description":"Re-activates a paused alert, one the availability gate suspended, or a\nspent one-shot, re-armed from the current bar and with the gate reason\ncleared. If the condition that gated it still holds — the market is\nstill short of history, say — it is gated again on the next pass and the\nreason is recorded afresh. `rules:write`.\n","parameters":[{"in":"path","name":"id","description":"Rule id","required":true,"schema":{"type":"integer"}}],"summary":"Resume a signal alert","tags":["Signal alerts"],"responses":{"200":{"description":"The active alert","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignalAlertEnvelope"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such alert on this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/client/api/signal-alerts/availability":{"get":{"description":"The runtime half of the contract. For one market, which setups can\nactually evaluate on which timeframes right now, and where they cannot,\na machine-readable `reason` with the numbers behind it and the sentence\na person would be shown.\n\nWithout `setup`, every setup on every timeframe it declares. With\n`setup`, that one setup's timeframes evaluated against the `params` you\nintend to use — which matters, because a 200-period moving average needs\nfour times the history a 50 does.\n\nAsk this before arming anything on a long timeframe. A weekly\nmoving-average cross needs 260 weekly closes, which is five years of\nhistory; without this endpoint the only way to learn that is to create\nthe alert and wait.\n\nMetered per key, because it is the one endpoint here that loads a\nmarket's candle history rather than reading a row. Over the limit is\n`429` with a `retry-after` header — a throttle, not an authorization\nfailure, and nothing about the request was wrong.\n\nRequires the `market:read` scope.\n","parameters":[{"in":"query","name":"exchange","description":"The venue","required":true,"schema":{"type":"string","enum":["coinbase","binanceus","bybit"]}},{"in":"query","name":"symbol","description":"A market listed on that venue, in its own spelling","required":true,"schema":{"type":"string"}},{"in":"query","name":"setup","description":"Ask about one setup rather than all of them","required":false,"schema":{"type":"string","enum":["ltf_hf_buy","ltf_hf_sell","rsi_oversold","rsi_recovery","rsi_overbought","golden_cross","death_cross","price_reclaims_ma","price_loses_ma","bollinger_lower","bollinger_upper","macd_bullish","macd_bearish","msb_bullish","msb_bearish"]}},{"in":"query","name":"params","description":"The params you intend to use, e.g. `params[period]=200`. Only meaningful with `setup`.","required":false,"style":"deepObject","schema":{"type":"object"},"explode":true}],"summary":"Whether a market can carry a setup today","tags":["Signal alerts"],"responses":{"200":{"description":"What this market can carry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvailabilityEnvelope"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The market could not be resolved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrors"}}}},"429":{"description":"Too many availability calls on this key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/client/api/condition-alerts/{id}/pause":{"post":{"description":"Pause closed-bar evaluation while preserving state and history. Required scopes: rules:write. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"path","name":"id","required":true,"schema":{"maximum":2147483647,"type":"integer","minimum":1}}],"summary":"Pause closed-bar evaluation while preserving state and history. Required scopes: rules:write. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"status":{"type":"string"},"state":{"type":"object"},"revision":{"type":"integer"},"summary":{"type":"string"},"rule":{"type":"object"},"channel_ids":{"type":["array","null"],"items":{"type":"integer"}},"evaluation":{"type":"object"},"cooldown_seconds":{"type":"integer"},"dsl_version":{"const":"condition.v1"},"one_shot":{"type":"boolean"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"pause_condition_alert","x-required-scopes":["rules:write"]}},"/client/api/condition-alerts/{id}/fires":{"get":{"description":"Read observed fires with exact price, closed-bar trace and correlated delivery state. Required scopes: rules:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"path","name":"id","required":true,"schema":{"maximum":2147483647,"type":"integer","minimum":1}},{"in":"query","name":"limit","required":false,"schema":{"maximum":100,"type":"integer","minimum":1}}],"summary":"Read observed fires with exact price, closed-bar trace and correlated delivery state. Required scopes: rules:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"fires":{"type":"array","items":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"trace":{"type":"object"},"values":{"type":"object"},"plan":{"type":["object","null"]},"revision":{"type":"integer"},"direction":{"type":"string"},"delivery":{"type":["object","null"]},"rule":{"type":"object"},"bucket_start":{"type":["string","null"],"format":"date-time"},"plan_error":{"type":["object","null"]},"plan_status":{"type":"string","enum":["resolved","absent","unresolved"]},"price":{"type":["string","null"],"description":"Exact decimal text; never a JSON float."},"rule_id":{"maximum":2147483647,"type":"integer","minimum":1}}}},"rule_id":{"maximum":2147483647,"type":"integer","minimum":1}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"get_condition_alert_fires","x-required-scopes":["rules:read"]}},"/client/api/signal-baskets/preflight":{"post":{"description":"Resolve and check a basket.v1 setup across fixed symbols or dynamic top_n volume markets. Reports the separate basket and active-member evaluation budgets before creation; saves nothing. Requires rules:read and market:read. Required scopes: rules:read, market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[],"summary":"Resolve and check a basket.v1 setup across fixed symbols or dynamic top_n volume markets. Reports the separate basket and active-member evaluation budgets before creation; saves nothing. Requires rules:read and market:read. Required scopes: rules:read, market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"runtime":{"type":"object"},"members":{"type":"array","items":{"type":"object"}},"saved":{"const":false},"errors":{"type":"array","items":{"type":"object"}},"valid":{"type":"boolean"},"ready":{"type":"boolean"},"summary":{"type":"string"},"document":{"type":"object"},"delivery":{"type":"object"},"rule":{"type":"object"},"checked_at":{"type":["string","null"],"format":"date-time"},"caveat":{"type":"string"},"blockers":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}},"quota":{"type":"object"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","dsl_version","setup","exchange","timeframe","universe"],"additionalProperties":false,"properties":{"channel_ids":{"type":"array","items":{"maximum":2147483647,"type":"integer","minimum":1}},"cooldown_seconds":{"maximum":2147483647,"type":"integer","minimum":0},"dsl_version":{"type":"string","enum":["basket.v1"]},"exchange":{"type":"string","enum":["coinbase","binanceus","bybit"]},"name":{"type":"string","maxLength":120,"minLength":1},"note":{"type":"string"},"one_shot":{"type":"boolean"},"params":{"type":"object"},"plan":{"type":"object","required":["side","entry","stop","targets"],"additionalProperties":false,"properties":{"entry":{"type":"object","additionalProperties":false,"properties":{"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"ref":{"type":"string"},"offset_abs":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"offset_pct":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["ref"]},{"not":{"required":["ref"]},"required":["value"]}]},"stop":{"type":"object","additionalProperties":false,"properties":{"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"ref":{"type":"string"},"offset_abs":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"offset_pct":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["ref"]},{"not":{"required":["ref"]},"required":["value"]}]},"labels":{"type":"object","additionalProperties":false,"properties":{"entry":{"type":"string","maxLength":24,"minLength":1},"stop":{"type":"string","maxLength":24,"minLength":1},"r":{"type":"string","maxLength":24,"minLength":1}}},"side":{"type":"string","enum":["long","short"]},"targets":{"type":"array","items":{"type":"object","required":["id"],"additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,15}$"},"label":{"type":"string","maxLength":24,"minLength":1},"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"r":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["r"]},{"not":{"required":["r"]},"required":["value"]}]},"maxItems":5,"minItems":1}}},"setup":{"type":"string","enum":["ltf_hf_buy","ltf_hf_sell","rsi_oversold","rsi_recovery","rsi_overbought","golden_cross","death_cross","price_reclaims_ma","price_loses_ma","bollinger_lower","bollinger_upper","macd_bullish","macd_bearish","msb_bullish","msb_bearish"]},"timeframe":{"type":"string","enum":["m15","h1","h4","h12","d1","w1"]},"universe":{"oneOf":[{"type":"object","required":["symbols"],"additionalProperties":false,"properties":{"symbols":{"type":"array","items":{"type":"string"},"maxItems":20,"minItems":1,"uniqueItems":true}}},{"type":"object","required":["top_n","sort"],"additionalProperties":false,"properties":{"exclude_bases":{"type":"array","items":{"type":"string"},"maxItems":50,"uniqueItems":true},"major_only":{"type":"boolean"},"min_volume_24h_usd":{"type":"string","description":"Optional exact decimal USD-equivalent 24h notional floor.","pattern":"^[0-9]+(?:\\.[0-9]+)?$"},"quote":{"type":"string","description":"Optional exact quote asset, for example USDT."},"sort":{"type":"string","enum":["volume_24h_usd"]},"top_n":{"maximum":20,"type":"integer","minimum":1}}}]}}}}}},"operationId":"preflight_signal_basket","x-required-scopes":["rules:read","market:read"]}},"/client/api/rules/{id}":{"get":{"description":"The rule with its most recent fires inline, under `fires`. The full\npaginated history is at `/client/api/rules/{id}/fires`.\n\n`rules:read`. A rule belonging to someone else is `404`, never `403`:\ntelling one account that id 41 exists but is not theirs is itself the\ndisclosure that makes enumeration worth attempting.\n","parameters":[{"in":"path","name":"id","description":"Rule id","required":true,"schema":{"type":"integer"}}],"summary":"Fetch one rule","tags":["Rules"],"responses":{"200":{"description":"The rule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RuleEnvelope"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such rule on this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"description":"Permanent, and it takes the rule's fire history with it. `rules:write`.","parameters":[{"in":"path","name":"id","description":"Rule id","required":true,"schema":{"type":"integer"}}],"summary":"Delete a rule","tags":["Rules"],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Deleted"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such rule on this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"description":"Any subset of the create body. A body carrying only settings validates\nnothing, so a rename cannot fail because the vocabulary tightened since\nthe rule was accepted; a body carrying a document re-validates it and\nstores the canonical form.\n\nChanging the rule moves its cursor to the current bar. It does **not**\nclear which coins it has already reported, because those rows are its\noutcome ledger, and a rule that could forget its own history could be\nmade to look better by editing it.\n\nRequires the `rules:write` scope.\n","parameters":[{"in":"path","name":"id","description":"Rule id","required":true,"schema":{"type":"integer"}}],"summary":"Update a rule","tags":["Rules"],"responses":{"200":{"description":"The updated rule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RuleEnvelope"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such rule on this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The rule is invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrors"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRuleRequest"}}}}}},"/client/api/condition-alerts/{id}/resume":{"post":{"description":"Recheck readiness and resume; unresolved blockers leave an explicit draft. Required scopes: rules:write, market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"path","name":"id","required":true,"schema":{"maximum":2147483647,"type":"integer","minimum":1}}],"summary":"Recheck readiness and resume; unresolved blockers leave an explicit draft. Required scopes: rules:write, market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"status":{"type":"string"},"state":{"type":"object"},"revision":{"type":"integer"},"summary":{"type":"string"},"rule":{"type":"object"},"channel_ids":{"type":["array","null"],"items":{"type":"integer"}},"evaluation":{"type":"object"},"cooldown_seconds":{"type":"integer"},"dsl_version":{"const":"condition.v1"},"one_shot":{"type":"boolean"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"resume_condition_alert","x-required-scopes":["rules:write","market:read"]}},"/client/api/derivatives/series":{"get":{"description":"Read up to 300 stored public Bybit derivatives observations aligned to a requested grain. Values are exact decimal strings; missing and stale inputs carry blockers and never become zero. Required scopes: market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"query","name":"before","required":false,"schema":{"oneOf":[{"type":"string","format":"date-time"},{"type":"integer","minimum":1}]}},{"in":"query","name":"exchange","required":true,"schema":{"type":"string","enum":["bybit"]}},{"in":"query","name":"limit","required":false,"schema":{"maximum":300,"type":"integer","minimum":1}},{"in":"query","name":"metric","required":true,"schema":{"type":"string","enum":["funding_rate","open_interest","open_interest_delta","open_interest_usd","basis"]}},{"in":"query","name":"symbol","required":true,"schema":{"type":"string"}},{"in":"query","name":"timeframe","required":true,"schema":{"type":"string","enum":["h1","m15","m5"]}}],"summary":"Read up to 300 stored public Bybit derivatives observations aligned to a requested grain. Values are exact decimal strings; missing and stale inputs carry blockers and never become zero. Required scopes: market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"count":{"type":"integer"},"status":{"type":"string"},"exchange":{"type":"string"},"stale":{"type":"boolean"},"points":{"type":"array","items":{"type":"object"}},"metric":{"type":"string"},"next_before":{"type":["string","null"],"format":"date-time"},"timeframe":{"type":"string"},"market_type":{"type":"string"},"as_of":{"type":["string","null"],"format":"date-time"},"blockers":{"type":"array","items":{"type":"object"}},"perp_symbol":{"type":"string"},"spot_symbol":{"type":"string"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"get_derivatives_series","x-required-scopes":["market:read"]}},"/client/api/assistant/context":{"get":{"description":"Read one bounded snapshot containing quota, safe delivery readiness, a selected venue's top markets, owned rules and baskets, active preparation blockers, and recent fires. It contains no channel destinations or key secrets. Required scopes: rules:read, market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"query","name":"exchange","required":false,"schema":{"type":"string","enum":["coinbase","binanceus","bybit"]}},{"in":"query","name":"fire_limit","required":false,"schema":{"maximum":50,"type":"integer","minimum":1}},{"in":"query","name":"market_limit","required":false,"schema":{"maximum":20,"type":"integer","minimum":1}}],"summary":"Read one bounded snapshot containing quota, safe delivery readiness, a selected venue's top markets, owned rules and baskets, active preparation blockers, and recent fires. It contains no channel destinations or key secrets. Required scopes: rules:read, market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"delivery":{"type":"object","required":["ready","blockers","channels","transports"],"properties":{"ready":{"type":"boolean"},"channels":{"type":"array","items":{"type":"object"}},"blockers":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"channel_id":{"type":"integer"}}}},"transports":{"type":"array","items":{"type":"object"}}}},"rules":{"type":"array","items":{"type":"object"}},"markets":{"type":"object"},"account":{"type":"object"},"derivatives":{"type":"object"},"halted_reason":{"type":["string","null"]},"baskets":{"type":"array","items":{"type":"object"}},"generated_at":{"type":["string","null"],"format":"date-time"},"preparations":{"type":"array","items":{"type":"object"}},"recent_fires":{"type":"array","items":{"type":"object"}}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"get_assistant_context","x-required-scopes":["rules:read","market:read"]}},"/client/api/condition-alerts/preflight":{"post":{"description":"Validate one condition.v1 document and report closed-bar data, delivery, quota and halt blockers without saving. It supports exact close_above/close_below, inclusive enter/leave zones and persisted sweep_reclaim sequences. Required scopes: rules:read, market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[],"summary":"Validate one condition.v1 document and report closed-bar data, delivery, quota and halt blockers without saving. It supports exact close_above/close_below, inclusive enter/leave zones and persisted sweep_reclaim sequences. Required scopes: rules:read, market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"runtime":{"type":"object"},"members":{"type":"array","items":{"type":"object"}},"saved":{"const":false},"errors":{"type":"array","items":{"type":"object"}},"valid":{"type":"boolean"},"ready":{"type":"boolean"},"summary":{"type":"string"},"document":{"type":"object"},"delivery":{"type":"object"},"rule":{"type":"object"},"checked_at":{"type":["string","null"],"format":"date-time"},"caveat":{"type":"string"},"blockers":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}},"quota":{"type":"object"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["rule"],"additionalProperties":false,"properties":{"channel_ids":{"type":"array","items":{"maximum":2147483647,"type":"integer","minimum":1}},"cooldown_seconds":{"maximum":2147483647,"type":"integer","minimum":0},"one_shot":{"type":"boolean"},"rule":{"type":"object","required":["dsl_version","name","exchange","symbol","timeframe"],"additionalProperties":false,"properties":{"name":{"type":"string","maxLength":120,"minLength":1},"exchange":{"type":"string","enum":["coinbase","binanceus","bybit"]},"when":{"type":"object"},"params":{"type":"object"},"symbol":{"type":"string","maxLength":80,"minLength":1},"plan":{"type":"object","required":["side","entry","stop","targets"],"additionalProperties":false,"properties":{"entry":{"type":"object","additionalProperties":false,"properties":{"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"ref":{"type":"string"},"offset_abs":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"offset_pct":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["ref"]},{"not":{"required":["ref"]},"required":["value"]}]},"stop":{"type":"object","additionalProperties":false,"properties":{"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"ref":{"type":"string"},"offset_abs":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"offset_pct":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["ref"]},{"not":{"required":["ref"]},"required":["value"]}]},"labels":{"type":"object","additionalProperties":false,"properties":{"entry":{"type":"string","maxLength":24,"minLength":1},"stop":{"type":"string","maxLength":24,"minLength":1},"r":{"type":"string","maxLength":24,"minLength":1}}},"side":{"type":"string","enum":["long","short"]},"targets":{"type":"array","items":{"type":"object","required":["id"],"additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,15}$"},"label":{"type":"string","maxLength":24,"minLength":1},"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"r":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["r"]},{"not":{"required":["r"]},"required":["value"]}]},"maxItems":5,"minItems":1}}},"direction":{"type":"string","enum":["rise","fall","neutral"]},"sequence":{"type":"object"},"indicators":{"type":"object"},"dsl_version":{"type":"string","enum":["condition.v1"]},"timeframe":{"type":"string","enum":["m15","h1","h4","h12","d1","w1"]},"note":{"type":"string","maxLength":280},"rearm":{"type":"object"}},"oneOf":[{"required":["when"]},{"required":["sequence"]}]}}},"examples":{"enter_zone":{"value":{"rule":{"direction":"rise","dsl_version":"condition.v1","exchange":"bybit","indicators":{},"name":"BTC enters support zone","symbol":"BTCUSDT","timeframe":"m15","when":{"enter_zone":{"high":{"decimal":"76500"},"low":{"decimal":"76000"},"value":"price"}}}},"summary":"Fire when a confirmed close enters an inclusive price zone"},"leave_zone":{"value":{"rule":{"direction":"fall","dsl_version":"condition.v1","exchange":"bybit","indicators":{},"name":"BTC leaves support zone","symbol":"BTCUSDT","timeframe":"m15","when":{"leave_zone":{"high":{"decimal":"76500"},"low":{"decimal":"76000"},"value":"price"}}}},"summary":"Fire when a confirmed close leaves an inclusive price zone"}}}}},"operationId":"preflight_condition_alert","x-required-scopes":["rules:read","market:read"]}},"/client/api/ohlcv/batch":{"post":{"description":"Read up to ten spot markets in one bounded call. source=market returns exchange chart bars; source=engine returns the stored successor-confirmed rollups used by signal evaluation. Each symbol has its own success, invalid or unavailable result. Required scopes: market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[],"summary":"Read up to ten spot markets in one bounded call. source=market returns exchange chart bars; source=engine returns the stored successor-confirmed rollups used by signal evaluation. Each symbol has its own success, invalid or unavailable result. Required scopes: market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"exchange":{"type":"string"},"source":{"type":"string"},"results":{"type":"array","items":{"type":"object"}}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["exchange","symbols","timeframe"],"additionalProperties":false,"properties":{"before":{"oneOf":[{"type":"string","format":"date-time"},{"type":"integer","minimum":1}]},"exchange":{"type":"string","enum":["coinbase","binanceus","bybit"]},"limit":{"maximum":300,"type":"integer","minimum":1},"source":{"type":"string","enum":["market","engine"]},"symbols":{"type":"array","items":{"type":"string"},"maxItems":10,"minItems":1,"uniqueItems":true},"timeframe":{"type":"string","enum":["m1","m5","m15","m30","h1","h2","h6","d1"]}}}}}},"operationId":"get_ohlcv_batch","x-required-scopes":["market:read"]}},"/client/api/preflight":{"post":{"description":"Check a watcher.v1 or signal.v1 rule plus delivery settings without saving. Returns valid and ready separately, canonical rule, quota, data, delivery and halt blockers. Readiness is a snapshot, not a reservation. Requires rules:read and market:read. Required scopes: rules:read, market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[],"summary":"Check a watcher.v1 or signal.v1 rule plus delivery settings without saving. Returns valid and ready separately, canonical rule, quota, data, delivery and halt blockers. Readiness is a snapshot, not a reservation. Requires rules:read and market:read. Required scopes: rules:read, market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"runtime":{"type":"object"},"members":{"type":"array","items":{"type":"object"}},"saved":{"const":false},"errors":{"type":"array","items":{"type":"object"}},"valid":{"type":"boolean"},"ready":{"type":"boolean"},"summary":{"type":"string"},"document":{"type":"object"},"delivery":{"type":"object"},"rule":{"type":"object"},"checked_at":{"type":["string","null"],"format":"date-time"},"caveat":{"type":"string"},"blockers":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}},"quota":{"type":"object"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["rule"],"additionalProperties":false,"properties":{"channel_ids":{"type":"array","items":{"maximum":2147483647,"type":"integer","minimum":1}},"cooldown_seconds":{"maximum":2147483647,"type":"integer","minimum":0},"once_per_asset":{"type":"boolean"},"one_shot":{"type":"boolean"},"rule":{"type":"object","description":"A complete watcher.v1 or signal.v1 document."}}}}}},"operationId":"preflight_rule","x-required-scopes":["rules:read","market:read"]}},"/client/api/signal-alerts/{id}/pause":{"post":{"description":"Stops evaluation and keeps everything else. A paused alert still\noccupies a tier slot — it is one call from running again. `rules:write`.\n","parameters":[{"in":"path","name":"id","description":"Rule id","required":true,"schema":{"type":"integer"}}],"summary":"Pause a signal alert","tags":["Signal alerts"],"responses":{"200":{"description":"The paused alert","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignalAlertEnvelope"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such alert on this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/client/api/price-alerts/{id}/fires":{"get":{"description":"Read bounded fire history with exact observed prices and correlated delivery state. Required scopes: rules:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"path","name":"id","required":true,"schema":{"maximum":2147483647,"type":"integer","minimum":1}},{"in":"query","name":"limit","required":false,"schema":{"maximum":100,"type":"integer","minimum":1}}],"summary":"Read bounded fire history with exact observed prices and correlated delivery state. Required scopes: rules:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"fires":{"type":"array","items":{"type":"object"}},"rule_id":{"maximum":2147483647,"type":"integer","minimum":1}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"get_price_alert_fires","x-required-scopes":["rules:read"]}},"/client/api/signal-alerts/validate":{"post":{"description":"Validates a signal-alert document and returns either its canonical form\nplus the plain-English sentence it renders as, or **every** error in it.\nStores nothing, counts against no limit, and is the intended first call.\n\nThe canonical form is worth diffing against what you sent: it carries\nthe venue's own spelling of the symbol and the setup's defaults filled\nin, so it says exactly what we understood.\n\nThe body may be the document itself or the document under a `rule` key\n— both are accepted. Requires the `rules:read` scope.\n","summary":"Check a signal alert without storing it","tags":["Signal alerts"],"responses":{"200":{"description":"The alert is valid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignalAlertValidateEnvelope"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The alert is invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrors"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignalAlertValidateRequest"}}}}}},"/client/api/levels":{"get":{"description":"Calculate exact prior-range, confirmed swing and rolling VWAP levels from the engine's successor-confirmed closed bars. The response pins the calculation version, UTC session, lookback inclusion policy and missing-input blockers. Required scopes: market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"query","name":"exchange","required":true,"schema":{"type":"string","enum":["coinbase","binanceus","bybit"]}},{"in":"query","name":"lookback","required":false,"schema":{"maximum":300,"type":"integer","minimum":1}},{"in":"query","name":"swing_strength","required":false,"schema":{"maximum":10,"type":"integer","minimum":1}},{"in":"query","name":"symbol","required":true,"schema":{"type":"string"}},{"in":"query","name":"timeframe","required":true,"schema":{"type":"string","enum":["m15","h1","h4","h12","d1","w1"]}}],"summary":"Calculate exact prior-range, confirmed swing and rolling VWAP levels from the engine's successor-confirmed closed bars. The response pins the calculation version, UTC session, lookback inclusion policy and missing-input blockers. Required scopes: market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"session":{"type":"object"},"status":{"type":"string","enum":["available","unavailable"]},"exchange":{"type":"string"},"symbol":{"type":"string"},"levels":{"type":"object"},"inputs":{"type":"object"},"timeframe":{"type":"string"},"as_of":{"type":["string","null"],"format":"date-time"},"blockers":{"type":"array","items":{"type":"string"}},"calculation_id":{"const":"levels.v1"},"calculation_version":{"const":1}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"get_market_levels","x-required-scopes":["market:read"]}},"/client/api/signal-baskets/{id}/resume":{"post":{"description":"Resume a basket, retry membership readiness and preserve per-market one-shot/hysteresis state. Required scopes: rules:write. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"path","name":"id","required":true,"schema":{"maximum":2147483647,"type":"integer","minimum":1}}],"summary":"Resume a basket, retry membership readiness and preserve per-market one-shot/hysteresis state. Required scopes: rules:write. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"name":{"type":"string"},"status":{"type":"string","enum":["active","paused"]},"members":{"type":"array","items":{"type":"object","description":"Signal alert representation with basket_id and basket_member_active; use id with the signal-alert fire endpoint."}},"revision":{"type":"integer"},"document":{"type":"object"},"member_symbols":{"type":"array","items":{"type":"string"}},"quota_unit":{"type":"string"},"readiness":{"type":"object"},"refreshed_at":{"type":["string","null"],"format":"date-time"},"selection":{"type":"object"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"resume_signal_basket","x-required-scopes":["rules:write"]}},"/client/api/ohlcv":{"get":{"description":"Read up to 300 recent spot OHLCV bars from the exchange/chart cache, with decimal strings, closed/forming flags, gaps and freshness. Read intervals do not imply signal evaluation support. Upstream failures are unknown, never zero. Required scopes: market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"query","name":"before","required":false,"schema":{"oneOf":[{"type":"string","format":"date-time"},{"type":"integer","minimum":1}]}},{"in":"query","name":"exchange","required":true,"schema":{"type":"string"}},{"in":"query","name":"limit","required":false,"schema":{"maximum":300,"type":"integer","minimum":1}},{"in":"query","name":"symbol","required":true,"schema":{"type":"string"}},{"in":"query","name":"timeframe","required":true,"schema":{"type":"string","enum":["m1","m5","m15","m30","h1","h2","h6","d1"]}}],"summary":"Read up to 300 recent spot OHLCV bars from the exchange/chart cache, with decimal strings, closed/forming flags, gaps and freshness. Read intervals do not imply signal evaluation support. Upstream failures are unknown, never zero. Required scopes: market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"count":{"type":"integer"},"status":{"type":"string","enum":["available","stale","unavailable"]},"exchange":{"type":"string"},"symbol":{"type":"string"},"source":{"type":"string"},"stale":{"type":"boolean"},"candles":{"type":"array","items":{"type":"object","properties":{"close":{"type":["string","null"],"description":"Exact decimal text; never a JSON float."},"closed":{"type":"boolean"},"high":{"type":["string","null"],"description":"Exact decimal text; never a JSON float."},"low":{"type":["string","null"],"description":"Exact decimal text; never a JSON float."},"open":{"type":["string","null"],"description":"Exact decimal text; never a JSON float."},"bucket_start":{"type":["string","null"],"format":"date-time"},"engine_confirmed":{"type":"boolean"},"volume":{"type":["string","null"],"description":"Exact decimal text; never a JSON float."}}}},"cache_ttl_ms":{"type":"integer"},"missing_bars":{"type":"integer"},"next_before":{"type":["string","null"],"format":"date-time"},"read_at":{"type":["string","null"],"format":"date-time"},"timeframe":{"type":"string"},"as_of":{"type":["string","null"],"format":"date-time"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"get_ohlcv","x-required-scopes":["market:read"]}},"/client/api/markets/prepare":{"post":{"description":"Queue a bounded, deduplicated history preparation for one listed market, setup and signal timeframe. Poll the returned preparation until ready or blocked; provider failures remain explicit and retryable. Required scopes: rules:write, market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[],"summary":"Queue a bounded, deduplicated history preparation for one listed market, setup and signal timeframe. Poll the returned preparation until ready or blocked; provider failures remain explicit and retryable. Required scopes: rules:write, market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"status":{"type":"string","enum":["queued","running","ready","blocked","failed"]},"exchange":{"type":"string"},"progress":{"type":"object"},"started_at":{"type":["string","null"],"format":"date-time"},"coverage":{"type":"object"},"setup":{"type":"string"},"symbol":{"type":"string"},"confirmation":{"type":"string"},"completed_at":{"type":["string","null"],"format":"date-time"},"retryable":{"type":"boolean"},"blocker":{"type":["string","null"]},"timeframe":{"type":"string"},"attempts":{"type":"integer"},"requested_depth":{"type":"object"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["exchange","symbol","setup","timeframe"],"additionalProperties":false,"properties":{"exchange":{"type":"string","enum":["coinbase","binanceus","bybit"]},"setup":{"type":"string","enum":["ltf_hf_buy","ltf_hf_sell","rsi_oversold","rsi_recovery","rsi_overbought","golden_cross","death_cross","price_reclaims_ma","price_loses_ma","bollinger_lower","bollinger_upper","macd_bullish","macd_bearish","msb_bullish","msb_bearish"]},"symbol":{"type":"string"},"timeframe":{"type":"string","enum":["m15","h1","h4","h12","d1","w1"]}}}}}},"operationId":"prepare_market","x-required-scopes":["rules:write","market:read"]}},"/client/api/condition-alerts/{id}":{"get":{"description":"Read one owned advanced condition. Required scopes: rules:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"path","name":"id","required":true,"schema":{"maximum":2147483647,"type":"integer","minimum":1}}],"summary":"Read one owned advanced condition. Required scopes: rules:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"status":{"type":"string"},"state":{"type":"object"},"revision":{"type":"integer"},"summary":{"type":"string"},"rule":{"type":"object"},"channel_ids":{"type":["array","null"],"items":{"type":"integer"}},"evaluation":{"type":"object"},"cooldown_seconds":{"type":"integer"},"dsl_version":{"const":"condition.v1"},"one_shot":{"type":"boolean"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"get_condition_alert","x-required-scopes":["rules:read"]},"delete":{"description":"Delete one owned advanced condition and its version/fire history. Required scopes: rules:write. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"path","name":"id","required":true,"schema":{"maximum":2147483647,"type":"integer","minimum":1}}],"summary":"Delete one owned advanced condition and its version/fire history. Required scopes: rules:write. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"deleted":{"const":true}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"delete_condition_alert","x-required-scopes":["rules:write"]},"patch":{"description":"Replace one condition document and settings with an expected revision. Logic changes create a new immutable revision and reset sequence state. Required scopes: rules:write, market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"path","name":"id","required":true,"schema":{"maximum":2147483647,"type":"integer","minimum":1}}],"summary":"Replace one condition document and settings with an expected revision. Logic changes create a new immutable revision and reset sequence state. Required scopes: rules:write, market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"status":{"type":"string"},"state":{"type":"object"},"revision":{"type":"integer"},"summary":{"type":"string"},"rule":{"type":"object"},"channel_ids":{"type":["array","null"],"items":{"type":"integer"}},"evaluation":{"type":"object"},"cooldown_seconds":{"type":"integer"},"dsl_version":{"const":"condition.v1"},"one_shot":{"type":"boolean"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"update_condition_alert","x-required-scopes":["rules:write","market:read"]}},"/client/api/condition-alerts/replay":{"post":{"description":"Evaluate condition.v1 with the live closed-bar engine and return bounded historical example fires without arming or mixing them into observed statistics. Required scopes: rules:read, market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[],"summary":"Evaluate condition.v1 with the live closed-bar engine and return bounded historical example fires without arming or mixing them into observed statistics. Required scopes: rules:read, market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"count":{"type":"integer"},"source":{"type":"string"},"examples":{"type":"array","items":{"type":"object","properties":{"trace":{"type":"object"},"values":{"type":"object"},"plan":{"type":["object","null"]},"direction":{"type":"string"},"bucket_start":{"type":["string","null"],"format":"date-time"},"plan_error":{"type":["object","null"]},"plan_status":{"type":"string","enum":["resolved","absent","unresolved"]},"price":{"type":["string","null"],"description":"Exact decimal text; never a JSON float."}}}},"dsl_version":{"const":"condition.v1"},"observed_statistics_included":{"const":false}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["rule"],"additionalProperties":false,"properties":{"limit":{"maximum":500,"type":"integer","minimum":1},"rule":{"type":"object","required":["dsl_version","name","exchange","symbol","timeframe"],"additionalProperties":false,"properties":{"name":{"type":"string","maxLength":120,"minLength":1},"exchange":{"type":"string","enum":["coinbase","binanceus","bybit"]},"when":{"type":"object"},"params":{"type":"object"},"symbol":{"type":"string","maxLength":80,"minLength":1},"plan":{"type":"object","required":["side","entry","stop","targets"],"additionalProperties":false,"properties":{"entry":{"type":"object","additionalProperties":false,"properties":{"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"ref":{"type":"string"},"offset_abs":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"offset_pct":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["ref"]},{"not":{"required":["ref"]},"required":["value"]}]},"stop":{"type":"object","additionalProperties":false,"properties":{"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"ref":{"type":"string"},"offset_abs":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"offset_pct":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["ref"]},{"not":{"required":["ref"]},"required":["value"]}]},"labels":{"type":"object","additionalProperties":false,"properties":{"entry":{"type":"string","maxLength":24,"minLength":1},"stop":{"type":"string","maxLength":24,"minLength":1},"r":{"type":"string","maxLength":24,"minLength":1}}},"side":{"type":"string","enum":["long","short"]},"targets":{"type":"array","items":{"type":"object","required":["id"],"additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,15}$"},"label":{"type":"string","maxLength":24,"minLength":1},"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"r":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["r"]},{"not":{"required":["r"]},"required":["value"]}]},"maxItems":5,"minItems":1}}},"direction":{"type":"string","enum":["rise","fall","neutral"]},"sequence":{"type":"object"},"indicators":{"type":"object"},"dsl_version":{"type":"string","enum":["condition.v1"]},"timeframe":{"type":"string","enum":["m15","h1","h4","h12","d1","w1"]},"note":{"type":"string","maxLength":280},"rearm":{"type":"object"}},"oneOf":[{"required":["when"]},{"required":["sequence"]}]}}}}}},"operationId":"replay_condition_alert","x-required-scopes":["rules:read","market:read"]}},"/client/api/signal-alerts":{"get":{"description":"Newest first, each with its generated summary and track record. `rules:read`.","summary":"List your signal alerts","tags":["Signal alerts"],"responses":{"200":{"description":"Your signal alerts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignalAlertList"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"description":"Validates the document, stores it, and starts evaluating it at the close\nof each bar on its timeframe.\n\nTwo refusals are not validation failures and come back as themselves.\n`402` means the account's tier has no free signal-alert slot, and its\nbody names the tier, the limit and what would raise it. A setup the\nmarket cannot currently carry — not enough history, not enough\nliquidity — is refused on the `setup` field with the availability\ngate's own sentence; `/client/api/signal-alerts/availability` answers\nthat before you ask.\n\nThe body may be the document itself or the document under a `rule` key\nalongside delivery settings. There is no `name` to set: the label in\nevery response is generated from the rule, so it cannot disagree with\nwhat the rule watches. `note` is your own free text.\n\nRequires the `rules:write` scope.\n","parameters":[{"in":"header","name":"Idempotency-Key","description":"Stable create retry key, scoped to this owner and operation across REST/MCP. Same normalized body replays the original 201 snapshot, including after deletion; a changed body returns 409. Receipts persist for the account lifetime. Read the resource for current status. Omission creates a new rule each time.","required":false,"schema":{"type":"string","pattern":"^[!-~]+$","maxLength":128,"minLength":1}}],"summary":"Create a signal alert","tags":["Signal alerts"],"responses":{"201":{"description":"The alert as stored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignalAlertEnvelope"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"No free slot in this tier","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntitlementError"}}}},"403":{"description":"The key lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation errors or invalid_idempotency_key; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSignalAlertRequest"}}}}}},"/client/api/rules/{id}/fires":{"get":{"description":"Newest first. Each fire carries the coin, the bar it fired on, the price\nand liquidity at that bar, every operand the rule could have read\n(`facts`), a chart link, and the stamped `+1h` / `+24h` outcomes.\n\nAn outcome is `pending` until its horizon arrives and `unavailable` when\nthere was no confirmed close to measure against — never `0`. A coin that\nstopped trading is the case that matters most, and scoring it flat would\nflatter exactly the rules that deserve it least.\n\nRequires the `rules:read` scope.\n","parameters":[{"in":"path","name":"id","description":"Rule id","required":true,"schema":{"type":"integer"}},{"in":"query","name":"limit","description":"Most fires to return (default 50, max 200)","required":false,"schema":{"maximum":200,"type":"integer","minimum":1}}],"summary":"What this rule has reported","tags":["Fires"],"responses":{"200":{"description":"The fire history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FireList"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such rule on this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/client/api/signal-baskets/{id}/pause":{"post":{"description":"Pause a basket and its active members; retain membership, quota and history. Required scopes: rules:write. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"path","name":"id","required":true,"schema":{"maximum":2147483647,"type":"integer","minimum":1}}],"summary":"Pause a basket and its active members; retain membership, quota and history. Required scopes: rules:write. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"name":{"type":"string"},"status":{"type":"string","enum":["active","paused"]},"members":{"type":"array","items":{"type":"object","description":"Signal alert representation with basket_id and basket_member_active; use id with the signal-alert fire endpoint."}},"revision":{"type":"integer"},"document":{"type":"object"},"member_symbols":{"type":"array","items":{"type":"string"}},"quota_unit":{"type":"string"},"readiness":{"type":"object"},"refreshed_at":{"type":["string","null"],"format":"date-time"},"selection":{"type":"object"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"pause_signal_basket","x-required-scopes":["rules:write"]}},"/client/api/price-alerts/{id}/pause":{"post":{"description":"Pause evaluation of one owned price alert. Required scopes: rules:write. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"path","name":"id","required":true,"schema":{"maximum":2147483647,"type":"integer","minimum":1}}],"summary":"Pause evaluation of one owned price alert. Required scopes: rules:write. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"status":{"type":"string"},"revision":{"type":"integer"},"summary":{"type":"string"},"rule":{"type":"object"},"channel_ids":{"type":"array","items":{"type":"integer"}},"evaluation":{"type":"object"},"cooldown_seconds":{"type":"integer"},"dsl_version":{"const":"price.v1"},"one_shot":{"type":"boolean"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"pause_price_alert","x-required-scopes":["rules:write"]}},"/client/api/price-alerts/{id}":{"get":{"description":"Read one owned price alert. Required scopes: rules:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"path","name":"id","required":true,"schema":{"maximum":2147483647,"type":"integer","minimum":1}}],"summary":"Read one owned price alert. Required scopes: rules:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"status":{"type":"string"},"revision":{"type":"integer"},"summary":{"type":"string"},"rule":{"type":"object"},"channel_ids":{"type":"array","items":{"type":"integer"}},"evaluation":{"type":"object"},"cooldown_seconds":{"type":"integer"},"dsl_version":{"const":"price.v1"},"one_shot":{"type":"boolean"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"get_price_alert","x-required-scopes":["rules:read"]},"delete":{"description":"Delete one owned price alert and its fire history. Required scopes: rules:write. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"path","name":"id","required":true,"schema":{"maximum":2147483647,"type":"integer","minimum":1}}],"summary":"Delete one owned price alert and its fire history. Required scopes: rules:write. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"deleted":{"const":true}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"delete_price_alert","x-required-scopes":["rules:write"]},"patch":{"description":"Patch one owned price alert. expected_revision is required so concurrent logic or routing edits cannot overwrite each other. Required scopes: rules:write. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"path","name":"id","required":true,"schema":{"maximum":2147483647,"type":"integer","minimum":1}}],"summary":"Patch one owned price alert. expected_revision is required so concurrent logic or routing edits cannot overwrite each other. Required scopes: rules:write. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"maximum":2147483647,"type":"integer","minimum":1},"status":{"type":"string"},"revision":{"type":"integer"},"summary":{"type":"string"},"rule":{"type":"object"},"channel_ids":{"type":"array","items":{"type":"integer"}},"evaluation":{"type":"object"},"cooldown_seconds":{"type":"integer"},"dsl_version":{"const":"price.v1"},"one_shot":{"type":"boolean"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"update_price_alert","x-required-scopes":["rules:write"]}},"/client/api/onchain/assets/{id}":{"get":{"description":"Read one on-chain asset, its canonical pool, freshness and the exact current/previous watcher inputs plus successor-confirmed hourly candles. Missing fields remain null and are listed as unknown. Required scopes: market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","parameters":[{"in":"path","name":"id","required":true,"schema":{"maximum":2147483647,"type":"integer","minimum":1}},{"in":"query","name":"limit","required":false,"schema":{"maximum":100,"type":"integer","minimum":1}}],"summary":"Read one on-chain asset, its canonical pool, freshness and the exact current/previous watcher inputs plus successor-confirmed hourly candles. Missing fields remain null and are listed as unknown. Required scopes: market:read. Read the returned status and reasons before reporting success; saved rules, available data and successful delivery are separate facts.","tags":["Assistant"],"responses":{"200":{"description":"Result under data; preflight returns valid and ready independently","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"count":{"type":"integer"},"decimals":{"type":["integer","null"]},"id":{"maximum":2147483647,"type":"integer","minimum":1},"name":{"type":["string","null"]},"status":{"type":"string"},"symbol":{"type":["string","null"]},"confirmation":{"type":"string"},"chain":{"type":"string"},"tracked":{"type":"boolean"},"candles":{"type":"array","items":{"type":"object"}},"canonical_pool":{"type":["object","null"]},"contract_address":{"type":"string"},"freshness":{"type":"object"},"gate":{"type":"object"},"watcher_inputs":{"type":"object"}}}}}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Owned basket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A stale expected_revision or an idempotency key reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request or basket preflight blockers; nothing saved","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Shared market-read budget exhausted; Retry-After: 60","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Upstream market data unavailable; not an empty successful read","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"get_onchain_asset","x-required-scopes":["market:read"]}},"/client/api/rules/{id}/pause":{"post":{"description":"Stops evaluation and keeps everything else. A paused rule still occupies\na tier slot — it is one call from running again. `rules:write`.\n","parameters":[{"in":"path","name":"id","description":"Rule id","required":true,"schema":{"type":"integer"}}],"summary":"Pause a rule","tags":["Rules"],"responses":{"200":{"description":"The paused rule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RuleEnvelope"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such rule on this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/client/api/usage":{"get":{"description":"What the account holds, what that entitles it to, and how much of it is\nin use. `unknown_balance` true means the wallet could not be read — that\nis not the same as holding nothing, and the limits shown are the\nfail-closed floor rather than a measurement.\n\nThe counts cover all three rule classes because the entitlement does;\n`rule_classes` says which of them this API can actually create and\nwhere, so a remaining budget is never read as a promise of an endpoint\nthat does not exist.\n\nRequires the `rules:read` scope.\n","summary":"Tier, limits and this key's usage","tags":["Account"],"responses":{"200":{"description":"The account snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageEnvelope"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/client/api/signal-alerts/schema":{"get":{"description":"Everything needed to write a signal alert: every setup with the side it\nwatches, the timeframes it is defined on, the params it takes, the\nhistory it warms up on, and a plain-English explainer of what the\nstructure actually means. Plus the venues, the timeframes, a skeleton to\ncopy, and the one length limit.\n\nRead this before writing an alert. The setup list is closed, so a\nstructure that is not here has no representation — and the explainers\nare the point of publishing it: the ids alone are enough to write a\nvalid alert, not the right one.\n\nWhat this deliberately does **not** answer is whether a given setup can\nrun on a given market today. That is a runtime fact about one market and\nit is at `/client/api/signal-alerts/availability`; a flag here would be\nstale the moment it was serialised.\n\nRequires the `market:read` scope — it describes what we speak and\ndiscloses nothing about any account.\n","summary":"The setup catalog and the closed lists a signal alert draws from","tags":["Signal alerts"],"responses":{"200":{"description":"The setup catalog","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupCatalogEnvelope"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"tags":[{"name":"DSL","description":"The rule vocabulary and the validator"},{"name":"Rules","description":"Create, read, pause, resume and delete rules"},{"name":"Signal alerts","description":"Curated technical setups on one exchange-listed market"},{"name":"Fires","description":"What a rule has reported, and how it turned out"},{"name":"Account","description":"Tier, limits and this key's usage"},{"name":"MCP","description":"The same operations over Model Context Protocol"}],"openapi":"3.1.0","security":[{"bearerAuth":[]}],"servers":[{"description":"Production","url":"https://app.dutchmantrading.com"}],"x-dsl-vocabulary":{"combinators":["all","any","not"],"document":{"dsl_version":"watcher.v1","name":"short label, required","note":"optional free text","universe":{"chain":"solana"},"when":{"all":[{"above":{"left":"liquidity_usd","right":100000}}]}},"dsl_version":"watcher.v1","fields":[{"available":true,"description":"Which chain the coin trades on. Give one chain as a string or several as an array. Naming a chain is the single largest reduction in a rule's evaluation cost; omitting it scans every chain.","history_hours":0,"max":null,"min":null,"name":"chain","operators":["is","one_of"],"scope":"universe","type":"enum","unavailable_reason":null,"unit":null,"units":[],"values":["base","robinhood","solana"]},{"available":true,"description":"True while the coin appears on a data aggregator's trending list. This is a statement about that aggregator's output, computed by methods it does not publish, not an independent measurement of the market.","history_hours":0,"max":null,"min":null,"name":"trending","operators":["is"],"scope":"universe","type":"boolean","unavailable_reason":null,"unit":null,"units":[],"values":[true,false]},{"available":true,"description":"True once the coin has cleared the mechanical liquidity, age and staleness gate. A coin we have not checked yet reads as false, never as true.","history_hours":0,"max":null,"min":null,"name":"gate_passed","operators":["is"],"scope":"universe","type":"boolean","unavailable_reason":null,"unit":null,"units":[],"values":[true,false]},{"available":true,"description":"US-dollar reserve held in the coin's canonical pool. Has no previous-bar value, so it takes no cross operator; pair \"above\" with once_per_asset to fire the first time a coin reaches a level.","history_hours":0,"max":1000000000000,"min":0,"name":"liquidity_usd","operators":["above","below","between"],"scope":"condition","type":"number","unavailable_reason":null,"unit":"usd","units":["b","k","m","usd"],"values":null},{"available":true,"description":"Hours since the pool was created, falling back to when we first saw the coin. Accepts a unit object such as {\"value\": 5, \"unit\": \"days\"}. Age only increases, so cross_above fires once when a pool comes of age and cross_below can never be true.","history_hours":0,"max":87600,"min":0,"name":"pool_age_hours","operators":["above","below","between","cross_above"],"scope":"condition","type":"number","unavailable_reason":null,"unit":"hours","units":["days","hours","minutes","weeks"],"values":null},{"available":true,"description":"US-dollar volume traded through the canonical pool over the trailing 24 hours, as reported by the pool. No previous-bar value, so no cross operator.","history_hours":0,"max":1000000000000,"min":0,"name":"volume_24h_usd","operators":["above","below","between"],"scope":"condition","type":"number","unavailable_reason":null,"unit":"usd","units":["b","k","m","usd"],"values":null},{"available":true,"description":"Latest US-dollar price from the canonical pool, falling back to the last confirmed hourly close. No previous-bar value, so no cross operator; use a price_change field to talk about movement.","history_hours":0,"max":1000000000,"min":0,"name":"price_usd","operators":["above","below","between"],"scope":"condition","type":"number","unavailable_reason":null,"unit":"usd","units":["b","k","m","usd"],"values":null},{"available":true,"description":"Percentage change in close price over the last hour. Negative for a fall; cannot go below -100.","history_hours":1,"max":10000000,"min":-100,"name":"price_change_1h_pct","operators":["above","below","between","cross_above","cross_below"],"scope":"condition","type":"number","unavailable_reason":null,"unit":"percent","units":["percent"],"values":null},{"available":true,"description":"Percentage change in close price over the last six hours. Negative for a fall; cannot go below -100.","history_hours":6,"max":10000000,"min":-100,"name":"price_change_6h_pct","operators":["above","below","between","cross_above","cross_below"],"scope":"condition","type":"number","unavailable_reason":null,"unit":"percent","units":["percent"],"values":null},{"available":true,"description":"Percentage change in close price over the last 24 hours. Negative for a fall; cannot go below -100.","history_hours":24,"max":10000000,"min":-100,"name":"price_change_24h_pct","operators":["above","below","between","cross_above","cross_below"],"scope":"condition","type":"number","unavailable_reason":null,"unit":"percent","units":["percent"],"values":null},{"available":false,"description":"Raw count of posts mentioning the coin on X in the most recent complete hourly sample. A raised count means people are posting; coordinated posting is indistinguishable from organic posting at this resolution.","history_hours":1,"max":100000000,"min":0,"name":"attention_mentions","operators":["above","below","between","cross_above","cross_below"],"scope":"condition","type":"integer","unavailable_reason":"No X credential is configured on this deployment, so no attention samples are being collected and this field is nil for every coin. A rule using it is accepted and stored, and holds on every pass until the source is connected — at which point it starts firing with no change to this contract and no new dsl_version.","unit":"count","units":["count"],"values":null},{"available":false,"description":"Standard deviations the latest mention count sits above the coin's own 24-hour baseline, so a quiet ticker and a loud one are measured on the same scale. Needs a baseline: a coin sampled for the first time has no z-score.","history_hours":24,"max":1000,"min":-1000,"name":"attention_z","operators":["above","below","between","cross_above","cross_below"],"scope":"condition","type":"number","unavailable_reason":"No X credential is configured on this deployment, so no attention samples are being collected and this field is nil for every coin. A rule using it is accepted and stored, and holds on every pass until the source is connected — at which point it starts firing with no change to this contract and no new dsl_version.","unit":"sigma","units":["sigma"],"values":null},{"available":false,"description":"Latest mention count divided by the coin's own 24-hour baseline mean, so 3 means three times its usual chatter. Needs the same baseline as attention_z.","history_hours":24,"max":100000,"min":0,"name":"attention_ratio","operators":["above","below","between","cross_above","cross_below"],"scope":"condition","type":"number","unavailable_reason":"No X credential is configured on this deployment, so no attention samples are being collected and this field is nil for every coin. A rule using it is accepted and stored, and holds on every pass until the source is connected — at which point it starts firing with no change to this contract and no new dsl_version.","unit":"ratio","units":["ratio","x"],"values":null}],"limits":{"max_conditions":32,"max_depth":6,"max_name_length":80,"max_nodes_per_group":16,"max_note_length":500},"operators":{"above":"left is strictly greater than right","below":"left is strictly less than right","between":"value is within [low, high], both bounds inclusive","cross_above":"left was at or below right on the previous bar and is above it now","cross_below":"left was at or above right on the previous bar and is below it now"},"unavailable_fields":{"attention_mentions":"No X credential is configured on this deployment, so no attention samples are being collected and this field is nil for every coin. A rule using it is accepted and stored, and holds on every pass until the source is connected — at which point it starts firing with no change to this contract and no new dsl_version.","attention_ratio":"No X credential is configured on this deployment, so no attention samples are being collected and this field is nil for every coin. A rule using it is accepted and stored, and holds on every pass until the source is connected — at which point it starts firing with no change to this contract and no new dsl_version.","attention_z":"No X credential is configured on this deployment, so no attention samples are being collected and this field is nil for every coin. A rule using it is accepted and stored, and holds on every pass until the source is connected — at which point it starts firing with no change to this contract and no new dsl_version."}},"x-scope-by-operation":{"GET /client/api/rules/{id}":"rules:read","POST /client/api/signal-alerts/{id}/resume":"rules:write","POST /client/api/rules":"rules:write","GET /client/api/usage":"rules:read","GET /client/api/ohlcv":"market:read","GET /client/api/signal-alerts/availability":"market:read","POST /client/api/rules/{id}/pause":"rules:write","POST /client/api/mcp":null,"POST /client/api/rules/validate":"rules:read","POST /client/api/signal-alerts/validate":"rules:read","POST /client/api/condition-alerts/replay":"rules:read","POST /client/api/condition-alerts/{id}/pause":"rules:write","GET /client/api/derivatives/snapshot":"market:read","DELETE /client/api/condition-alerts/{id}":"rules:write","GET /client/api/signal-baskets/{id}":"rules:read","GET /client/api/vocabulary":null,"POST /client/api/signal-alerts":"rules:write","DELETE /client/api/rules/{id}":"rules:write","GET /client/api/condition-alerts/{id}/versions":"rules:read","POST /client/api/preflight":"rules:read","GET /client/api/onchain/assets/{id}":"market:read","GET /client/api/price-alerts/{id}":"rules:read","POST /client/api/markets/prepare":"rules:write","GET /client/api/rules/{id}/fires":"rules:read","GET /client/api/markets":"market:read","POST /client/api/condition-alerts/{id}/resume":"rules:write","GET /client/api/capabilities":"rules:read","DELETE /client/api/signal-baskets/{id}":"rules:write","GET /client/api/derivatives/series":"market:read","GET /client/api/signal-alerts/{id}":"rules:read","GET /client/api/signal-alerts":"rules:read","GET /client/api/levels":"market:read","PATCH /client/api/signal-alerts/{id}":"rules:write","POST /client/api/ohlcv/batch":"market:read","PATCH /client/api/rules/{id}":"rules:write","PATCH /client/api/condition-alerts/{id}":"rules:write","GET /client/api/market-preparations/{id}":"market:read","DELETE /client/api/price-alerts/{id}":"rules:write","DELETE /client/api/signal-alerts/{id}":"rules:write","POST /client/api/signal-baskets/{id}/pause":"rules:write","GET /client/api/price-alerts":"rules:read","POST /client/api/price-alerts":"rules:write","POST /client/api/signal-baskets/preflight":"rules:read","POST /client/api/signal-alerts/{id}/pause":"rules:write","POST /client/api/price-alerts/{id}/resume":"rules:write","PATCH /client/api/price-alerts/{id}":"rules:write","GET /client/api/rules":"rules:read","GET /client/api/condition-alerts/{id}":"rules:read","POST /client/api/condition-alerts/preflight":"rules:read","POST /client/api/condition-alerts":"rules:write","POST /client/api/signal-baskets/{id}/resume":"rules:write","GET /client/api/signal-alerts/schema":"market:read","GET /client/api/condition-alerts/{id}/fires":"rules:read","GET /client/api/condition-alerts":"rules:read","GET /client/api/ping":null,"POST /client/api/rules/{id}/resume":"rules:write","POST /client/api/price-alerts/{id}/pause":"rules:write","GET /client/api/price-alerts/{id}/fires":"rules:read","POST /client/api/signal-baskets":"rules:write","GET /client/api/signal-alerts/{id}/fires":"rules:read","PATCH /client/api/signal-baskets/{id}":"rules:write","GET /client/api/signal-baskets":"rules:read","GET /client/api/assistant/context":"rules:read"},"x-scopes":{"market:read":"Read asset, pool, liquidity and candle data","rules:read":"Read your rules, their fires, and their stamped track records","rules:write":"Create, update, pause and delete your rules"},"x-signal-vocabulary":{"document":{"dsl_version":"signal.v1","exchange":"coinbase","note":"optional free text","params":{"period":50},"setup":"price_reclaims_ma","symbol":"SOL-USD","timeframe":"d1"},"dsl_version":"signal.v1","exchanges":[{"id":"coinbase","label":"Coinbase"},{"id":"binanceus","label":"Binance.US"},{"id":"bybit","label":"Bybit"}],"keys":{"exchange":"Required. One of the venues below.","note":"Optional free text, carried into the alert that fires. Not part of the condition.","params":"Optional. The chosen setup's declared params. A setup that declares none accepts only an empty object.","plan":"Optional user-authored entry, stop and target geometry. References resolve from the fire's exact decimal measurements; this records levels and never places orders.","setup":"Required. One of the setup ids below.","symbol":"Required. A market listed on that venue, spelled the way that venue spells it — the same pair is \"SOL-USD\" on one venue and \"SOLUSDT\" on another, so a symbol is only meaningful next to its exchange. Matching ignores case. The one open value in this document: ask for the venue's market list rather than guessing.","timeframe":"Required. One of the timeframes below, and one the chosen setup offers: each setup's own list is the narrower constraint."},"limits":{"max_note_length":280,"max_plan_targets":5},"plan":{"type":"object","required":["side","entry","stop","targets"],"additionalProperties":false,"properties":{"entry":{"type":"object","additionalProperties":false,"properties":{"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"ref":{"type":"string"},"offset_abs":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"offset_pct":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["ref"]},{"not":{"required":["ref"]},"required":["value"]}]},"stop":{"type":"object","additionalProperties":false,"properties":{"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"ref":{"type":"string"},"offset_abs":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"offset_pct":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["ref"]},{"not":{"required":["ref"]},"required":["value"]}]},"labels":{"type":"object","additionalProperties":false,"properties":{"entry":{"type":"string","maxLength":24,"minLength":1},"stop":{"type":"string","maxLength":24,"minLength":1},"r":{"type":"string","maxLength":24,"minLength":1}}},"side":{"type":"string","enum":["long","short"]},"targets":{"type":"array","items":{"type":"object","required":["id"],"additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,15}$"},"label":{"type":"string","maxLength":24,"minLength":1},"value":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"},"r":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$"}},"oneOf":[{"not":{"required":["value"]},"required":["r"]},{"not":{"required":["r"]},"required":["value"]}]},"maxItems":5,"minItems":1}}},"setups":[{"id":"ltf_hf_buy","label":"LTF breakout with volume (buy watch)","learn":"Version 1 fires when a confirmed, closed 15-minute candle closes strictly above the highest high of the preceding 20 consecutive candles, and its base-asset volume is at least 1.5 times their average volume. The current candle is excluded from both baselines; missing bars or unavailable volume block evaluation. After firing, it re-arms only when a later close returns inside or onto that side of the rolling 20-bar range. Cooldown and one-shot settings still apply. This is a documented range-break approximation, not a reproduction of a TradingView HF indicator, an intrabar high-frequency strategy, or a recommendation to trade.","params":[],"plan_refs":["price","range_high","range_low"],"side":"buy_watch","side_label":"Buy watch","timeframes":["m15"],"warmup":[{"bars":20,"params":{}}]},{"id":"ltf_hf_sell","label":"LTF breakdown with volume (sell watch)","learn":"Version 1 fires when a confirmed, closed 15-minute candle closes strictly below the lowest low of the preceding 20 consecutive candles, and its base-asset volume is at least 1.5 times their average volume. The current candle is excluded from both baselines; missing bars or unavailable volume block evaluation. After firing, it re-arms only when a later close returns inside or onto that side of the rolling 20-bar range. Cooldown and one-shot settings still apply. This is a documented range-break approximation, not a reproduction of a TradingView HF indicator, an intrabar high-frequency strategy, or a recommendation to trade.","params":[],"plan_refs":["price","range_high","range_low"],"side":"sell_watch","side_label":"Sell watch","timeframes":["m15"],"warmup":[{"bars":20,"params":{}}]},{"id":"rsi_oversold","label":"RSI crosses into oversold","learn":"RSI (Relative Strength Index) runs 0–100 and measures how one-sided recent moves have been. Below 30 is traditionally called \"oversold\" — selling has dominated. Traders watch it as a place where a bounce *may* form, but a market can stay oversold for a long time in a strong downtrend.","params":[],"plan_refs":["price"],"side":"buy_watch","side_label":"Buy watch","timeframes":["m15","h1","h4","h12","d1","w1"],"warmup":[{"bars":50,"params":{}}]},{"id":"rsi_recovery","label":"RSI recovers out of oversold","learn":"This fires when RSI climbs back *above* 30 after being oversold — the momentum downturn easing rather than the dip itself. Many traders consider the turn back up a cleaner reference point than the moment price first became oversold.","params":[],"plan_refs":["price"],"side":"buy_watch","side_label":"Buy watch","timeframes":["m15","h1","h4","h12","d1","w1"],"warmup":[{"bars":50,"params":{}}]},{"id":"rsi_overbought","label":"RSI crosses into overbought","learn":"Above 70, RSI is traditionally \"overbought\" — buying has dominated recently. It's watched as a spot where upward momentum *may* be stretched, but like oversold it can persist through a strong uptrend, so it is a caution flag, not a top.","params":[],"plan_refs":["price"],"side":"sell_watch","side_label":"Sell watch","timeframes":["m15","h1","h4","h12","d1","w1"],"warmup":[{"bars":50,"params":{}}]},{"id":"golden_cross","label":"Golden cross (50 over 200)","learn":"A \"golden cross\" is the 50-period moving average crossing above the 200-period one — a slow, trend-following signal that the medium-term average has overtaken the long-term average. It is defined on daily and weekly closes; on intraday candles the same math is dominated by noise and isn't what traders mean by the term.","params":[],"plan_refs":["price"],"side":"buy_watch","side_label":"Buy watch","timeframes":["d1","w1"],"warmup":[{"bars":260,"params":{}}]},{"id":"death_cross","label":"Death cross (50 under 200)","learn":"The mirror of the golden cross: the 50-period average crossing *below* the 200-period one, read as the trend turning down over a medium horizon. Also a daily/weekly signal — it lags by design, describing a shift that has already begun.","params":[],"plan_refs":["price"],"side":"sell_watch","side_label":"Sell watch","timeframes":["d1","w1"],"warmup":[{"bars":260,"params":{}}]},{"id":"price_reclaims_ma","label":"Price reclaims a moving average","learn":"Fires when price closes back above its moving average after being below it. The moving average is a common reference for the prevailing trend, so reclaiming it is watched as short-term strength. Choose the 50 for a medium reference or the 200 for the long-term one.","params":[{"default":50,"key":"period","label":"Moving average","options":[50,200],"unit":"EMA"}],"plan_refs":["price"],"side":"buy_watch","side_label":"Buy watch","timeframes":["h4","h12","d1","w1"],"warmup":[{"bars":80,"params":{"period":50}},{"bars":230,"params":{"period":200}}]},{"id":"price_loses_ma","label":"Price loses a moving average","learn":"Fires when price closes below its moving average after being above it — the mirror of reclaiming it, watched as short-term weakness relative to the trend reference. The 50 tracks a medium horizon, the 200 the long-term one.","params":[{"default":50,"key":"period","label":"Moving average","options":[50,200],"unit":"EMA"}],"plan_refs":["price"],"side":"sell_watch","side_label":"Sell watch","timeframes":["h4","h12","d1","w1"],"warmup":[{"bars":80,"params":{"period":50}},{"bars":230,"params":{"period":200}}]},{"id":"bollinger_lower","label":"Price pierces the lower Bollinger band","learn":"Bollinger Bands sit two standard deviations either side of a 20-period average, so they widen and narrow with volatility. A close below the lower band means price is unusually far below its recent average — a stretch that sometimes mean-reverts, though in a strong down-move price can \"walk the band\" lower.","params":[],"plan_refs":["price"],"side":"buy_watch","side_label":"Buy watch","timeframes":["h1","h4","h12","d1"],"warmup":[{"bars":40,"params":{}}]},{"id":"bollinger_upper","label":"Price pierces the upper Bollinger band","learn":"A close above the upper Bollinger band means price is unusually far above its recent 20-period average — an extension that can mean-revert, but which also occurs during strong breakouts, so it reads as \"stretched,\" not \"reversing.\"","params":[],"plan_refs":["price"],"side":"sell_watch","side_label":"Sell watch","timeframes":["h1","h4","h12","d1"],"warmup":[{"bars":40,"params":{}}]},{"id":"macd_bullish","label":"MACD bullish signal cross","learn":"MACD tracks the gap between a fast and a slow moving average, and a \"signal line\" smooths that gap. The MACD line crossing above the signal line is a classic momentum-turning-up marker. It whipsaws on short timeframes, so it's offered on 4h and above.","params":[],"plan_refs":["price"],"side":"buy_watch","side_label":"Buy watch","timeframes":["h4","h12","d1","w1"],"warmup":[{"bars":80,"params":{}}]},{"id":"macd_bearish","label":"MACD bearish signal cross","learn":"The MACD line crossing *below* its signal line — the mirror of the bullish cross, read as momentum turning down. Also offered on 4h and above, where the signal is less prone to whipsaw.","params":[],"plan_refs":["price"],"side":"sell_watch","side_label":"Sell watch","timeframes":["h4","h12","d1","w1"],"warmup":[{"bars":80,"params":{}}]},{"id":"msb_bullish","label":"Bullish structure break (new higher high)","learn":"Markets that are falling make a series of lower highs. When price finally closes above the most recent one, that sequence is broken — traders call it a bullish market-structure break (MSB, or BOS). It is the moment a downtrend stops making lower highs, which is why it sits under Buy watch: it is the condition someone looking for a long waits for.\n\nThe level itself is a \"swing high\" — a bar standing above the two bars on each side of it. Needing bars on BOTH sides is what makes it a pivot rather than just a recent high, and it is also why it can only be confirmed two bars after it printed. This alert fires on a break of a confirmed level, never a guessed one.\n\nIt marks the end of the old structure, not the start of a reliable new one. Plenty of structure breaks fail inside an ongoing downtrend, and a condition being met is information, not advice.","params":[],"plan_refs":["price"],"side":"buy_watch","side_label":"Buy watch","timeframes":["m15","h1","h4","h12","d1","w1"],"warmup":[{"bars":60,"params":{}}]},{"id":"msb_bearish","label":"Bearish structure break (new lower low)","learn":"Markets that are rising make a series of higher lows. When price closes below the most recent one, that sequence is broken — the mirror of the bullish case, and the moment an uptrend stops making higher lows. It sits under Sell watch because it is the condition someone looking to exit a long, or to short, watches for.\n\nThe level is a \"swing low\": a bar sitting below the two bars on each side of it. Because it needs bars on both sides to be a pivot, it is confirmed two bars after it printed, and this fires only on a break of a confirmed level.\n\nAs with the bullish case, it marks the end of the previous structure rather than the start of a dependable new one. A condition being met is information, not advice.","params":[],"plan_refs":["price"],"side":"sell_watch","side_label":"Sell watch","timeframes":["m15","h1","h4","h12","d1","w1"],"warmup":[{"bars":60,"params":{}}]}],"timeframes":[{"id":"m15","label":"15 minutes"},{"id":"h1","label":"1 hour"},{"id":"h4","label":"4 hours"},{"id":"h12","label":"12 hours"},{"id":"d1","label":"1 day"},{"id":"w1","label":"1 week"}],"warmup_unit":"closed bars on the alert's own timeframe. A setup will not evaluate until the market has that many; on a weekly timeframe that is years of history."},"x-validation-error-codes":{"signal.v1":["empty","invalid_type","invalid_value","missing_key","not_an_object","out_of_range","too_long","too_many_keys","unknown_key","unknown_market","unsupported_timeframe","unknown_plan_ref","invalid_plan_target","invalid_plan_offset","plan_too_many_targets","wrong_dsl_version"],"watcher.v1":["ambiguous_node","empty","invalid_range","invalid_type","invalid_unit","invalid_value","missing_key","not_an_object","out_of_range","too_deep","too_expensive","too_long","too_many_conditions","too_many_keys","too_many_nodes","unknown_field","unknown_key","unknown_operator","unsupported_operator","wrong_dsl_version","wrong_scope"]}}