Documentation
Webhooks
Rondar sends a signed HTTP request to your own address when a session finishes, a pull request opens or a release ships.
Know the events
Use a webhook to connect Rondar to your own tools: post a message to a team chat, update a ticket, or start a job.
| Event | When Rondar sends it | Fields in data |
|---|---|---|
session.completed |
A session finished its work | session_id, title, status, project_id |
session.failed |
A session failed | session_id, title, status, project_id |
pr.opened |
Rondar opened the pull request of a session | session_id, title, pr_url, pr_number |
release.shipped |
A deployment of a release completed | deployment_id, environment, session_id, project_id, url |
Add an endpoint
Open Settings → Webhooks and select Add webhook.
- Give the Payload URL. It must be a public HTTPS address.
- Give a description, if you want one.
- Select one event or more.
- Select Save endpoint.
Rondar shows the signing secret one time. It starts with whsec_. Copy it now and keep it with your other secrets: Rondar stores it encrypted and does not show it again.
Read the request
Each delivery is a POST request with a JSON body:
{
"event": "pr.opened",
"timestamp": "2026-10-13T09:24:11Z",
"data": {
"session_id": 1842,
"title": "Add an allergen filter to the breads page",
"pr_url": "https://github.com/example/bakery/pull/12",
"pr_number": 12
}
}
The request has these headers:
| Header | Value |
|---|---|
Content-Type |
application/json |
User-Agent |
Rondar-Webhooks/1.0 |
X-Rondar-Event |
The name of the event |
X-Rondar-Delivery |
The identifier of the delivery |
X-Rondar-Signature |
t=<unix time>,v1=<signature> |
Verify the signature
Anybody who knows your address can send a request to it. Verify the signature before you use a request.
The signature is the HMAC-SHA256 of the text <t>.<body>, with your signing secret as the key, written as lower-case hexadecimal. <t> is the time from the header and <body> is the body exactly as you received it.
Use the bytes of the body as they arrived. If your framework parses the JSON and you write it again, the signature does not match.
// Node.js, with Express
import crypto from "node:crypto";
import express from "express";
const app = express();
const secret = process.env.RONDAR_WEBHOOK_SECRET;
app.post("/rondar", express.raw({ type: "application/json" }), (req, res) => {
const header = req.get("X-Rondar-Signature") || "";
const parts = Object.fromEntries(header.split(",").map((part) => part.split("=")));
const expected = crypto
.createHmac("sha256", secret)
.update(`${parts.t}.`)
.update(req.body)
.digest("hex");
const valid =
parts.v1 &&
parts.v1.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
// Refuse a request that is older than five minutes.
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
if (!valid || !fresh) return res.status(400).end();
const { event, data } = JSON.parse(req.body);
console.log(event, data);
res.status(204).end();
});
app.listen(process.env.PORT || 3000);
# Python, with Flask
import hashlib
import hmac
import os
import time
from flask import Flask, abort, request
app = Flask(__name__)
secret = os.environ["RONDAR_WEBHOOK_SECRET"].encode()
@app.post("/rondar")
def rondar():
header = request.headers.get("X-Rondar-Signature", "")
parts = dict(part.split("=", 1) for part in header.split(",") if "=" in part)
signed = parts.get("t", "").encode() + b"." + request.get_data()
expected = hmac.new(secret, signed, hashlib.sha256).hexdigest()
if not hmac.compare_digest(parts.get("v1", ""), expected):
abort(400)
# Refuse a request that is older than five minutes.
if abs(time.time() - int(parts["t"])) > 300:
abort(400)
payload = request.get_json()
print(payload["event"], payload["data"])
return "", 204
Answer fast
Answer with a status from 200 to 299 in less than 10 seconds. Do the long work after the answer, for example in a queue.
If the answer is an error or does not come, Rondar tries again after 1 second and after 5 seconds. After three tries the delivery is failed, and Rondar does not try again by itself.
A delivery can arrive more than one time. X-Rondar-Delivery is the same for each try of one delivery, so use it to ignore a delivery that you already handled.
Test and inspect deliveries
- Send test sends an
endpoint.testevent to the endpoint. - The Delivery log lists each delivery with its status. Open one to see the request and the answer of your server.
- Retry this delivery sends a failed delivery again, with the same identifier and the same body.
Change or stop an endpoint
Rotate secret makes a new signing secret; change it in your server at the same time. Disable stops the deliveries and keeps the endpoint. Delete removes it.
A project or a session with its notifications turned off sends no webhook for its events.