Skip to main content

Overview

Webhooks allow you to build or set up integrations that subscribe to specific events in your Gitea repositories. When an event is triggered, Gitea sends an HTTP POST payload to the webhook’s configured URL. Webhooks can be configured to trigger for specific events or all repository events.

Webhook Types

Gitea supports multiple webhook formats for integration with various platforms:
  • Gitea - Native Gitea webhook format
  • Gogs - Gogs-compatible webhook format
  • Slack - Slack notifications
  • Discord - Discord channel notifications
  • DingTalk - DingTalk group notifications
  • Telegram - Telegram bot messages
  • Microsoft Teams - Teams channel notifications
  • Feishu - Feishu/Lark notifications
  • Matrix - Matrix room notifications
  • WeCom - WeChat Work notifications
  • Packagist - Packagist package updates

Event Types

Webhooks can be configured to trigger on the following events:
EventDescription
createBranch or tag created
deleteBranch or tag deleted
forkRepository forked
pushGit push to repository
issuesIssue opened, closed, reopened, edited, or deleted
issue_assignIssue assigned or unassigned
issue_labelIssue labels updated
issue_milestoneIssue milestone changed
issue_commentComment created, edited, or deleted on issue
pull_requestPull request opened, closed, reopened, edited, or synchronized
pull_request_assignPull request assigned or unassigned
pull_request_labelPull request labels updated
pull_request_milestonePull request milestone changed
pull_request_commentComment on pull request
pull_request_review_approvedPull request approved
pull_request_review_rejectedPull request rejected
pull_request_review_commentReview comment on pull request
pull_request_syncPull request synchronized
pull_request_review_requestReview requested on pull request
repositoryRepository created or deleted
releaseRelease published, updated, or deleted
packagePackage created or deleted
wikiWiki page created, edited, or deleted
statusCommit status updated
workflow_runGitHub Actions workflow run event
workflow_jobGitHub Actions workflow job event
Reference: modules/webhook/type.go:10-43

Creating a Webhook

