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