# Live cross-ticker options flow (Server-Sent Events)

`GET https://api.skylit.ai/v1/flow/stream`

API: Flowseeker.

A long-lived `text/event-stream` carrying options trades as they
print, across every ticker unless you filter. This is the same feed
that drives the Skylit website, with the same filter semantics.

### Live only

The stream carries trades that arrive **after** you connect; it
replays no history. Load a backlog from `/v1/flow/{ticker}` first if
you need one, then attach here. `limit` is rejected with `400` rather
than silently ignored.

### Pricing

Costs differ from one-shot routes because they accrue over time:

- **1 credit on connect**, charged before the stream opens — an
  under-funded client gets a clean `402`, not a stream that dies
  immediately.
- **1 credit per minute open**, reported back as a `credits` event.
- **5 concurrent streams per account**; a sixth gets `429`.
- **1 hour maximum**, then a `reconnect` event and a clean close.

### Filter names

This endpoint uses the live-feed filter vocabulary, which differs
from the curated parameters on `/v1/flow/{ticker}`: use
`show_calls`/`show_puts` rather than `option_type`, and
`min_size`/`max_size` rather than `min_contracts`/`max_contracts`.

### Events

| Event | Payload | Meaning |
|---|---|---|
| `connected` | stream terms | First frame after the stream opens. |
| `trade` | trade object | A trade that passed your filters. Flags `sweep_trade`, `multi_leg` and `cross_trade` are always present. |
| `credits` | `{"remaining": N}` | Emitted each minute after billing. |
| `lagged` | `{"dropped": N}` | You read slower than the tape; trades were skipped. |
| `closed` | `{"reason": "..."}` | Terminal. `insufficient_credits`, `account_suspended`, `credit_check_failed`, or `feed_unavailable`. |
| `reconnect` | `{"reason": "max_duration"}` | Terminal after 1h; reconnect to continue. |

A `:` comment arrives every 30s as a proxy keepalive. Treat a stalled
stream as a reconnect signal.

### Example

```
curl -N -H "Authorization: Bearer $SKYLIT_API_KEY" \
  "https://flow-api.skylit.ai/v1/flow/stream?min_premium=100000&show_puts=false"
```

`-N` matters: without it curl buffers the response and the stream
appears to hang.

## Authentication

Send your Skylit API key as a bearer token: `Authorization: Bearer <key>`. No other header is accepted.

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `ticker` | query | string | no | Comma-separated tickers to include (e.g. `AAPL,NVDA`, max 50). Omit to stream every ticker. |
| `exclude_ticker` | query | string | no | Comma-separated tickers to exclude. |
| `min_premium` | query | number (double) | no | Minimum premium per trade (USD). Strongly recommended — an unfiltered stream carries the entire tape. |
| `max_premium` | query | number (double) | no | Maximum premium per trade (USD). |
| `min_size` | query | integer | no | Minimum contracts per trade. (min 0) |
| `max_size` | query | integer | no | Maximum contracts per trade. (min 0) |
| `show_calls` | query | boolean | no | Include calls. (default `true`) |
| `show_puts` | query | boolean | no | Include puts. (default `true`) |
| `show_below_bid` | query | boolean | no | Include prints below the bid. The five side toggles are independent buckets: `show_bid` covers exact-bid prints, `show_ask` exact-ask, and the aggressive variants are gated by their own toggles. (default `true`) |
| `show_bid` | query | boolean | no | Include prints at the bid. (default `true`) |
| `show_mid` | query | boolean | no | Include prints at the mid. (default `true`) |
| `show_ask` | query | boolean | no | Include prints at the ask. (default `true`) |
| `show_above_ask` | query | boolean | no | Include prints above the ask. (default `true`) |
| `min_dte` | query | integer | no | Minimum days to expiration. |
| `max_dte` | query | integer | no | Maximum days to expiration. |
| `only_0dte` | query | boolean | no | Restrict to contracts expiring today. (default `false`) |
| `min_oi` | query | integer | no | Minimum open interest on the contract. (min 0) |
| `max_oi` | query | integer | no | Maximum open interest on the contract. (min 0) |
| `min_vol_oi` | query | number (double) | no | Minimum volume/open-interest ratio. |
| `max_vol_oi` | query | number (double) | no | Maximum volume/open-interest ratio. |
| `min_iv` | query | number (double) | no | Minimum implied volatility (decimal, e.g. `0.42`). |
| `max_iv` | query | number (double) | no | Maximum implied volatility (decimal). |
| `only_sweeps` | query | boolean | no | Restrict to multi-exchange sweeps. (default `false`) |
| `only_crosses` | query | boolean | no | Restrict to pre-negotiated crosses. These carry no aggressor information, so `side` is not meaningful on them. (default `false`) |
| `only_multi_leg` | query | boolean | no | Restrict to legs of multi-leg strategies. (default `false`) |
| `exclude_multi_leg` | query | boolean | no | Exclude multi-leg legs, leaving outright trades. (default `false`) |
| `min_flow_score` | query | integer | no | Minimum directional Flow Score (-100 → +100). (min -100; max 100) |
| `max_flow_score` | query | integer | no | Maximum directional Flow Score. (min -100; max 100) |
| `abs_min_flow_score` | query | integer | no | Minimum absolute Flow Score — conviction in either direction. (min 0; max 100) |
| `min_percentile` | query | integer | no | Minimum premium percentile for the ticker. Trades with no computed percentile are excluded once this is set. (one of `0`, `50`, `75`, `90`, `95`, `99`) |
| `show_stocks` | query | boolean | no | Include single-stock underlyings. (default `true`) |
| `show_etf` | query | boolean | no | Include ETF underlyings. (default `true`) |
| `show_indices` | query | boolean | no | Include index underlyings. (default `true`) |

