Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Github Webhooks Laravel Package

spatie/laravel-github-webhooks

Handle GitHub webhooks in Laravel: verify signatures, log valid calls, and dispatch jobs/events per webhook type. Includes a GitHubWebhookCall model to access payloads and queueable handlers for event-driven integrations.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require spatie/laravel-github-webhooks
    php artisan vendor:publish --provider="Spatie\GitHubWebhooks\GitHubWebhooksServiceProvider" --tag="github-webhooks-config"
    php artisan vendor:publish --provider="Spatie\GitHubWebhooks\GitHubWebhooksServiceProvider" --tag="github-webhooks-migrations"
    php artisan migrate
    
  2. Configure GitHub Webhook:

    • Set GITHUB_WEBHOOK_SECRET in .env (found in GitHub repo settings).
    • Add to config/github-webhooks.php:
      'signing_secret' => env('GITHUB_WEBHOOK_SECRET'),
      'jobs' => [
          'issues.opened' => \App\Jobs\GitHubWebhooks\HandleIssueOpened::class,
      ],
      
  3. Route Setup (in routes/api.php):

    Route::githubWebhooks('github-webhook');
    
  4. First Use Case: Create a job to handle a specific event (e.g., issues.opened):

    namespace App\Jobs\GitHubWebhooks;
    use Illuminate\Bus\Queueable;
    use Spatie\GitHubWebhooks\Models\GitHubWebhookCall;
    
    class HandleIssueOpened implements ShouldQueue {
        use Queueable;
        public function __construct(public GitHubWebhookCall $webhookCall) {}
        public function handle() {
            $issue = $this->webhookCall->payload('issue');
            // Process issue (e.g., notify team, update DB)
        }
    }
    

Implementation Patterns

Usage Patterns

  1. Job-Based Handling:

    • Define jobs in config/github-webhooks.php for specific events (e.g., pull_request.closed).
    • Use * as a wildcard for generic handlers (e.g., log all events).
    • Example:
      'jobs' => [
          'pull_request.*' => \App\Jobs\GitHubWebhooks\HandlePR::class,
          '*' => \App\Jobs\GitHubWebhooks\LogWebhook::class,
      ],
      
  2. Event Listeners:

    • Register listeners in EventServiceProvider for real-time reactions:
      protected $listen = [
          'github-webhooks::push' => \App\Listeners\SyncRepo::class,
      ];
      
    • Useful for immediate actions (e.g., triggering CI/CD pipelines).
  3. Payload Access:

    • Extract nested data with dot notation:
      $actor = $webhookCall->payload('sender.login');
      $repo = $webhookCall->payload('repository.full_name');
      
  4. Queue Optimization:

    • Always queue jobs to avoid timeouts (GitHub expects a 200 response within seconds).
    • Example job:
      class HandleWebhook implements ShouldQueue {
          use Dispatchable, InteractsWithQueue, Queueable;
          public function handle() { /* ... */ }
      }
      

Workflows

  1. Development Workflow:

    • Disable signature verification locally ('verify_signature' => false).
    • Test with GitHub’s webhook testing tool.
  2. Production Workflow:

    • Enable signature verification ('verify_signature' => true).
    • Monitor failed webhooks via the github_webhook_calls table.
  3. Debugging:

    • Log payloads for inspection:
      \Log::info('Webhook payload:', $webhookCall->payload());
      
  4. Integration with Other Packages:

    • Combine with spatie/laravel-activitylog to track changes:
      Activity::log('github_webhook', 'Processed ' . $webhookCall->eventActionName());
      

Gotchas and Tips

Pitfalls

  1. Signature Mismatches:

    • Issue: Invalid GITHUB_WEBHOOK_SECRET causes WebhookFailed exceptions.
    • Fix: Double-check the secret in GitHub repo settings and .env.
  2. Queue Failures:

    • Issue: Unhandled exceptions in jobs may leave webhooks stuck.
    • Fix: Use fail() in jobs to log errors:
      try { /* ... */ } catch (\Exception $e) {
          \Log::error($e);
          $this->fail($e);
      }
      
  3. Payload Parsing:

    • Issue: Nested payload keys may fail if malformed.
    • Fix: Validate payload structure:
      if (!isset($webhookCall->payload('action'))) {
          throw new \InvalidArgumentException('Invalid payload');
      }
      
  4. Route Conflicts:

    • Issue: CSRF protection may block webhook routes in web.php.
    • Fix: Exclude the route from VerifyCsrfToken middleware:
      protected $except = ['github-webhook'];
      

Debugging Tips

  1. Inspect Raw Payloads:

    • Use Tinker to debug:
      php artisan tinker
      >>> $webhook = \Spatie\GitHubWebhooks\Models\GitHubWebhookCall::find(1);
      >>> $webhook->payload();
      
  2. Check Headers:

    • Verify GitHub’s X-GitHub-Event and X-Hub-Signature-256 headers:
      $event = $webhookCall->headers()->get('X-GitHub-Event');
      $signature = $webhookCall->headers()->get('X-Hub-Signature-256');
      
  3. Retry Failed Webhooks:

    • Manually reprocess stuck webhooks:
      php artisan queue:work --once
      
    • Or dispatch manually:
      ProcessGitHubWebhookJob::dispatch($webhookCall);
      

Extension Points

  1. Custom Models:

    • Extend GitHubWebhookCall to add fields (e.g., processed_at):
      class CustomWebhookCall extends GitHubWebhookCall {
          protected $casts = ['processed_at' => 'datetime'];
      }
      
    • Update config/github-webhooks.php:
      'model' => \App\Models\CustomWebhookCall::class,
      
  2. Custom Profiles:

    • Filter webhooks dynamically by implementing WebhookProfile:
      class CustomProfile implements WebhookProfile {
          public function shouldProcess(GitHubWebhookCall $call) {
              return $call->payload('repository.full_name') === 'your/repo';
          }
      }
      
    • Update config:
      'profile' => \App\Profiles\CustomProfile::class,
      
  3. Webhook Retries:

    • Implement exponential backoff for retries:
      class RetryJob extends ProcessGitHubWebhookJob {
          public function handle() {
              if ($this->attempts() > 3) {
                  \Log::error('Max retries reached');
                  return;
              }
              parent::handle();
          }
      }
      
  4. Testing:

    • Mock webhooks in tests:
      $payload = json_encode(['action' => 'opened']);
      $this->postJson('/github-webhook', $payload, [
          'HTTP_X_GITHUB_EVENT' => 'issues',
          'HTTP_X_HUB_SIGNATURE_256' => 'sha256=' . hash_hmac('sha256', $payload, config('github-webhooks.signing_secret')),
      ]);
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope
anil/file-picker
broqit/fields-ai