Alerts & webhooks
Let the engine do the watching: create price-cross and percent-move alerts over the API, and receive an HTTP call to your own server the moment one fires, evaluated on every tick, 24/7.
/v1/alerts/v1/alerts/v1/alerts/{id}Polling for a condition is the most wasteful pattern in trading automation: thousands of requests to observe that nothing happened yet. Alerts invert it. You register the condition once; our alert engine (the same one behind the site's alerts) evaluates it against every live tick and, at the moment of truth, notifies every channel your account has configured plus, for API-created alerts, POSTs a JSON payload to your webhook. Your side spends zero requests while waiting.
Alert types
| Type | Condition | Directions | Extra fields |
|---|---|---|---|
price | Live price reaches a level | above / below | price: the level. Must be on the far side of the current price at creation (validated, else 422). |
pct | The current candle moves at least X percent | up / down / any | pct (0.1-500) and window (5m 15m 1h 4h 1d 1w): the candle timeframe measured open→now. Needs a plan that includes % move alerts (422 otherwise). |
Because a price alert's level must start on the far side of the market, "reach" and "cross" are the same event; an alert can never fire at the creation instant. One-shot alerts flip to triggered status after firing; repeat: true alerts stay active and re-arm with hysteresis (price must retreat ~0.1% past the level before it can fire again, so an oscillation exactly on the line will not spam you). Percent alerts fire at most once per candle bucket. Repeating alerts are plan-gated; active alerts count against your plan's price alert cap, a separate pool from the market and density alert caps.
Creating an alert
curl -X POST "https://osiristrader.com/api/v1/alerts" \
-H "Authorization: Bearer osk_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"symbol": "BTCUSDT",
"type": "price",
"direction": "below",
"price": 60000,
"note": "weekly support retest",
"webhook_url": "https://your.app/hooks/osiris?secret=d41d8cd98f"
}'{
"data": {
"id": 91, "symbol": "BTCUSDT", "type": "price", "direction": "below", "price": 60000,
"pct": null, "window": null, "repeat": false, "note": "weekly support retest",
"webhookUrl": "https://your.app/hooks/osiris?secret=d41d8cd98f",
"status": "active", "createdPrice": 63516.6, "lastTriggeredAt": null,
"triggerCount": 0, "createdAt": "2026-08-14T09:12:00+00:00"
}
}curl -X POST "https://osiristrader.com/api/v1/alerts" \
-H "Authorization: Bearer osk_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "symbol": "SOLUSDT", "type": "pct", "direction": "any",
"pct": 3, "window": "15m", "repeat": true,
"webhook_url": "https://your.app/hooks/osiris?secret=d41d8cd98f" }'Listing & deleting
# active (default), or ?status=triggered / ?status=all curl "https://osiristrader.com/api/v1/alerts?status=all" \ -H "Authorization: Bearer osk_YOUR_KEY" curl -X DELETE "https://osiristrader.com/api/v1/alerts/91" \ -H "Authorization: Bearer osk_YOUR_KEY"
The API and the site's alerts page manage the same records: alerts created here appear in Settings → Alerts and vice versa. (The webhook_url field is API-only; UI-created alerts simply have none.) This page covers price alerts only: market alerts (Fear & Greed, board numbers) and density alerts (order-book wall watches) are managed on the site, each with its own plan cap, and have no API endpoints yet.
Alerts are venue-bound
Every alert watches one exchange's price feed, fixed at creation. Pass exchange (binance, bybit, okx, bitget) in the create payload to arm the alert against that venue's market; omitted, it binds to the default venue where the pair is listed. The bound venue comes back as the exchange field on every alert row. The same pair on two venues is two different markets; set two alerts if you watch both. If the venue later delists the pair, the alert is removed and you are notified.
Webhook delivery
When an alert with a webhook_url fires, we POST once, from our servers, with a 10-second timeout. Non-2xx responses and timeouts are retried up to 3 attempts total (10 s, then 60 s after the first failure). Webhook delivery runs alongside your other notification channels, never instead of them.
POST /hooks/osiris?secret=d41d8cd98f HTTP/1.1
Content-Type: application/json
X-Osiris-Event: alert.triggered
{
"event": "alert.triggered",
"alert": {
"id": 91, "exchange": "binance", "symbol": "BTCUSDT", "type": "price", "direction": "below",
"price": 60000, "pct": null, "window": null, "repeat": false,
"note": "weekly support retest"
},
"trigger": { "price": 59987.2, "move": null, "time": 1783877000000 }
}| Field | Description |
|---|---|
alert | The alert as configured, with everything needed to route the event without a lookup. |
trigger.price | The price at the firing tick. |
trigger.move | For pct alerts, the signed percent move that fired it; null for price alerts. |
trigger.time | Firing timestamp, ms. |
Webhook endpoint requirements & best practices
- Public URL, http(s), max 500 chars. Targets must resolve to a public address; localhost and private ranges are rejected at creation with
422. For local development, use a tunnel (cloudflared, ngrok). - Authenticate deliveries with a secret in your URL. Include a random token as a query parameter or path segment and verify it on every request; anyone who knows your URL shape could POST fake events otherwise. Treat the full URL as a credential.
- Respond fast, process async. Return
200immediately and hand the payload to a queue. A handler that trades synchronously inside the webhook request risks eating into the 10-second timeout and triggering a retry mid-action. - Be idempotent. Retries mean at-least-once delivery. Deduplicate on
(alert.id, trigger.time); that pair is unique per firing. - Design for the miss. If all 3 attempts fail (your endpoint was down), that firing is not re-delivered. On recovery, reconcile with
GET /v1/alerts?status=all:lastTriggeredAtandtriggerCounttell you exactly what you missed.