2
  • Go to your repository settings
  • Click on Webhooks in the sidebar
  • Click Add Webhook and select the webhook type
  • 3
    Configure the webhook
    4
    Provide the following configuration:
    5
  • Payload URL: The endpoint that will receive webhook POST requests
  • Content Type: Choose between application/json or application/x-www-form-urlencoded
  • Secret: Optional secret token for validating payloads
  • Trigger events: Select which events should trigger the webhook
  • Active: Enable or disable the webhook
  • 6
    Test the webhook
    7
    After creating the webhook, you can trigger a test delivery to verify the configuration.

    Webhook Configuration

    HTTP Method

    By default, webhooks use POST requests. You can configure a custom HTTP method if needed:
    type Webhook struct {
        HTTPMethod  string  // Default: POST
        URL         string
        ContentType HookContentType
    }
    
    Reference: models/webhook/webhook.go:129

    Content Types

    Webhooks support two content types:
    • JSON (application/json) - Recommended format, payload sent as JSON
    • Form (application/x-www-form-urlencoded) - Payload sent as form data

    Authorization Headers

    You can configure custom authorization headers for webhooks:
    # Example: Bearer token authentication
    Authorization: Bearer your-token-here
    
    # Example: Basic authentication
    Authorization: Basic base64-encoded-credentials
    
    The authorization header is encrypted and stored securely in the database. Reference: models/webhook/webhook.go:209-229

    Webhook Payloads

    All webhook payloads follow a consistent structure with event-specific data.

    Push Event

    {
      "ref": "refs/heads/main",
      "before": "9049f1265b7d61be4a8904a9a27120d2064dab3b",
      "after": "0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c",
      "compare_url": "http://localhost:3000/gitea/test/compare/9049f1265b7d...0d1a26e67d8f",
      "commits": [
        {
          "id": "0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c",
          "message": "Update README.md",
          "url": "http://localhost:3000/gitea/test/commit/0d1a26e67d8f",
          "author": {
            "name": "John Doe",
            "email": "[email protected]",
            "username": "johndoe"
          },
          "committer": {
            "name": "John Doe",
            "email": "[email protected]",
            "username": "johndoe"
          },
          "timestamp": "2026-03-10T12:00:00Z",
          "added": [],
          "removed": [],
          "modified": ["README.md"]
        }
      ],
      "total_commits": 1,
      "head_commit": {
        "id": "0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c",
        "message": "Update README.md",
        "url": "http://localhost:3000/gitea/test/commit/0d1a26e67d8f"
      },
      "repository": {
        "id": 1,
        "name": "test",
        "full_name": "gitea/test",
        "html_url": "http://localhost:3000/gitea/test"
      },
      "pusher": {
        "id": 1,
        "login": "johndoe",
        "email": "[email protected]"
      },
      "sender": {
        "id": 1,
        "login": "johndoe"
      }
    }
    
    Reference: modules/structs/hook.go:298-325

    Issue Event

    {
      "action": "opened",
      "number": 42,
      "issue": {
        "id": 123,
        "number": 42,
        "title": "Bug: Application crashes on startup",
        "body": "When launching the application...",
        "state": "open",
        "user": {
          "id": 1,
          "login": "reporter",
          "email": "[email protected]"
        },
        "labels": [
          {
            "id": 1,
            "name": "bug",
            "color": "ee0701"
          }
        ],
        "created_at": "2026-03-10T12:00:00Z",
        "updated_at": "2026-03-10T12:00:00Z"
      },
      "repository": {
        "id": 1,
        "name": "project",
        "full_name": "org/project"
      },
      "sender": {
        "id": 1,
        "login": "reporter"
      }
    }
    
    Reference: modules/structs/hook.go:384-405

    Pull Request Event

    {
      "action": "opened",
      "number": 15,
      "pull_request": {
        "id": 456,
        "number": 15,
        "title": "Add new feature",
        "body": "This PR implements...",
        "state": "open",
        "user": {
          "id": 2,
          "login": "contributor"
        },
        "head": {
          "ref": "feature-branch",
          "sha": "abc123..."
        },
        "base": {
          "ref": "main",
          "sha": "def456..."
        },
        "mergeable": true,
        "merged": false
      },
      "repository": {
        "id": 1,
        "name": "project",
        "full_name": "org/project"
      },
      "sender": {
        "id": 2,
        "login": "contributor"
      }
    }
    
    Reference: modules/structs/hook.go:427-452

    Create Event

    {
      "sha": "0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c",
      "ref": "refs/heads/new-feature",
      "ref_type": "branch",
      "repository": {
        "id": 1,
        "name": "test",
        "full_name": "gitea/test"
      },
      "sender": {
        "id": 1,
        "login": "johndoe"
      }
    }
    
    Reference: modules/structs/hook.go:155-172

    Webhook Security

    Secret Token Validation

    When you set a secret token for your webhook, Gitea signs the payload with HMAC-SHA256 and includes the signature in the request headers:
    X-Gitea-Signature: sha256=<signature>
    
    Validate the signature in your webhook handler:
    import hmac
    import hashlib
    
    def verify_signature(payload_body, secret_token, signature_header):
        expected = 'sha256=' + hmac.new(
            secret_token.encode('utf-8'),
            payload_body.encode('utf-8'),
            hashlib.sha256
        ).hexdigest()
        return hmac.compare_digest(expected, signature_header)
    

    Request Headers

    Webhook requests include identifying headers:
    X-Gitea-Event: push
    X-Gitea-Delivery: 550e8400-e29b-41d4-a716-446655440000
    X-Gitea-Signature: sha256=...
    Content-Type: application/json
    User-Agent: GiteaServer
    

    Branch Filtering

    You can configure webhooks to trigger only for specific branches using glob patterns:
    # Trigger only for main branch
    main
    
    # Trigger for release branches
    release/*
    
    # Trigger for feature branches
    feature/**
    
    # Multiple patterns (comma-separated)
    main,develop,release/*
    
    Reference: models/webhook/webhook.go:25

    Webhook Delivery Status

    Webhooks have three possible delivery statuses:
    • None - Not yet delivered
    • Succeed - Successfully delivered (2xx response)
    • Fail - Delivery failed (non-2xx response or network error)
    Reference: modules/webhook/type.go:133-141

    Viewing Delivery History

    Each webhook maintains a delivery history showing:
    • Request payload
    • Response status code
    • Response body
    • Delivery timestamp
    • Delivery duration
    You can redeliver any previous webhook event from the delivery history.

    System Webhooks

    Administrators can create system-level webhooks that trigger for events across all repositories:
    1. Navigate to Site Administration
    2. Click System Webhooks
    3. Configure webhook with the same options as repository webhooks
    System webhooks are useful for:
    • Organization-wide event monitoring
    • Security auditing
    • Automated backups
    • External analytics
    Reference: models/webhook/webhook.go:127

    Troubleshooting

    Webhook Not Triggering

    • Verify the webhook is Active
    • Check that the event type is enabled in webhook settings
    • Verify branch filter matches the pushed branch
    • Check webhook delivery history for errors

    Timeout Errors

    • Webhook endpoints must respond within the configured timeout
    • Use asynchronous processing for long-running tasks
    • Return 2xx response immediately, process in background

    Authentication Failures

    • Verify secret token matches on both sides
    • Check authorization header format
    • Ensure HTTPS is used for secure token transmission

    Best Practices

    1. Use HTTPS: Always use HTTPS endpoints for webhooks to protect secrets and payload data
    2. Validate signatures: Always verify the webhook signature before processing payloads
    3. Respond quickly: Return HTTP 2xx response immediately, process asynchronously
    4. Handle retries: Implement idempotency to handle duplicate deliveries
    5. Log deliveries: Maintain logs of webhook deliveries for debugging
    6. Use specific events: Subscribe only to needed events to reduce noise
    7. Secure secrets: Store webhook secrets securely, rotate regularly

    API Reference

    Manage webhooks programmatically using the Gitea API:
    # Create a webhook
    curl -X POST "https://gitea.example.com/api/v1/repos/{owner}/{repo}/hooks" \
      -H "Authorization: token YOUR_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "type": "gitea",
        "config": {
          "content_type": "json",
          "url": "https://example.com/webhook"
        },
        "events": ["push", "pull_request"],
        "active": true
      }'
    
    # List webhooks
    curl "https://gitea.example.com/api/v1/repos/{owner}/{repo}/hooks" \
      -H "Authorization: token YOUR_TOKEN"
    
    # Delete a webhook
    curl -X DELETE "https://gitea.example.com/api/v1/repos/{owner}/{repo}/hooks/{id}" \
      -H "Authorization: token YOUR_TOKEN"
    
    Reference: modules/structs/hook.go:48-83

    Build docs developers (and LLMs) love