PHP Pro

Use when building PHP applications with modern PHP 8.3+ features, Laravel, or Symfony frameworks.

Development / Languagesdevelopmentlanguages
by AgentVoltv1.0.0Published 1y ago1 install
Free to sign up · every skill included with AgentVolt Pro

Before & after

Same prompt, same agent — the only difference is the skill.

PromptBuild a Laravel API endpoint to process webhook events from Stripe payments.
Beforegeneric AI agent
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?
Afterwith PHP Pro
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 logic

About 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

SKILL.md
---
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)
Sign up to view, copy, and install the full skill

More development skills

View all Development skills →