Skip to content
Back to skills

Github Webhooks Integration

ASecurity

Set up webhooks, handle events, and build integrations.

  • 2 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 10, 2026
ai-agentsjavascriptpythonjavabashreactnodefastapitestinggitapi

Works with

  • cli
  • api

Security analysis

A100/100

Scanned September 10, 2026

npx -y skills add LoopyLuci/Skills --skill github-webhooks-integration --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Github Webhooks Integration?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Github Webhooks Integration
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/loopyluci-github-webhooks-integration/badge)](https://www.skillsdirectory.com/skills/loopyluci-github-webhooks-integration)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: github-webhooks-integration
description: Set up webhooks, handle events, and build integrations.
---

# GitHub Webhooks Integration

**Trigger**: Use when setting up GitHub webhooks, building integrations, or reacting to GitHub events programmatically.

## Webhook Events

| Event | When it fires | Payload includes |
|-------|--------------|------------------|
| `push` | Git push | commits, ref, before/after SHA |
| `pull_request` | PR opened/closed/sync | PR data, review status |
| `issues` | Issue created/edited/closed | Issue body, labels |
| `issue_comment` | Comment on issue/PR | Comment body, issue ref |
| `release` | Release published | Release data, assets |
| `workflow_run` | Workflow completed | Workflow status, conclusion |
| `star` | Repo starred/unstarred | Action (created/deleted) |
| `create`/`delete` | Branch/tag created/deleted | Ref type, ref name |

## Setting Up a Webhook

### Via API
```bash
gh api repos/:owner/:repo/hooks \
  --method POST \
  --input - << 'EOF'
{
  "name": "web",
  "active": true,
  "events": ["push", "pull_request", "issues"],
  "config": {
    "url": "https://example.com/github-webhook",
    "content_type": "json",
    "secret": "your-webhook-secret"
  }
}
EOF
```

### Via CLI
```bash
gh api repos/:owner/:repo/hooks --method POST \
  -f name=web \
  -f active=true \
  -f events[]=push \
  -f events[]=pull_request \
  -f config[url]=https://example.com/webhook \
  -f config[content_type]=json \
  -f config[secret]=my-secret
```

## Verifying Webhook Signatures

```python
# Python — verify HMAC-SHA256 signature
import hashlib, hmac

def verify_webhook(payload_body: bytes, signature_header: str, secret: str) -> bool:
    """Verify GitHub webhook signature."""
    signature = hmac.new(
        secret.encode(), payload_body, hashlib.sha256
    ).hexdigest()
    expected = f"sha256={signature}"
    return hmac.compare_digest(expected, signature_header)
```

```javascript
// Node.js
const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
  const sig = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(signature));
}
```

## Managing Webhooks

```bash
# List hooks
gh api repos/:owner/:repo/hooks --jq '.[].config.url'

# Get a specific hook
gh api repos/:owner/:repo/hooks/123456

# Update hook
gh api repos/:owner/:repo/hooks/123456 \
  --method PATCH \
  -f active=true \
  -f events[]=push

# Delete hook
gh api repos/:owner/:repo/hooks/123456 --method DELETE

# Test ping (sends test event)
gh api repos/:owner/:repo/hooks/123456/tests --method POST

# Recent deliveries
gh api repos/:owner/:repo/hooks/123456/deliveries --jq '.[].guid'
```

## Webhook Handler (FastAPI Example)

```python
from fastapi import FastAPI, Request, HTTPException
import hmac, hashlib

app = FastAPI()
WEBHOOK_SECRET = "your-webhook-secret"

@app.post("/github-webhook")
async def handle_webhook(request: Request):
    payload = await request.body()
    signature = request.headers.get("x-hub-signature-256", "")
    
    # Verify signature
    expected = "sha256=" + hmac.new(
        WEBHOOK_SECRET.encode(), payload, hashlib.sha256
    ).hexdigest()
    if not hmac.compare_digest(expected, signature):
        raise HTTPException(403, "Invalid signature")
    
    event = request.headers.get("x-github-event", "push")
    data = await request.json()
    
    if event == "push":
        branch = data["ref"].split("/")[-1]
        print(f"Push to {branch}: {data['head_commit']['message']}")
    elif event == "pull_request":
        action = data["action"]
        print(f"PR {data['pull_request']['number']}: {action}")
    
    return {"status": "ok"}
```

## Re-delivery & Troubleshooting

```bash
# List recent deliveries
gh api repos/:owner/:repo/hooks/123456/deliveries --jq \
  '.[] | {guid, status_code, delivered_at}'

# Get delivery details
gh api repos/:owner/:repo/hooks/123456/deliveries/DELIVERY_GUID

# Re-deliver a failed delivery
gh api repos/:owner/:repo/hooks/123456/deliveries/DELIVERY_GUID/attempts \
  --method POST
```

## Pitfalls
- **Signature verification**: Always verify — without it, anyone can POST to your endpoint
- **Payload size limit**: GitHub caps payloads at 25 MB — larger events are dropped
- **Retry on failure**: GitHub retries 3 times with exponential backoff if endpoint returns 5xx
- **Secret rotation**: Update the secret in both GitHub and your server — use `gh api` to patch
- **Local testing**: Use `smee.io` or `ngrok http 8000` for forwarding webhooks to localhost

## Verification
```bash
# Test ping
gh api repos/:owner/:repo/hooks/123456/tests --method POST

# Check recent deliveries
gh api repos/:owner/:repo/hooks/123456/deliveries --jq '.[0]'
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.