---
title: "Api V2 Signals Action Get"
method: GET
path: "/api/v2/signals/action"
tags: ["Trade Signals (v2)"]
---

# Api V2 Signals Action Get

`GET /api/v2/signals/action`

## Request

- Base URL: `https://api.zerogex.io` (the document declares no server; this is the origin it was published from)
- URL: `https://api.zerogex.io/api/v2/signals/action`
- Auth: HTTP bearer

Latest **Action Card** — single, decisive trade instruction.

The Playbook Engine fuses Market Posture (the MSI regime), advanced
+ basic signals, and live structural levels into one Card per cycle.
A Card is either a specific trade (`BUY_PUT_DEBIT`, `SELL_CALL_SPREAD`,
`BUY_IRON_CONDOR`, etc.), a position-management directive, or
`STAND_DOWN` when no pattern matches current structure.

`STAND_DOWN` is an **earned** outcome, not equivocation — it ships
with a `near_misses[]` list naming the closest patterns and the
specific trigger conditions they failed.

Outside the regular session (09:30 ET to the close) the answer is always
`STAND_DOWN` with rationale "Market closed", empty `near_misses`, and
`context.session = "closed"`: no pattern is evaluated on a pre-market or
after-hours print.

**Params:** `underlying` (default `SPY`).
Returns 404 when no signal_score row exists for the symbol yet.

**Returns:** see `docs/playbook_catalog.md` §2 for the full schema.
Trade Card example:
```json
{
  "underlying": "SPY",
  "timestamp": "2026-05-01T18:42:13Z",
  "action": "SELL_CALL_SPREAD",
  "pattern": "call_wall_fade",
  "tier": "0DTE",
  "direction": "bearish",
  "confidence": 0.68,
  "size_multiplier": 0.6,
  "max_hold_minutes": 90,
  "legs": [
    {"expiry": "2026-05-01", "strike": 678.0, "right": "C", "side": "SELL", "qty": 1},
    {"expiry": "2026-05-01", "strike": 683.0, "right": "C", "side": "BUY",  "qty": 1}
  ],
  "entry":  {"ref_price": 678.40, "trigger": "at_touch"},
  "target": {"ref_price": 675.00, "kind": "level", "level_name": "max_pain"},
  "stop":   {"ref_price": 680.03, "kind": "premium_pct", "level_name": "call_wall_break"},
  "rationale": "Price $678.40 pinned at call wall $678.00, net GEX $7.1B, confirmed by trap_detection → call credit spread at the wall.",
  "context": {"...regime, msi, levels, signals_aligned..."},
  "alternatives_considered": []
}
```

STAND_DOWN example:
```json
{
  "underlying": "SPY",
  "timestamp": "...",
  "action": "STAND_DOWN",
  "pattern": "stand_down",
  "tier": "n/a",
  "direction": "non_directional",
  "confidence": 0.0,
  "rationale": "No tradable structure. Closest patterns: call_wall_fade.",
  "near_misses": [
    {"pattern": "call_wall_fade",
     "missing": ["price 0.45% from call_wall (needs <= 0.20%)"]}
  ],
  "context": {"msi": 32.5, "regime": "chop_range"}
}
```

**Notes.** The Card is computed on demand from the latest persisted
signal state and persisted when it is a trade. A pattern issues one Card
per idea: while its last Card on the symbol is inside its hold window it
stays quiet. Each pattern must also clear the entry bar its graded record
on the symbol has earned (`track_record` in `context`); a pattern that
has been losing there needs far more confidence or is paused.

## Query parameters

- `underlying` string

## Response `200`

Successful Response

- EnvelopeAny
  - `data` unknown, required
  - `freshness` Freshness, required: The v2 freshness envelope. Present on every ``/api/v2/*`` response.
    - `evaluated_at` string, date-time, required: When the API evaluated this response (server wall clock, UTC). Endpoint-health signal: advances on every request even when the underlying data is unchanged.
    - `generated_at` string, date-time, required: When the served data was computed. Equals the snapshot stamp for cycle-backed endpoints, or evaluated_at for endpoints computed on demand for this request.
    - `source_timestamp` string, date-time, nullable: Timestamp of the upstream market observation the payload derives from. This is what freshness_status is measured against. Null when the endpoint has no upstream feed or returned no rows.
    - `latest_event_at` string, date-time, nullable: Newest event timestamp present in the payload (last bar, last trade, last scored row). Best-effort on very large responses, which are sampled rather than fully walked.
    - `age_seconds` number, nullable: evaluated_at - source_timestamp, in seconds. Null when source_timestamp is null.
    - `market_session_status` string, required: pre-market | regular | after-hours | closed (US/Eastern).
    - `expected_update_cadence` string, nullable: ISO-8601 duration for how often this endpoint's data is expected to change right now, e.g. PT60S. Null means no updates are expected (weekend, holiday, or a feed that only runs during the session).
    - `expected_update_cadence_seconds` number, nullable: expected_update_cadence as a number of seconds.
    - `cadence_profile` string, required: Identifier of the cadence class this endpoint belongs to, e.g. analytics_cycle. Stable across releases; the seconds behind it may be retuned.
    - `stale_after` string, date-time, nullable: Instant after which this payload should be treated as stale. Null whenever expected_update_cadence is null.
    - `freshness_status` 'fresh' | 'aging' | 'stale' | 'session_closed' | 'static' | 'unknown', required: The rolled-up freshness verdict for one response. ``fresh`` ``source_timestamp`` is within one expected update cadence. ``aging`` Past one cadence but not yet past ``stale_after`` — the grace band that absorbs normal cycle jitter. Not an error; a client that polls faster than the cadence sees this routinely. ``stale`` Past ``stale_after`` while updates *were* expected. This is the actionable state: the feed behind this endpoint is late. ``session_closed`` A feed-backed endpoint whose feed is not due to produce anything right now (weekend, holiday, or a feed that only runs during the session). The payload is the last good value — deliberately NOT reported as ``stale``, because an overnight consumer polling a closed market is not observing a fault and should not page on it. ``static`` The endpoint is not feed-backed at all: completed history, or a result computed from the caller's own inputs. Age here carries no health meaning and never becomes a fault. ``unknown`` No source timestamp could be resolved from the payload (e.g. a pure calculator, an admin endpoint, or an empty result set). A consumer should fall back to ``evaluated_at`` for endpoint health and make no claim about data age.

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/zerogex/apis/zerogex-api.md) · [All operations](https://skmtc.dev/zerogex/apis/zerogex-api/llms.txt) · [OpenAPI document](https://skmtc.dev/zerogex/apis/zerogex-api/revisions/753b26bf0592?raw)
