API
Alerts your bot can create
The same REST surface the web app uses, with an API key instead of a session. Create levels from your own strategy code and receive the crossings on a signed webhook.
Live Pro plan
Authentication
Create a key in Settings → API keys. It is shown once, so store it where your
code reads it from. Send it as a bearer token against https://levelping.com/api/v1:
curl https://levelping.com/api/v1/alerts \
-H "Authorization: Bearer lp_live_xxx"
A key carries the same permissions as the account that created it, and nothing more: it reads and writes your own markets, alerts and history. It cannot create or revoke keys — that only happens from your session, so a leaked key cannot outlive the moment you revoke it. Revoking takes effect on the next request.
Create an alert
POST /api/v1/alerts
{
"market": "hyperliquid:BTC",
"direction": "above",
"price": 72000,
"mode": "oneshot",
"note": "breakout entry"
}
market is the pair as you see it in the app, venue:symbol; you can also send the
opaque marketId that /markets returns. The level is snapped to the exchange tick
size, so the response tells you the exact price that was stored. mode accepts
oneshot or recurring; recurring alerts take an optional cooldownS
(300–604800) and hysteresisPct (0–20). Alerts always go to every channel you have
enabled at the moment they fire, so connecting Telegram later covers the levels you already set.
The response carries willFireImmediately when the price is already on the other side of the
level: the alert is valid, it will just ping as soon as the engine sees the next tick.
Endpoints
| Method | Path | Does |
|---|---|---|
| GET | /markets | Search available markets (?q=BTC&venue=binance) |
| GET | /venues | Exchanges and how many markets each has |
| GET | /candles | Candles for a market (?market=<id>&interval=1h) |
| GET | /alerts | List your alerts |
| POST | /alerts | Create an alert |
| PATCH | /alerts/:id | Move the level, switch direction or mode, pause or re-arm |
| DELETE | /alerts/:id | Delete an alert |
| POST | /alerts/bulk-delete | Delete several at once: {"ids": [...]}, up to 500 |
| GET | /channels | Your notification channels and their ids |
| GET | /events | History of triggers and deliveries |
| GET | /me | Your plan, usage and channels |
Errors
Every error is JSON with an error code you can branch on.
| Status | Code | Means |
|---|---|---|
| 401 | missing_api_key | No Authorization: Bearer lp_live_… header |
| 401 | invalid_api_key | The key does not exist or was revoked |
| 402 | plan_feature | Your plan does not include that (the API itself, recurring, webhooks) |
| 402 | plan_limit | You are at your plan's alert limit |
| 400 | invalid_body | Validation failed; details says which field |
| 400 | market_unavailable | That market does not exist or is not trading |
| 404 | not_found | Not yours, or already deleted |
| 429 | rate_limited | Over the per-key rate limit |
Limits
Two requests per second per key, measured over ten-second windows so a short burst is not punished; the
ratelimit-* response headers tell you where you stand. Five live keys per account. A paused
alert still uses one of your plan's slots.
Webhook payload
When a level is crossed we POST this to the endpoint you registered in Settings:
{
"type": "alert.triggered",
"alert": { "id": "...", "direction": "above", "price": 72000, "note": "breakout entry", "mode": "oneshot" },
"market": { "venue": "hyperliquid", "symbol": "BTC", "base": "BTC", "quote": "USD" },
"trigger": { "price": 72014.5, "at": "2026-08-18T09:41:12.004Z" }
}
Verifying the signature
Every request carries x-levelping-timestamp and x-levelping-signature. The signature is an HMAC-SHA256 of timestamp + "." + rawBody using your webhook secret.
const expected = crypto
.createHmac('sha256', secret)
.update(`${req.get('x-levelping-timestamp')}.${rawBody}`)
.digest('hex')
// compare with the value after "sha256=" using timingSafeEqual
Reject requests whose timestamp is more than a few minutes old, and always compare in constant time.
Failed deliveries are retried three times with backoff; an endpoint that keeps failing is disabled and you get an email about it.