POST /api/install/webhook
File: app/api/install/webhook/route.ts
GitHub sends webhook events here whenever something changes with an installation, repository, or organization. The endpoint verifies the HMAC-SHA256 signature, figures out what happened, and updates Supabase accordingly.
Configuration
In your GitHub App settings, set the Webhook URL to:
https://your-domain.com/api/install/webhookSet the Webhook secret to the same value as your GITHUB_WEBHOOK_SECRET environment variable.
Security
Every request must include the X-Hub-Signature-256 header:
X-Hub-Signature-256: sha256=<hex-digest>The signature is computed as:
HMAC-SHA256(GITHUB_WEBHOOK_SECRET, requestBody)If GITHUB_WEBHOOK_SECRET isn’t configured, the endpoint logs a warning and accepts all requests. Not recommended for production.
Request headers
| Header | Required | Description |
|---|---|---|
X-GitHub-Event | yes | Event type (e.g., installation) |
X-Hub-Signature-256 | yes | HMAC-SHA256 signature of the body |
Content-Type | yes | application/json |
Supported events
installation
Triggered when the GitHub App is installed, deleted, or suspended on an account.
Actions handled:
created/unsuspend— Fetches full installation details from GitHub API and upserts togithub_installationsdeleted— Removes the installation fromgithub_installationssuspend— Updates the installation row with suspended status
{
"action": "created",
"installation": {
"id": 12345678,
"app_id": 98765,
"account": { "login": "my-org", "id": 111111, "type": "Organization" }
}
}installation_repositories
Triggered when repositories are added to or removed from an installation.
Actions handled:
added/removed— Refreshes the installation details and repository list
organization
Triggered when an organization is renamed or deleted.
Actions handled:
- Logs the event for audit purposes (no automatic data mutation)
membership / member
Triggered when organization membership changes.
Actions handled:
- Logs the event for audit purposes
Responses
| Status | Condition |
|---|---|
200 | Event processed |
400 | Invalid JSON payload |
403 | Invalid HMAC signature |
500 | Processing error (event logged) |
All responses:
{ "ok": true }Implementation details
The handler delegates to InstallationService in lib/auth/server/installation-service.ts for:
- Validating installation IDs via
validateInstallation() - Fetching fresh installation details via
getInstallationDetails() - Upserting to Supabase via
upsertInstallation()inlib/supabase/installation-repository.ts
The handler is idempotent — processing the same event twice produces the same database state.
Debugging webhooks locally
Use a tunnel service like ngrok for local development:
ngrok http 3000Then set the webhook URL in your GitHub App to https://your-ngrok-url.ngrok.io/api/install/webhook.
Related
- Install Routes — install start, callback, status, complete
- Database Schema —
github_installationstable reference