Webhooks

Contents
Receive events
Verify signatures
Consume
Retries

Receive events

A webhook is a plain POST request sent by an outside service when something happens: a payment completes, a build finishes, a form is submitted. Your job is small: accept the POST on a dedicated route, parse the body, and answer fast with a status code.

use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Attribute\Route; class AcmeWebhookController { #[Route("/webhook/acme", methods: ["POST"])] public function receive(Request $request): JsonResponse { $payload = $request->getContent(); $data = json_decode($payload, true); if (!is_array($data)) { return new JsonResponse(["error" => "Bad JSON"], 400); } return new JsonResponse(["status" => "accepted"]); } }

Verify signatures

Anyone can POST to your URL, so verify the signature header before trusting the body. The sender signs the payload with a shared secret, you recompute the signature with hash_hmac(), and you compare the two with hash_equals(). Reject anything that does not match.

$signature = $request->headers->get("X-Acme-Signature", ""); $expected = hash_hmac("sha256", $payload, $secret); if (!hash_equals($expected, $signature)) { return new JsonResponse(["error" => "Bad signature"], 401); }

Consume

Answer the webhook at once and do the slow work later in a worker. Wrap the event in a message and handle it outside the request, so a slow database never times out the sender and retries stay possible.

use Symfony\Component\RemoteEvent\RemoteEvent; class AcmeEventHandler { public function __invoke(RemoteEvent $event): void { $name = $event->getName(); $payload = $event->getPayload(); // update the local order from $payload } }

Retries

When handling fails, Messenger retries the message with a growing delay instead of dropping it. Three retries with a pause fix most short outages, and only a message that keeps failing lands in the failure queue for review.

messenger: retry_strategy: max_retries 3, delay 1000

Failed webhook handling is retried 3 times, then stored for review

Next: Asset Mapper

Article author: Arthur Isaev

Related articles
Development with PHP
What is Symfony and where it runs
Install Symfony
Your first page
Routes
Controllers
Twig basics
Twig advanced
Doctrine setup
Entities
Migrations
Repositories
Relations
Forms
Validation
Services and DI
JSON controllers
Serializer
Security intro
Users
Login form
Voters
Console commands
Events
Messenger
Mailer
Cache
Sessions
CSRF
Translations
Dotenv and env
Profiler
Testing
Fixtures
Pagination
File uploads
API Platform in one lesson
DQL
Transactions
Migrations advanced
Security advanced
HTTP client
Scheduler
Webhooks
Asset Mapper
Deployment
Performance
Capstone: blog
Capstone: JSON API
Modern Symfony tour
Hero roadmap: the whole course on one page
Banner image

Search this site

Channel @aofeed Chat @aofeedchat

Contacts and cooperation:
I recommend our hosting beget.com
Write to info@aredel.com if you:
1. Want to write an article for our site or translate an article into your native language.
2. Want to place thematically relevant ads on the site.
3. Ads on my site pass maximum censorship. If you see an ad block unsuitable for school-age children, shocking or misleading - please contact us by e-mail
4. Found a mistake, inaccuracy, bug, etc. on the site. ... .......
5. Articles can be shared on social media by clicking a network icon: