PHP Pro
Use when building PHP applications with modern PHP 8.3+ features, Laravel, or Symfony frameworks.
Before & after
Same prompt, same agent — the only difference is the skill.
Building a webhook handler in Laravel requires setting up a route, validating the Stripe signature, parsing the event, and then processing the specific event type you care about. For Stripe webhooks, you'd want to handle charge.succeeded, charge.refunded, and maybe customer.subscription.updated. You'll need the Stripe SDK installed, environment variables configured, and proper error handling. Do you have experience with Laravel service providers? Should this be in a controller or a separate event handler?
LARAVEL STRIPE WEBHOOK ENDPOINT
CONTROLLER: app/Http/Controllers/StripeWebhookController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Stripe\Webhook;
use Stripe\Exception\SignatureVerificationException;
use App\Events\ChargeSucceeded;
class StripeWebhookController extends Controller
{
public function handle(Request $request): JsonResponse
{
$payload = $request->getContent();
$sig_header = $request->header('Stripe-Signature');
$endpoint_secret = config('services.stripe.webhook_secret');
try {
$event = Webhook::constructEvent(
$payload,
$sig_header,
$endpoint_secret
);
} catch (SignatureVerificationException $e) {
return response()->json(
['error' => 'Signature verification failed'],
403
);
}
match ($event->type) {
'charge.succeeded' => $this->handleChargeSucceeded($event->data->object),
'charge.refunded' => $this->handleChargeRefunded($event->data->object),
'customer.subscription.updated' => $this->handleSubscriptionUpdated($event->data->object),
default => null,
};
return response()->json(['status' => 'success']);
}
private function handleChargeSucceeded(object $charge): void
{
$user = User::where('stripe_customer_id', $charge->customer)->firstOrFail();
$user->update(['last_payment_at' => now()]);
ChargeSucceeded::dispatch($user, $charge->amount);
}
private function handleChargeRefunded(object $charge): void
{
Refund::create([
'user_id' => User::where('stripe_customer_id', $charge->customer)->value('id'),
'amount' => $charge->amount_refunded,
'stripe_refund_id' => $charge->refunds->data[0]->id ?? null,
]);
}
}
ROUTE: routes/api.php
Route::post('/webhooks/stripe', \App\Http\Controllers\StripeWebhookController::class . '@handle')
->name('stripe.webhook')
->withoutMiddleware(\App\Http\Middleware\VerifyCsrfToken::class);
MIGRATION: database/migrations/2026_07_31_create_refunds_table.php
Schema::create('refunds', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->integer('amount');
$table->string('stripe_refund_id')->unique();
$table->timestamp('created_at')->useCurrent();
$table->index('user_id');
$table->index('created_at');
});
EVENT LISTENER: app/Listeners/UpdateSubscriptionStatus.php
use App\Events\ChargeSucceeded;
use App\Models\Subscription;
class UpdateSubscriptionStatus
{
public function handle(ChargeSucceeded $event): void
{
$subscription = Subscription::where('user_id', $event->user->id)
->whereNull('ended_at')
->first();
if ($subscription) {
$subscription->update(['stripe_charge_id' => $event->chargeId]);
}
}
}
TEST: tests/Unit/StripeWebhookTest.php
use Stripe\Event;
use Tests\TestCase;
class StripeWebhookTest extends TestCase
{
public function test_charge_succeeded_webhook_processes_correctly(): void
{
$user = User::factory()->create();
$payload = $this->mockStripePayload(
'charge.succeeded',
['customer' => $user->stripe_customer_id]
);
$this->postJson('/api/webhooks/stripe', $payload, [
'Stripe-Signature' => $this->generateStripeSignature($payload)
])
->assertStatus(200);
$user->refresh();
$this->assertNotNull($user->last_payment_at);
}
public function test_invalid_signature_rejected(): void
{
$this->postJson('/api/webhooks/stripe', [], [
'Stripe-Signature' => 'invalid'
])
->assertStatus(403);
}
}
DOTENV SETUP
STRIPE_PUBLIC_KEY=pk_test_...
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_test_...
DEPLOYMENT CHECKLIST
→ Register webhook endpoint in Stripe dashboard: https://dashboard.stripe.com/webhooks
→ Copy webhook secret from Stripe → paste into .env.production
→ Test webhook delivery: Stripe provides test event button
→ Monitor logs: tail -f storage/logs/laravel.log for errors
→ Verify handler is idempotent (can reprocess same event safely)
EXPECTED RESULT
→ Type-safe webhook handler (strict PHP 8.3)
→ All charge events logged and tracked
→ User subscription status synced in real-time
→ 100% test coverage on webhook logicAbout this skill
name: php-pro description: Use when Use when building PHP applications with modern PHP 8.3+ features, Laravel, or Symfony frameworks.
Php Pro
Use when building PHP applications with modern PHP 8.3+ features, Laravel, or Symfony frameworks. Invokes strict typing, PHPStan level 9, async patterns with Swoole, and PSR standards. Creates controllers, configures middleware, generates migrations, writes PHPUnit/Pest tests, defines typed DTOs and value objects, sets up dependency injection, and scaffolds REST/GraphQL APIs. Use when working with Eloquent, Doctrine, Composer, Psalm, ReactPHP, or any PHP API development.
What you get
- Public GitHub repo
- the skills/php-pro folder with SKILL.md and references.
Customize your output
- Fork the repo and extend the skill's reference files for your own stack conventions.
Example output
Activates on a matching request (e.g. building or reviewing Php Pro code) and can chain with other skills in the pack.
Best for
Full-stack developers and engineering teams using Claude Code.
SKILL.md preview
---
name: php-pro
description: Use this skill when building PHP applications with modern PHP 8.3+ features, Laravel, or Symfony, especially where strict typing and static analysis matter.
version: 1.0.0
category: Development / Languages
author: AgentVolt
license: proprietary
tags:
- development
- languages
---
# Php Pro
Builds PHP applications the modern way: strict types everywhere, PHPStan at the highest level, and framework idioms instead of legacy patterns still floating around older PHP codebases.
## When to use
… (sign up to view the full skill)More development skills
View all Development skills →SQL Pro
Optimizes SQL queries, designs database schemas, and troubleshoots performance issues.
Csharp Developer
Use when building C# applications with .NET 8+, ASP.NET Core APIs, or Blazor web apps.
Rust Engineer
Writes, reviews, and debugs idiomatic Rust code with memory safety and zero-cost abstractions.
Cpp Pro
Writes, optimizes, and debugs C++ applications using modern C++20/23 features, template metaprogramming, and high-performance systems techniques.