# How to Build a CS2 Skin Price Alert Bot

> Poll `POST /v1/prices/latest` on a schedule, track `(market_hash_name, doppler_phase)` state, fire alerts on **threshold crossings** with hysteresis — or skip code and use [Live Deals](/apps/livedeals) + the [Chrome extension](/extension).

## Alert types that work

| Type | Rule | Example |
|---|---|---|
| **Absolute price** | `price <= X` on market M | YouPin Redline FT under ¥140 |
| **Cross-market spread** | `price_A / fx(A) - price_B / fx(B) > Y%` | Skinport 8% above YouPin after fees |
| **Percent move** | `change_24h <= -Z%` | Dump alert on CSFloat |
| **Phase-specific** | Same as above + `doppler_phase` filter | Ruby Karambit only |

## Architecture

```
┌─────────────┐     every N min      ┌──────────────────┐
│  Scheduler  │ ──────────────────► │ POST /v1/prices/  │
│  (cron)     │                     │ latest (≤100)     │
└─────────────┘                     └────────┬─────────┘
                                           │
                                           ▼
                                  ┌──────────────────┐
                                  │ State store      │
                                  │ prev price, phase│
                                  └────────┬─────────┘
                                           │
              crossing detected            ▼
                                  ┌──────────────────┐
                                  │ Discord / TG /   │
                                  │ webhook          │
                                  └──────────────────┘
```

Respect plan rate limits. Batch up to **100 items** per POST.

## Poll example

```bash
curl -s -X POST "https://api.cspriceapi.com/v1/prices/latest" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      "AK-47 | Redline (Field-Tested)",
      "M4A1-S | Printstream (Field-Tested)"
    ],
    "markets": "youpin,skinport,csfloat"
  }'
```

## Crossing logic (with hysteresis)

Avoid alert spam when price oscillates ±0.5%:

```python
def crossed_below(prev: float | None, curr: float, threshold: float, hysteresis: float = 0.005) -> bool:
    if prev is None:
        return curr <= threshold
    # Fire when crossing down through threshold; reset when clearly above
    if prev > threshold >= curr:
        return True
    if curr > threshold * (1 + hysteresis):
        return "reset"  # allow re-arm
    return False
```

Store `armed` per `(name, phase, market, rule_id)`.

## Discord webhook (minimal)

```python
import requests

def notify_discord(webhook_url: str, content: str) -> None:
    requests.post(webhook_url, json={"content": content}, timeout=10)

# Example message
msg = (
    "🔔 **AK-47 | Redline (FT)** YouPin ¥138.50 "
    "(crossed below ¥140)\n"
    "Skinport: €17.90 | CSFloat: $124\n"
    "<https://cspriceapi.com/apps/pricecomparison>"
)
notify_discord("https://discord.com/api/webhooks/...", msg)
```

## Rules that prevent false alerts

| Rule | Why |
|---|---|
| Match `doppler_phase` | Phase 4 dip ≠ Ruby dip |
| `count >= 5` | Ignore single-listing noise |
| Stale check | Skip if `updated_at` older than 15 min on fast markets |
| Fee-adjusted spread | Raw price gap ≠ profit |
| One alert per crossing | Hysteresis re-arm |

## Buy-order alerts (exit price)

Monitor YouPin bids for "someone wants to buy above X":

```bash
curl -s "https://api.cspriceapi.com/v1/prices/youpin/buyorder" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

Compare top bid movement vs your inventory [fair value](/resources/how-to-calculate-cs2-skin-fair-value).

## No-code alternatives

| Tool | Best for |
|---|---|
| [Live Deals](/apps/livedeals) | Pre-computed cross-market gaps, no cron |
| [Price Comparison](/apps/pricecomparison) | Saved market pairs + ROI filters |
| [Chrome extension Pro](/extension) | Price alerts while browsing listings |
| [Trending](/apps/trending) | 24h movers without custom rules |

## Production checklist

1. [Discord testkey](https://discord.gg/XT3rpfH4Tx) or [dashboard](/dashboard) API key
2. [Quickstart](/docs/quickstart) — verify auth
3. Log `updated_at` per row — freshness matters
4. Handle partial POST failures (per-item errors if returned)
5. Backtest thresholds on [history](/resources/how-to-get-historical-cs2-skin-prices) before live alerts

## Related

- [Arbitrage bot guide](/resources/how-to-build-cs2-skin-arbitrage-bot)
- [Compare marketplaces](/resources/compare-cs2-skin-prices-across-marketplaces)
- [CSFloat prices](/resources/how-to-get-csfloat-prices)
