GUIDE — FOR DEVELOPERS

Price alerts, as JSON.

Every coinsentry alert can POST a signed JSON payload to any endpoint you own — a trading bot, a spreadsheet, a Discord relay, your home dashboard. This is the whole integration: the exact payload, signature verification in two languages, and the delivery semantics. Ten minutes, start to verified.

PUBLISHED 2026-07-31LAST UPDATED 2026-07-315 MIN READBY COINSENTRY
01THE PAYLOAD

What lands on your endpoint

One shape, always. Prices are strings — exact numerics as exchange APIs send them, so you never lose precision to a float. Timestamps are unix milliseconds. Test deliveries (event: "test") use the exact production shape — build your parser against the test event and production just works.

POST — APPLICATION/JSON
{
  "event": "price_alert",
  "alert": {
    "pairSymbol": "BTC-USDT",
    "exchange": "Binance",
    "currentPrice": "120014.37",
    "targetPrice": "120000.00",
    "alertType": "crossing-up",
    "triggeredAt": 1753948800412
  },
  "timestamp": 1753948800498
}
FIELD REFERENCE
TYPEMEANING
event"price_alert" | "test"Test fires from the dashboard's Send test button — identical shape.
alert.pairSymbolstringThe pair that crossed, e.g. "BTC-USDT".
alert.exchangestringThe exchange whose feed triggered — alerts are pinned to one exchange's real prices.
alert.currentPricestringPrice at trigger time. String on purpose — parse with a decimal type if precision matters.
alert.targetPricestringThe level you set.
alert.alertTypestringDirection of the cross, e.g. "crossing-up".
alert.triggeredAtnumberUnix ms — when the price crossed.
timestampnumberUnix ms — when this delivery was sent. Differs from triggeredAt on retries.
02SECURITY

Verify it's really us

Set a secret in Dashboard → Channels → Webhook and every delivery carries an X-Coinsentry-Signature header: the hex-encoded HMAC-SHA256 of the request body, keyed with your secret. The body is serialized once, signed, and shipped as-is — so the signature always matches the exact bytes you receive.

The one classic mistake: verifying against re-serialized JSON. Key order or whitespace differences break the digest. Always verify against the raw request bytes, before any JSON parsing.

NODE — VERIFY
import crypto from "node:crypto";

// rawBody must be the exact bytes received — not re-serialized JSON.
// (Express: use express.raw() or the verify hook on express.json().)
function isFromCoinsentry(rawBody, signatureHeader, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");
  return (
    signatureHeader.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signatureHeader))
  );
}
PYTHON — VERIFY
import hashlib
import hmac

# raw_body must be the exact request bytes — not re-serialized JSON.
def is_from_coinsentry(raw_body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)
03SEMANTICS

Delivery rules to build against

  • Method & headers are yours. POST, PUT or PATCH, plus any custom headers — an auth token for your own gateway, a routing hint, whatever your stack needs.
  • 10-second timeout. Respond 2xx fast; queue slow work. A timeout counts as a failed delivery.
  • Failed deliveries retry automatically. Which means at-least-once delivery: the same alert can arrive twice. Deduplicate on alert.triggeredAt + alert.pairSymbol if double-handling would hurt.
  • Redirects are not followed. Point the URL at the final endpoint.
04TEST DRIVE

Verified in three steps

  1. 01
    Point it somewhere

    Grab a throwaway URL from webhook.site, paste it in Dashboard → Channels → Webhook, add a secret.

  2. 02
    Send the test event

    Hit Send test. The test payload is the production shape — inspect the body and the X-Coinsentry-Signature header live.

  3. 03
    Verify and ship

    Drop in the verification snippet, swap the URL for your real endpoint, route any alert to the webhook channel.

GET YOUR WEBHOOK URL30-DAY FREE TRIAL — NO CARD
05FAQ

Fair questions, straight answers

Q1How do I verify a webhook is really from coinsentry?

Set a secret in your webhook settings. Every delivery then carries an X-Coinsentry-Signature header: the hex HMAC-SHA256 of the exact request body, keyed with your secret. Recompute it over the raw bytes you received and compare with a constant-time check.

Q2What does the webhook payload look like?

A JSON object: event ("price_alert" or "test"), an alert object with pairSymbol, exchange, currentPrice, targetPrice (both strings), alertType and triggeredAt (unix ms), plus a top-level timestamp. Test deliveries use the exact production shape, so parse once.

Q3Can I set custom headers or a different HTTP method?

Yes — POST, PUT or PATCH, plus any custom headers you need (an auth token for your own endpoint, say). Content-Type and the signature header are always set by coinsentry and can't be overridden.

Q4What happens if my endpoint is down?

Failed deliveries are retried automatically. Your endpoint has 10 seconds to respond; respond with a 2xx quickly and do slow work asynchronously. Make handling idempotent — a retry means the same alert can arrive more than once.

Q5Do I need an API key to use webhooks?

No. Webhooks are outbound from coinsentry to your URL — you configure the URL, optional secret, method and headers in the dashboard. No polling, no API key, no exchange account connection.

Know
first.

Ten seconds to set an alert.

LAUNCH COINSENTRY30-DAY FREE TRIAL — NO CARD