API reference
Webhooks
POST
/v1/webhooksPaid plansRegister a receiver. The secret is shown once. New webhooks receive events from now on.
| Parameter | Description |
|---|---|
url | https, on a public host and the default port. |
event_types | Optional. All types by default. See Change events. |
scope | watchlist (default) or all. |
curl -X POST -H "X-API-Key: $STRATADB_KEY" \
-H "Content-Type: application/json" -d '{"url":"https://hooks.example.com/stratadb","event_types":["ai_provider_added"],"scope":"watchlist"}' \
https://api.stratadb.io/v1/webhooksconst res = await fetch("https://api.stratadb.io/v1/webhooks", {
method: "POST",
headers: { "X-API-Key": process.env.STRATADB_KEY, "Content-Type": "application/json" },
body: JSON.stringify({"url":"https://hooks.example.com/stratadb","event_types":["ai_provider_added"],"scope":"watchlist"}),
});
const data = await res.json();import os, requests
res = requests.post(
"https://api.stratadb.io/v1/webhooks",
headers={"X-API-Key": os.environ["STRATADB_KEY"]},
json={"url":"https://hooks.example.com/stratadb","event_types":["ai_provider_added"],"scope":"watchlist"},
)
data = res.json()Response 201
{
"id": 7,
"url": "https://hooks.example.com/stratadb",
"event_types": [
"ai_provider_added"
],
"scope": "watchlist",
"secret": "whsec_...",
"note": "Save the secret: it signs each delivery and is shown only once."
}GET
/v1/webhooksYour webhooks, with their failure counts.
curl -H "X-API-Key: $STRATADB_KEY" \
https://api.stratadb.io/v1/webhooksconst res = await fetch("https://api.stratadb.io/v1/webhooks", {
headers: { "X-API-Key": process.env.STRATADB_KEY },
});
const data = await res.json();import os, requests
res = requests.get(
"https://api.stratadb.io/v1/webhooks",
headers={"X-API-Key": os.environ["STRATADB_KEY"]},
)
data = res.json()Response
{
"webhooks": [
{
"id": 7,
"url": "https://hooks.example.com/stratadb",
"event_types": [
"ai_provider_added"
],
"scope": "watchlist",
"active": 1,
"failures": 0,
"created_at": 1793691482000
}
]
}POST
/v1/webhooks/{id}/testSend a clearly fake event with a real signature, to build and check your receiver.
curl -X POST -H "X-API-Key: $STRATADB_KEY" \
https://api.stratadb.io/v1/webhooks/7/testconst res = await fetch("https://api.stratadb.io/v1/webhooks/7/test", {
method: "POST",
headers: { "X-API-Key": process.env.STRATADB_KEY },
});
const data = await res.json();import os, requests
res = requests.post(
"https://api.stratadb.io/v1/webhooks/7/test",
headers={"X-API-Key": os.environ["STRATADB_KEY"]},
)
data = res.json()Response
{
"delivered": true,
"status": 200
}DELETE
/v1/webhooks/{id}Delete it. Returns 204.
curl -X DELETE -H "X-API-Key: $STRATADB_KEY" \
https://api.stratadb.io/v1/webhooks/7const res = await fetch("https://api.stratadb.io/v1/webhooks/7", {
method: "DELETE",
headers: { "X-API-Key": process.env.STRATADB_KEY },
});import os, requests
res = requests.delete(
"https://api.stratadb.io/v1/webhooks/7",
headers={"X-API-Key": os.environ["STRATADB_KEY"]},
)Deliveries
Each delivery is a POST with the events as JSON. One delivery can carry several events, so loop over events. Deliveries are at least once, so use the event id to ignore repeats.
{
"events": [
{
"id": 0,
"type": "test",
"company": "example.com",
"technology": null,
"details": {
"note": "This is a test delivery from StrataDB."
},
"occurred_at": "2026-11-03T12:00:00.000Z"
}
]
}
Verifying the signature
The StrataDB-Signature header is t=TIMESTAMP,v1=HEX, the HMAC-SHA256 of TIMESTAMP.BODY using your secret. Check it against the raw body, before parsing it.
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const expected = createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
return timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}import hashlib, hmac
def verify(raw_body: bytes, header: str, secret: str) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
signed = parts["t"].encode() + b"." + raw_body
expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts["v1"])