File: /home/xedaptot/be.naniguide.com/app/Http/Controllers/SendingServerWebhookController.php
<?php
namespace App\Http\Controllers;
use App\Model\SendingServer;
use App\Notifications\Admin\SendingServerWebhookReceived;
use App\SendingServers\Capabilities\ReceivesWebhooks;
use App\Services\Notifications\Notifier;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
/**
* Single skinny entry point for vendor sending-server webhook callbacks
* (bounces, feedback loops, delivery confirmations, handshakes).
*
* Per-instance URL: `/webhook/{driverType}/{serverUid}` so tenant scope
* resolves directly from the URL — no need to look up customer via
* `runtime_message_id` like the legacy DeliveryController did. That
* approach failed for handshake events (Amazon SNS SubscriptionConfirmation)
* which have no msg id.
*
* Flow:
* 1. Resolve server by uid; abort 404 on type mismatch (cross-tenant guard).
* 2. Driver implements ReceivesWebhooks → delegate verify + parse.
* 3. Each parsed WebhookEvent → dispatch via Laravel event bus.
* 4. Listeners (RecordBounce, RecordComplaint, ConfirmSnsSubscription)
* handle side effects asynchronously (ShouldQueue) so the vendor
* sees a fast 200 even when DB / blacklist write is slow.
*/
class SendingServerWebhookController extends Controller
{
public function handle(Request $req, string $driverType, string $serverUid): JsonResponse
{
Log::info('SendingServer webhook received', [
'driver' => $driverType,
'server_uid' => $serverUid,
'body' => $req->getContent(),
'query' => $req->query(),
]);
$server = SendingServer::findByUid($serverUid);
if (is_null($server)) {
abort(404);
}
if ($server->type !== $driverType) {
// URL → server.type mismatch. Avoids cross-tenant accident.
abort(404);
}
$driver = $server->driver();
if (!$driver instanceof ReceivesWebhooks) {
// Driver doesn't accept webhooks. Admin form only renders
// webhookUrl() for drivers that implement the interface, so this
// path should not be reachable in practice.
abort(404);
}
// Per-event notification — debug + monitor every inbound POST.
app(Notifier::class)->dispatch(new SendingServerWebhookReceived(
$server,
$req->getContent()
));
$driver->verifyWebhook($req);
foreach ($driver->parseWebhook($req) as $event) {
event($event);
}
return response()->json(['ok' => true]);
}
}