## Example request

```bash
curl -N "https://api.skylit.ai/v1/flow/stream" \
  -H "Authorization: Bearer $SKYLIT_API_KEY" \
  -H "Accept: text/event-stream"
```

## Responses

### 200

An open SSE stream. Frames are newline-delimited
`event:`/`data:` pairs as described above.

`text/event-stream`

### 400

An unsupported parameter was supplied — `limit` is not valid on
the stream.

### 401

Missing or invalid API key.

missingKey:

```json
{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Authentication required"
  }
}
```

### 402

The account's shared Skylit credit balance is lower than this route's cost. Top up to continue. Carries `X-Credits-Remaining: 0`.

Headers: `X-Credits-Remaining`.

outOfCredits:

```json
{
  "error": {
    "code": "insufficient_credits",
    "message": "Out of credits. Top up to continue making requests."
  }
}
```

### 403

Unknown, revoked or expired API key (the gateway's `forbidden`), the account's API access is suspended (`account_suspended`) or blocked (`account_blocked`). Not retryable.

badKey:

```json
{
  "error": {
    "code": "FORBIDDEN",
    "message": "Access to this API has been disallowed"
  }
}
```

accountSuspended:

```json
{
  "error": {
    "code": "account_suspended",
    "message": "API access has been suspended for this account. Contact support."
  }
}
```

### 404

Unknown ticker or contract (`SYMBOL_NOT_FOUND`), or no data for the requested window. Not charged.

unknownSymbol:

```json
{
  "error": {
    "code": "SYMBOL_NOT_FOUND",
    "message": "Unknown ticker 'ZZZZQ'."
  }
}
```

noData:

```json
{
  "error": {
    "code": "NOT_FOUND",
    "message": "No trades found for AAPL on 2026-05-27 with timeframe 1d"
  }
}
```

### 429

Either the account's request rate limit, or its cap of 5
concurrent streams (`stream_limit_reached`).

### 503

Underlying data source temporarily unavailable, the credit balance could not be verified (`credit_check_failed`), or the API is paused for maintenance (`api_paused`, with a `Retry-After` header and a `retry_after` field in seconds). Not charged; safe to retry.

ingestionLag:

```json
{
  "error": {
    "code": "UNAVAILABLE",
    "message": "Live feed is degraded; please retry in a few seconds."
  }
}
```

creditCheckFailed:

```json
{
  "error": {
    "code": "credit_check_failed",
    "message": "Could not verify credit balance. Please retry."
  }
}
```

### 504

The request did not complete within 25 seconds. Not charged; narrow the window or retry.

tooSlow:

```json
{
  "error": {
    "code": "GATEWAY_TIMEOUT",
    "message": "The request took too long and was not completed. It was not charged; narrow the request or retry."
  }
}
```
