Official PHP SDK for Webhook Platform
2.2.1
2026-03-01 17:59 UTC
Requires
- php: >=8.1
- ext-curl: *
- ext-json: *
Requires (Dev)
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.0
README
Official PHP SDK for Hookflow.
Requirements
- PHP 8.1+
- ext-json
- ext-curl
Installation
composer require webhook-platform/php
Quick Start
<?php use Hookflow\Hookflow; $client = new Hookflow( apiKey: 'wh_live_your_api_key', baseUrl: 'http://localhost:8080' // optional ); // Send an event $event = $client->events->send( type: 'order.completed', data: [ 'orderId' => 'ord_12345', 'amount' => 99.99, 'currency' => 'USD', ] ); echo "Event created: {$event['eventId']}\n"; echo "Deliveries created: {$event['deliveriesCreated']}\n";
API Reference
Events
// Send event with idempotency key $event = $client->events->send( type: 'order.completed', data: ['orderId' => '123'], idempotencyKey: 'unique-key' );
Endpoints
// Create endpoint $endpoint = $client->endpoints->create($projectId, [ 'url' => 'https://api.example.com/webhooks', 'description' => 'Production webhooks', 'enabled' => true, ]); // List endpoints $endpoints = $client->endpoints->list($projectId); // Update endpoint $client->endpoints->update($projectId, $endpointId, [ 'enabled' => false, ]); // Delete endpoint $client->endpoints->delete($projectId, $endpointId); // Rotate secret $updated = $client->endpoints->rotateSecret($projectId, $endpointId); echo "New secret: {$updated['secret']}\n"; // Test endpoint connectivity $result = $client->endpoints->test($projectId, $endpointId); $status = $result['success'] ? 'passed' : 'failed'; echo "Test {$status}: {$result['latencyMs']}ms\n";
Subscriptions
// Subscribe endpoint to an event type $subscription = $client->subscriptions->create($projectId, [ 'endpointId' => $endpoint['id'], 'eventType' => 'order.completed', 'enabled' => true, ]); // List subscriptions $subscriptions = $client->subscriptions->list($projectId); // Update subscription $client->subscriptions->update($projectId, $subscriptionId, [ 'eventType' => 'order.shipped', 'enabled' => true, ]); // Delete subscription $client->subscriptions->delete($projectId, $subscriptionId);
Deliveries
// List deliveries with filters $deliveries = $client->deliveries->list($projectId, [ 'status' => 'FAILED', 'page' => 0, 'size' => 20, ]); echo "Total failed: {$deliveries['totalElements']}\n"; // Get delivery attempts $attempts = $client->deliveries->getAttempts($deliveryId); foreach ($attempts as $attempt) { echo "Attempt {$attempt['attemptNumber']}: {$attempt['httpStatus']} ({$attempt['latencyMs']}ms)\n"; } // Replay failed delivery $client->deliveries->replay($deliveryId);
Incoming Webhooks
Receive, validate, and forward webhooks from third-party providers (Stripe, GitHub, Twilio, etc.).
Incoming Sources
// Create an incoming source with HMAC verification $source = $client->incomingSources->create($projectId, [ 'name' => 'Stripe Webhooks', 'slug' => 'stripe', 'providerType' => 'STRIPE', 'verificationMode' => 'HMAC_GENERIC', 'hmacSecret' => 'whsec_...', 'hmacHeaderName' => 'Stripe-Signature', ]); echo "Ingress URL: {$source['ingressUrl']}\n"; // List sources $sources = $client->incomingSources->list($projectId); // Update source $client->incomingSources->update($projectId, $sourceId, [ 'name' => 'Stripe Production', 'rateLimitPerSecond' => 100, ]); // Delete source $client->incomingSources->delete($projectId, $sourceId);
Incoming Destinations
// Add a forwarding destination $dest = $client->incomingSources->createDestination($projectId, $sourceId, [ 'url' => 'https://your-api.com/webhooks/stripe', 'enabled' => true, 'maxAttempts' => 5, 'timeoutSeconds' => 30, ]); // List destinations $dests = $client->incomingSources->listDestinations($projectId, $sourceId); // Update destination $client->incomingSources->updateDestination($projectId, $sourceId, $destId, [ 'enabled' => false, ]); // Delete destination $client->incomingSources->deleteDestination($projectId, $sourceId, $destId);
Incoming Events
// List incoming events (with optional source filter) $events = $client->incomingEvents->list($projectId, [ 'sourceId' => $sourceId, 'page' => 0, 'size' => 20, ]); // Get event details $event = $client->incomingEvents->get($projectId, $eventId); // Get forward attempts $attempts = $client->incomingEvents->getAttempts($projectId, $eventId); // Replay event to all destinations $result = $client->incomingEvents->replay($projectId, $eventId); echo "Replayed to {$result['destinationsCount']} destinations\n";
Webhook Signature Verification
Verify incoming webhooks in your endpoint:
<?php use Hookflow\Webhook; use Hookflow\Exception\HookflowException; // Get raw request body $payload = file_get_contents('php://input'); $headers = getallheaders(); $secret = getenv('WEBHOOK_SECRET'); try { // Option 1: Just verify Webhook::verifySignature($payload, $headers['X-Signature'] ?? '', $secret); // Option 2: Verify and parse $event = Webhook::constructEvent($payload, $headers, $secret); echo "Received {$event['type']}: " . json_encode($event['data']) . "\n"; // Handle the event switch ($event['type']) { case 'order.completed': handleOrderCompleted($event['data']); break; } http_response_code(200); echo 'OK'; } catch (HookflowException $e) { error_log("Webhook verification failed: {$e->getMessage()}"); http_response_code(400); echo 'Invalid signature'; }
Laravel Example
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Hookflow\Webhook; use Hookflow\Exception\HookflowException; class WebhookController extends Controller { public function handle(Request $request) { $payload = $request->getContent(); $headers = $request->headers->all(); try { $event = Webhook::constructEvent( $payload, $headers, config('services.webhook.secret') ); // Process event... return response('OK', 200); } catch (HookflowException $e) { return response('Invalid signature', 400); } } }
Symfony Example
<?php namespace App\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Hookflow\Webhook; use Hookflow\Exception\HookflowException; class WebhookController { public function handle(Request $request): Response { $payload = $request->getContent(); $headers = $request->headers->all(); try { $event = Webhook::constructEvent( $payload, $headers, $_ENV['WEBHOOK_SECRET'] ); // Process event... return new Response('OK', 200); } catch (HookflowException $e) { return new Response('Invalid signature', 400); } } }
Error Handling
<?php use Hookflow\Exception\HookflowException; use Hookflow\Exception\RateLimitException; use Hookflow\Exception\AuthenticationException; use Hookflow\Exception\ValidationException; try { $client->events->send('test', []); } catch (RateLimitException $e) { // Wait and retry $retryAfterMs = $e->getRetryAfterMs(); echo "Rate limited. Retry after {$retryAfterMs}ms\n"; usleep($retryAfterMs * 1000); } catch (AuthenticationException $e) { echo "Invalid API key\n"; } catch (ValidationException $e) { echo "Validation failed: " . json_encode($e->getFieldErrors()) . "\n"; } catch (HookflowException $e) { echo "Error {$e->getStatusCode()}: {$e->getMessage()}\n"; }
Configuration
$client = new Hookflow( apiKey: 'wh_live_xxx', // Required: Your API key baseUrl: 'https://api.example.com', // Optional: API base URL timeout: 30 // Optional: Request timeout in seconds (default: 30) );
Development
Running Tests
Local (requires PHP 8.1+):
composer install
composer test
Docker:
docker run --rm -v $(pwd):/app -w /app composer:2 sh -c "composer install && composer test"
License
MIT