bitbirddev/trustkey-webhook-bundle
Installation
composer require bitbirddev/trustkey-webhook-bundle
Register the bundle in config/bundles.php:
return [
// ...
BitbirdDev\TrustkeyWebhookBundle\TrustkeyWebhookBundle::class => ['all' => true],
];
Configuration Publish the default config:
php bin/console trustkey-webhook:install
Update config/packages/bitbirddev_trustkey_webhook.yaml with your:
webhook_secret (from Trustkey dashboard)trustkey_public_key (for verification)endpoint (e.g., /api/webhooks/trustkey)Route Definition
Add to config/routes.yaml:
trustkey_webhook:
path: /api/webhooks/trustkey
controller: BitbirdDev\TrustkeyWebhookBundle\Controller\WebhookController::handle
methods: [POST]
First Use Case
Trigger a test webhook from Trustkey’s dashboard. Verify logs (var/log/dev.log) for:
[TRUSTKEY] Webhook received: {event_type}
Event Handling
Extend BitbirdDev\TrustkeyWebhookBundle\Event\TrustkeyWebhookEvent to create custom listeners:
use BitbirdDev\TrustkeyWebhookBundle\Event\TrustkeyWebhookEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class MyWebhookSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
TrustkeyWebhookEvent::WEBHOOK_RECEIVED => 'onWebhookReceived',
];
}
public function onWebhookReceived(TrustkeyWebhookEvent $event)
{
$data = $event->getData();
if ($data['event_type'] === 'user.created') {
// Handle user creation (e.g., sync to your DB)
}
}
}
Register the subscriber in services.yaml:
services:
App\EventSubscriber\MyWebhookSubscriber:
tags: ['kernel.event_subscriber']
Data Validation Use the bundle’s validator to ensure payload integrity:
use BitbirdDev\TrustkeyWebhookBundle\Validator\TrustkeyWebhookValidator;
$validator = new TrustkeyWebhookValidator($secret, $publicKey);
if (!$validator->validate($rawPayload)) {
throw new \RuntimeException('Invalid webhook signature');
}
Async Processing Offload heavy tasks to a queue (e.g., Symfony Messenger or Laravel Queues):
use Symfony\Component\Messenger\MessageBusInterface;
class MyWebhookSubscriber
{
public function __construct(private MessageBusInterface $bus) {}
public function onWebhookReceived(TrustkeyWebhookEvent $event)
{
$this->bus->dispatch(new ProcessTrustkeyEvent($event->getData()));
}
}
Testing Mock webhook payloads in PHPUnit:
$payload = json_encode(['event_type' => 'user.created', 'data' => [...]]);
$response = $this->client->request('POST', '/api/webhooks/trustkey', [], [], [
'HTTP_X_TRUSTKEY_SIGNATURE' => $this->generateSignature($payload),
]);
$this->assertEquals(200, $response->getStatusCode());
Signature Mismatches
403 Forbidden due to incorrect X-Trustkey-Signature.$webhook_secret in config matches Trustkey’s dashboard. Verify the signature algorithm (default: HMAC-SHA256).$computed = hash_hmac('sha256', $payload, $secret);
error_log("Computed: $computed | Received: {$_SERVER['HTTP_X_TRUSTKEY_SIGNATURE']}");
Missing Headers
X-Trustkey-Signature; ensure your middleware/route doesn’t strip headers.trustkey_webhook.yaml:
allowed_headers: ['x-trustkey-signature']
Idempotency
idempotency_key in payload to deduplicate:
if (TrustkeyWebhookEvent::getIdempotencyKey($data) === $seenKey) {
return; // Skip duplicate
}
Rate Limiting
# config/packages/messenger.yaml
framework:
messenger:
transports:
async: '%env(MESSENGER_TRANSPORT_DSN)%'
routing:
'App\Message\ProcessTrustkeyEvent': async
Event Mapping Pre-map Trustkey events to your domain:
$eventMap = [
'user.created' => UserCreatedHandler::class,
'payment.succeeded' => PaymentHandler::class,
];
$handler = new $eventMap[$data['event_type']]();
$handler->handle($data);
Webhook Retries Use exponential backoff for failed processing:
use Symfony\Component\Messenger\Attribute\AsMessage;
#[AsMessage]
class ProcessTrustkeyEvent
{
public function __construct(
public array $data,
public int $retries = 0
) {}
public function __invoke(): void
{
try {
// Process logic
} catch (\Exception $e) {
if ($this->retries < 3) {
throw new RetryException($e, delay: 2 ** $this->retries);
}
throw $e;
}
}
}
Local Testing
Use ngrok to expose a local endpoint for testing:
ngrok http 8000
Configure Trustkey to send webhooks to https://your-ngrok-url.ngrok.io/api/webhooks/trustkey.
Logging Enhance logging with structured data:
use Psr\Log\LoggerInterface;
class MyWebhookSubscriber
{
public function __construct(private LoggerInterface $logger) {}
public function onWebhookReceived(TrustkeyWebhookEvent $event)
{
$this->logger->info('Trustkey Webhook', [
'event' => $event->getData()['event_type'],
'metadata' => $event->getData()['metadata'] ?? [],
'context' => ['ip' => $_SERVER['REMOTE_ADDR']],
]);
}
}
Security
firewalls to add CSRF protection (if applicable):
# config/packages/security.yaml
firewalls:
main:
pattern: ^/api/webhooks/trustkey
stateless: true
csrf_protection: false # Disable if using signature validation
How can I help you explore Laravel packages today?