Webhook Endpoints Reference
GitHub webhook integration for automated test triggering.
Incoming Webhook: POST /api/webhooks/github/:projectId
The raw HTTP endpoint that receives GitHub push events. Registered in apps/api (Hono route).
Authentication: HMAC-SHA256 signature (GitHub webhook secret)
Headers:
| Header | Description |
|---|---|
X-Hub-Signature-256 |
sha256=<hmac> computed with your webhook secret |
X-GitHub-Event |
Event type: push, pull_request, etc. |
X-GitHub-Delivery |
Unique delivery ID |
Supported events: push, pull_request
Response:
200— Event received and queued400— Missing or invalid signature404— Project not found or webhook not configured429— Rate limit exceeded (30 req/min per IP)
tRPC Webhook Procedures
All procedures require authentication.
webhooks.configure
Create or replace webhook configuration for a project. Returns the webhook URL and generated secret — the secret is only shown once.
Input:
{
projectId: string // ULID
branches: string[] // Empty = all branches
filePatterns: string[] // Glob patterns, empty = any file
}
Response:
{
configId: string
secret: string // Store this — it won't be shown again
}
Rate limit: 30 req/min (webhook rate limiter)
webhooks.getConfig
Get webhook configuration (without exposing the secret).
Input: { projectId: string }
Response:
{
configId: string
active: boolean
branches: string[]
filePatterns: string[]
createdAt: Date
updatedAt: Date
} | null
webhooks.setActive
Enable or disable webhook delivery for a project.
Input: { projectId: string, active: boolean }
Response: { active: boolean }
webhooks.rotateSecret
Generate a new webhook secret without changing other settings. Returns the new secret — update your GitHub webhook configuration immediately.
Input: { projectId: string }
Response: { secret: string }
webhooks.listEvents
List recent webhook event deliveries.
Input:
{
projectId: string
limit?: number // 1-100, default 20
status?: 'PENDING' | 'PROCESSED' | 'FAILED' | 'SKIPPED' | 'ABANDONED'
}
Response:
{
events: Array<{
id: string
deliveryId: string
eventType: string
status: string
attempts: number
error: string | null
createdAt: Date
processedAt: Date | null
nextRetryAt: Date | null
}>
}
webhooks.delete
Delete webhook configuration for a project.
Input: { projectId: string }
Response: { deleted: true }
Webhook Signature Verification
GitHub signs each delivery using HMAC-SHA256 with your webhook secret. The platform verifies this using a timing-safe comparison:
X-Hub-Signature-256: sha256=<hex>
- Uses
crypto.subtle(Web Crypto API) for constant-time comparison - Mismatched or missing signatures return 400
Trigger Conditions
When a webhook event arrives, the trigger service evaluates:
- Branch filter — if
branchesis non-empty, the push must target a listed branch - File pattern filter — if
filePatternsis non-empty, at least one changed file must match a glob pattern - Deduplication — if a test run already exists for the same
projectId + commitSha + eventTypewithin the last hour, the event is skipped - Debouncing — rapid pushes to the same branch are coalesced (configurable
debounceMs)