Brancher des formulaires · Publié le · Emmanuel Sauvage

Webhook Symfony : envoyer et recevoir des webhooks proprement

Dans une application Symfony, les webhooks interviennent dans deux sens : envoyer un événement à un service externe (notification, e-mail, CRM) et recevoir les événements d’un partenaire (paiement, signature électronique…). Voici des exemples prêts à adapter, et les bonnes pratiques qui évitent les mauvaises surprises en production.

Envoyer un webhook avec HttpClient

Stockez l’URL dans .env.local (WEBHOOKY_URL=…), jamais en dur dans le code ni dans le dépôt.

PHP — service d’envoi
// src/Webhook/WebhookySender.php
namespace App\Webhook;

use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Contracts\HttpClient\HttpClientInterface;

final class WebhookySender
{
    public function __construct(
        private HttpClientInterface $client,
        #[Autowire(env: 'WEBHOOKY_URL')] private string $url,
    ) {}

    public function send(array $payload): void
    {
        $response = $this->client->request('POST', $this->url, [
            'headers' => ['Accept' => 'application/json'],
            'json' => $payload,
            'timeout' => 10,
        ]);

        if ($response->getStatusCode() >= 400) {
            throw new \RuntimeException('Webhook refusé : HTTP '.$response->getStatusCode());
        }
    }
}

Passer en asynchrone avec Messenger

Un appel HTTP synchrone ralentit la réponse et échoue si le service distant est indisponible. Avec Messenger, le contrôleur publie un message, et un worker effectue l’appel avec nouvelles tentatives automatiques.

PHP — Messenger
// src/Message/ContactSubmitted.php
final class ContactSubmitted
{
    public function __construct(public readonly array $payload) {}
}

// src/MessageHandler/ContactSubmittedHandler.php
#[AsMessageHandler]
final class ContactSubmittedHandler
{
    public function __construct(private WebhookySender $sender) {}

    public function __invoke(ContactSubmitted $message): void
    {
        $this->sender->send($message->payload);
    }
}

// Dans le contrôleur
$bus->dispatch(new ContactSubmitted([
    'name' => $form->get('name')->getData(),
    'email' => $form->get('email')->getData(),
    'message' => $form->get('message')->getData(),
]));

Recevoir un webhook et vérifier sa signature

Pour un webhook entrant, vérifiez toujours son authenticité. Beaucoup d’émetteurs signent le corps de la requête avec un secret partagé (HMAC). Le nom de l’en-tête et l’algorithme dépendent du service : reportez-vous à sa documentation.

PHP — contrôleur de réception (exemple générique)
#[Route('/webhook/partner', methods: ['POST'])]
public function __invoke(Request $request): Response
{
    $secret = $_ENV['PARTNER_WEBHOOK_SECRET'];
    $signature = (string) $request->headers->get('X-Signature');
    $expected = hash_hmac('sha256', $request->getContent(), $secret);

    if (!hash_equals($expected, $signature)) {
        return new Response('Signature invalide', Response::HTTP_UNAUTHORIZED);
    }

    $data = $request->toArray();
    // Traitement rapide ou dispatch Messenger, puis accusé de réception
    return new Response('', Response::HTTP_NO_CONTENT);
}

Pour les services courants, regardez aussi le composant symfony/webhook, qui fournit une structure standard (RequestParser, RemoteEvent, consumers).

Bonnes pratiques

Déléguer les intégrations à Webhooky

Plutôt que d’installer un SDK par fournisseur (e-mail, SMS, Slack…), votre application envoie un seul événement à Webhooky, qui exécute les actions configurées et journalise chaque exécution. Changer de fournisseur SMS devient une modification de configuration, pas un déploiement. Voir l’intégration Symfony et la page Webhooky pour les développeurs.

Questions fréquentes

Symfony a-t-il un composant Webhook ?

Oui. Depuis Symfony 6.3, les composants Webhook et RemoteEvent aident à recevoir et à parser des webhooks (avec des parsers fournis pour certains services) et à en envoyer. Pour un besoin simple, un contrôleur et HttpClient suffisent.

Faut-il envoyer les webhooks en asynchrone ?

C’est recommandé : avec Messenger et un transport asynchrone, la requête utilisateur n’attend pas le service distant et les échecs réseau peuvent être retentés.

Comment tester l’envoi ?

Utilisez MockHttpClient dans vos tests unitaires, et un webhook Webhooky en mode brouillon pour vérifier le payload réellement reçu.

Passez de l’idée au premier webhook en quelques minutes

Créez un compte gratuit, générez une URL et connectez votre première action.

Forfait Free · sans carte bancaire · 100 événements inclus

Cette page vous a-t-elle été utile ?