Update a custom signal
https://api.tickerbot.io/ v2/ signals/ {signal}Update a custom signal you own — its expression, description, or name.
Body parameters
stringrequiredCustom signal slug (the signal name). A built-in name answers 404 — built-ins are read-only.
stringNew SQL expression. Re-validated and re-inlined against your other custom signals. Same strict grammar as create — no LIKE/ILIKE, CASE, :: casts, or functions beyond abs/coalesce/round/least/greatest. The response echoes your expression as stored, not its expansion (a pre-2026-09-07 column spelling is stored under its current name and reported in _meta.deprecated_columns).
stringNew description. Not derived from expr — change both if the prose describes a threshold you are moving.
stringNew slug — renames the signal and changes its API handle everywhere (same validation as create). Refused while other custom signals reference the current name. name is accepted as an alias (new_name wins when both are sent), but new_name is the unambiguous spelling since the URL already carries the current name.
Returns
as_ofstringServer time this response was assembled (ISO 8601).
signalobjectThe stored signal: `name`, `kind` (`custom`), `description`, `expr` (your predicate as stored), `created_at`, `updated_at`.
_metaobjectOnly when `expr` named a column under its pre-2026-09-07 spelling: `deprecated_columns` lists each one (`requested`, `use`, `note`). The stored `expr` carries the current name.
Status codes
200{ as_of, signal: {...} } — the updated signal. A request that changes nothing (empty body, or name equal to the current name) is also a 200 carrying the signal unchanged, and does not touch updated_at.400compile_failed on bad expression, bad_request on shape failure or an unknown body key (strict — unknown fields are rejected, not ignored). The accepted keys are description, expr, new_name, and name (the legacy alias of new_name).404not_found — no custom signal with that name on this account, OR the name is a built-in: digit-leading names like 52_week_high can only be built-ins (create forbids the shape), so they answer "built-ins are read-only" rather than a misleading validation error.409rename_blocked (other custom signals reference the current name — listed in references.signals), name_collision (new name is a built-in signal), or already_exists (you already have a signal with the new name).Notes
- Partial update: supply
expr,description,new_name, or any combination. Providingexprrecompiles against the live signal whitelist, the same validator as create. Built-in signals are read-only — only your own custom signals can be patched. - The name IS the signal's API handle. Renaming via
new_namechanges what you reference inqand the CRUD path itself, so old-name references in your code stop compiling. Rename is refused with 409rename_blockedwhile other custom signals of yours reference the current name (edit those first), and with 409name_collision/already_existsif the new name hits a built-in signal or a signal you already have. - Existing subscriptions do not change. The subscribe endpoints freeze a custom signal's SQL into the webhook at creation, so editing or renaming here updates ad-hoc reads and *new* subscriptions while already-created webhooks keep firing on the old definition. Re-subscribe to apply.