Integrations and AI
Webhooks
Get an HTTP POST on your own server when hackathons are added or updated, with the payload shape and how to secure it
Webhooks send hackathon data to a URL you control when HackathonRadar adds or changes an event. You manage them at /settings/webhooks.
Create an endpoint
Open Webhooks
Go to /settings/webhooks.Enter your URL
Paste the address that should receive deliveries, for examplehttps://example.com/webhook. Usehttps.Pick a delivery type
Choose All Updates or Newly Seen from the dropdown. The next section explains the difference.Add headers (optional)
Click Add Header to send fixed headers with every delivery, such as a shared secret. Add as many as you need.Create it
Click Create Webhook. The endpoint appears in the list as Active.
Each endpoint in the list shows its URL, type, status, when it was created and when it Last fired. Use the switch to pause or resume it, and the trash button to delete it. You can create several endpoints.
What gets delivered and when
| Delivery type | What you receive | event_type |
|---|---|---|
| Newly Seen | Each hackathon when it is first added to HackathonRadar | created |
| All Updates | Each hackathon when it is added or changes, including when it is removed or restored | updated |
Deliveries go out as changes happen, and a daily run sends anything since your endpoint last fired. A new endpoint gets the last 24 hours of hackathons in its first daily run.
Some things to plan for:
- One hackathon per request. Each POST carries a single hackathon.
- Upsert on
id. The same hackathon can arrive more than once, for example when it changes twice in a day. Store deliveries keyed onidrather than inserting a new row each time. - All Updates includes new hackathons, labelled
updated. Comparefirst_seen_atwithlast_seen_atif you need to tell them apart. - Removed hackathons arrive with
is_deleted: true. - Every hackathon is sent. Webhooks cannot be limited to a saved search, so filter on your side.
Payload
Every delivery is a POST with Content-Type: application/json. The body is the full hackathon record, plus event_type, timestamp, organizers, sponsors and quality_score. This example is shortened.
{
"id": "7f1c2a9e-3b4d-4e5f-8a6b-9c0d1e2f3a4b",
"event_type": "created",
"timestamp": "2026-10-24T08:14:03.512Z",
"title": "Bristol AI Build Weekend",
"slug": "bristol-ai-build-weekend",
"start_at": "2026-11-14T09:00:00.000Z",
"end_at": "2026-11-15T18:00:00.000Z",
"timezone": "Europe/London",
"type": "in-person",
"categories": ["AI", "Open Source"],
"prize_pool": 5000,
"prize_currency": "GBP",
"prize_pool_usd": 6300,
"cash_prizes": true,
"venue_name": "Engine Shed",
"city": "Bristol",
"country": "United Kingdom",
"lat": 51.449,
"lng": -2.581,
"website_url": "https://example.com/bristol-ai",
"registration_url": "https://example.com/bristol-ai/register",
"student_only": false,
"participant_count": 120,
"description": "A weekend of building with AI...",
"first_seen_at": "2026-10-24T08:13:58.000Z",
"last_seen_at": "2026-10-24T08:13:58.000Z",
"enriched": true,
"featured": false,
"is_deleted": false,
"organizers": [
{
"id": "b2c3d4e5-0000-4000-8000-000000000001",
"name": "Bristol Builders",
"domain": "bristolbuilders.example",
"website_url": "https://bristolbuilders.example",
"twitter": null,
"linkedin": null,
"instagram": null,
"image_url": null,
"email": "hello@bristolbuilders.example",
"email_confidence": 0.9,
"created_at": "2026-03-02T10:00:00.000Z"
}
],
"sponsors": [
{
"id": "c3d4e5f6-0000-4000-8000-000000000002",
"name": "Example Cloud",
"domain": "examplecloud.example",
"website_url": "https://examplecloud.example",
"logo_url": "https://example.com/logos/example-cloud.png",
"sponsored_count": 14
}
],
"quality_score": {
"score_total": 78,
"confidence": 0.85,
"reasons_json": ["Clear prize information", "Named sponsors"],
"computed_at": "2026-10-24T08:20:00.000Z"
}
}quality_score is null until a score has been computed, and organizers and sponsors are empty arrays when none are known. Field meanings match the REST API.
Secure your endpoint
To make sure a request came from HackathonRadar, add a secret header when you create the endpoint and reject requests without it.
Make a secret
Generate a long random value, for example withopenssl rand -hex 32.Add it as a header
On /settings/webhooks, click Add Header. Use a name such asX-Webhook-Secretand paste the value.Check it on your server
Compare the header with your stored value before you trust the body.
import crypto from "node:crypto";
app.post("/webhook", express.json({ limit: "2mb" }), (req, res) => {
const got = Buffer.from(req.get("X-Webhook-Secret") ?? "");
const want = Buffer.from(process.env.RADAR_WEBHOOK_SECRET);
if (got.length !== want.length || !crypto.timingSafeEqual(got, want)) {
return res.sendStatus(401);
}
res.sendStatus(200); // reply first, then process
upsertHackathon(req.body); // keyed on req.body.id
});Headers are stored with the endpoint and cannot be edited. To rotate a secret, create a new endpoint with the new header, then delete the old one.
When a delivery fails
Any 2xx response counts as delivered. A failed delivery (an error status or an unreachable server) is not resent, so a hackathon you missed arrives again only if it changes. Reply quickly and do heavy work after responding.
If your endpoint was down, backfill the gap with the REST API. To stop deliveries while you fix something, turn the endpoint's switch off. Turning it back on resumes from its last delivery.
Test an endpoint
There is no test button. To see real deliveries before you build a receiver, create an endpoint pointing at a request inspector you control, choose All Updates, and wait for the next change or the daily run. Delete the test endpoint when you are done.