> ## Documentation Index
> Fetch the complete documentation index at: https://docs.routeur.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Watch for unusual flow

> Poll for trading far outside a market's normal, and print each signal once.

Unusual-flow signals are scored every five minutes, so polling every few minutes catches each one soon after it appears. A signal that keeps firing is extended rather than repeated, so track `id` together with `last_detected_at`.

<CodeGroup>
  ```python Python theme={null}
  import os
  import time
  import requests

  API = "https://api.routeur.app"
  session = requests.Session()
  session.headers["X-API-Key"] = os.environ["ROUTEUR_API_KEY"]
  seen = {}

  while True:
      res = session.get(f"{API}/v1/flow", params={"hours": 1, "limit": 100}, timeout=20)
      res.raise_for_status()
      for signal in res.json()["data"]:
          if seen.get(signal["id"]) == signal["last_detected_at"]:
              continue
          seen[signal["id"]] = signal["last_detected_at"]
          market, metrics = signal["market"], signal["metrics"]
          print(f"[{signal['kind']}] score {signal['score']:.1f} · {market['title']} ({market['venue']})")
          if "notional_usd" in metrics:
              print(f"    ${metrics['notional_usd']:,.0f} traded in the window")
      time.sleep(300)
  ```

  ```typescript TypeScript theme={null}
  const API = 'https://api.routeur.app';
  const headers = { 'X-API-Key': process.env.ROUTEUR_API_KEY! };
  const seen = new Map<number, string>();

  type Signal = {
    id: number; kind: 'burst' | 'large_fill' | 'one_sided'; score: number; last_detected_at: string;
    market: { venue: string; id: string; title: string }; metrics: Record<string, number>;
  };

  async function poll() {
    const res = await fetch(`${API}/v1/flow?hours=1&limit=100`, { headers });
    if (!res.ok) throw new Error(`flow: ${res.status}`);
    const { data } = (await res.json()) as { data: Signal[] };
    for (const signal of data) {
      if (seen.get(signal.id) === signal.last_detected_at) continue;
      seen.set(signal.id, signal.last_detected_at);
      console.log(`[${signal.kind}] score ${signal.score.toFixed(1)} · ${signal.market.title} (${signal.market.venue})`);
      if (signal.metrics.notional_usd) console.log(`    $${Math.round(signal.metrics.notional_usd).toLocaleString()} traded in the window`);
    }
  }

  await poll();
  setInterval(poll, 5 * 60_000);
  ```
</CodeGroup>

## Narrowing it

| To                                         | Add                   |
| ------------------------------------------ | --------------------- |
| One venue                                  | `venue=kalshi`        |
| Only one-way pressure that moved the price | `kind=one_sided`      |
| A longer look back                         | `hours=24`, up to 168 |

<Tip>
  A burst on its own is often news arriving. Look at `GET /v1/markets/{venue}/{id}/trades` for the fills behind it and `GET /v1/insights/flows` for which way the money went.
</Tip>
