Webhooks
Webhooks let external systems subscribe to events that happen in Lathe Studio — test run completions, build creations, release status changes, and more.
Availability: Webhooks are available on Pro (up to 5 endpoints) and Enterprise (unlimited endpoints) plans.
Event Taxonomy#
All events follow the naming convention: {resource}.{action}.{version}
| Event | Trigger | Availability |
|---|---|---|
testrun.created.v1 | A new test run is created | Pro+ |
testrun.submitted.v1 | A tester submits a test run | Pro+ |
testrun.completed.v1 | A test run is marked completed (after build completion) | Pro+ |
testcase.failed.v1 | A test case is recorded as failed in an execution | Pro+ |
build.created.v1 | A new build is created via API, UI, or webhook | Pro+ |
release.released.v1 | A release status changes to released | Pro+ |
Event Payload Structure#
All events share a common envelope:
{
"id": "evt_01HXYZ",
"event": "testrun.submitted.v1",
"created_at": "2026-03-01T14:32:00Z",
"data": { ... }
}
testrun.submitted.v1
{
"id": "evt_01HABC",
"event": "testrun.submitted.v1",
"created_at": "2026-03-01T14:32:00Z",
"data": {
"run_id": "run_01HDEF",
"project_id": "prj_01HGHI",
"build_id": "bld_01HJKL",
"release_id": "rel_01HMNO",
"submitted_by": "usr_01HPQR",
"results_summary": {
"pass": 42,
"fail": 3,
"blocked": 1,
"skipped": 4,
"total": 50
}
}
}
build.created.v1
{
"id": "evt_01HSTU",
"event": "build.created.v1",
"created_at": "2026-03-01T12:00:00Z",
"data": {
"build_id": "bld_01HVWX",
"project_id": "prj_01HGHI",
"name": "v2.4.1",
"commit_sha": "a1b2c3d4",
"branch": "main",
"source": "api"
}
}
Payloads are self-contained — they include all the data you need to act without making follow-up API calls.
Signature Verification#
Every webhook delivery includes an X-Perpetual-Signature header. Verify this signature before processing the payload to ensure it came from Lathe Studio.
The signature is an HMAC-SHA256 digest of the raw request body, keyed with your webhook secret:
X-Perpetual-Signature: sha256=a1b2c3d4e5f6...
Verification Examples
Node.js:
import crypto from 'crypto'
function verifyWebhookSignature(
rawBody: string,
signatureHeader: string,
secret: string
): boolean {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex')
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signatureHeader)
)
}
Python:
import hmac
import hashlib
def verify_signature(raw_body: bytes, signature_header: str, secret: str) -> bool:
expected = 'sha256=' + hmac.new(
secret.encode(), raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature_header)
Always use a timing-safe comparison (timingSafeEqual / hmac.compare_digest) to prevent timing attacks.
Registering a Webhook Endpoint#
Webhook registration is managed in Organization Settings → Webhooks.
To register an endpoint:
- Enter your endpoint URL (must be HTTPS)
- Select the events to subscribe to
- Save — a signing secret is generated and shown once
Your endpoint must respond with a 2xx status within 10 seconds or the delivery is treated as failed.
Retry Policy#
Failed deliveries (non-2xx response, timeout, or connection error) are retried with exponential backoff:
| Attempt | Delay |
|---|---|
| 1 (initial) | Immediate |
| 2 | 5 minutes |
| 3 | 30 minutes |
| 4 | 2 hours |
| 5 | 12 hours |
After 5 failed attempts, the event is sent to the dead-letter queue and delivery is stopped. You can view and replay dead-letter events from the Webhooks settings page.
Developer Skill#
Download the Lathe Studio Developer Skill for copy-paste signature verification examples, retry schedules, and CI/CD integration recipes in Node.js, Python, and Go.
Best Practices#
- Respond immediately, process asynchronously. Return
200 OKimmediately and process the payload in a background job to avoid timeouts. - Handle duplicate deliveries. Use
evt.idto deduplicate — the same event may be delivered more than once after retries. - Verify signatures. Never process a webhook without first verifying the signature.
- Monitor the dead-letter queue. Check failed deliveries periodically in Org Settings.