@php /** @var \App\Models\Webhook $hook */ /** @var \Illuminate\Support\Collection $deliveries */ $deliveries = $deliveries ?? collect(); $analytics = $analytics ?? [ 'total7d' => 0, 'success_pct' => null, 'p95_ms' => null, 'retries' => 0, 'failed' => 0, 'codes' => [], 'days' => collect(), ]; $hookName = $hook?->name ?: 'Webhook #' . optional($hook)->id; $hookUrl = $hook?->webhook_url ?: '—'; $events = collect($hook?->events ?? []); $isActive = $hook?->state_label === 'active'; $isFailing = $hook?->state_label === 'failing'; // Pretty status pill for an HTTP code. $codePill = function (?int $c) { if ($c === null) { return ['cls' => 'bg-paper-100 text-ink-500', 'label' => '—']; } if ($c >= 200 && $c < 300) { return ['cls' => 'bg-wa-mint text-wa-deep', 'label' => $c . ' OK']; } if ($c >= 300 && $c < 400) { return ['cls' => 'bg-paper-100 text-ink-700', 'label' => (string) $c]; } if ($c >= 400 && $c < 500) { return ['cls' => 'bg-accent-amber/20 text-[#7B5A14]', 'label' => (string) $c]; } return ['cls' => 'bg-accent-coral/15 text-[#A1431F]', 'label' => (string) $c]; }; $fmtLatency = function (?int $ms) { if ($ms === null) { return '—'; } return $ms < 1000 ? $ms . 'ms' : number_format($ms / 1000, 1) . 's'; }; @endphp
{{ __('Webhooks / Endpoint') }}
{{ __('Webhook') }} {{ __('analytics') }}
{{ __('Edit') }}
icon_color) style="background:{{ $hook->icon_color }}20;color:{{ $hook->icon_color }}" @endif>
Endpoint · {{ $hook->environment ?: 'Production' }}

{{ $hookName }}

{{ $hookUrl }}
{{ $hook->http_method ?: 'POST' }} {{ $events->count() }} {{ $events->count() === 1 ? 'event' : 'events' }} @if ($hook->secret) {{ __('HMAC signed') }} @endif @if ($isActive) Active @elseif ($isFailing) Failing @else Paused @endif
{{ __('Events') }}7d
{{ number_format($analytics['total7d']) }}{{ __('fired') }}
{{ __('Success') }} 2xx rate
{{ $analytics['success_pct'] !== null ? $analytics['success_pct'] . '%' : '—' }}{{ $analytics['total7d'] ? 'last 7d' : 'no data' }}
{{ __('Latency') }} {{ __('target 500ms') }}
{{ $analytics['p95_ms'] !== null ? $fmtLatency($analytics['p95_ms']) : '—' }}p95
{{ __('Retries') }}{{ $analytics['total7d'] ? round(($analytics['retries'] / max($analytics['total7d'], 1)) * 100, 1) . '%' : '—' }}
{{ number_format($analytics['retries']) }}{{ __('last 7d') }}
{{ __('Failed') }}{{ $analytics['total7d'] ? round(($analytics['failed'] / max($analytics['total7d'], 1)) * 100, 1) . '%' : '—' }}
{{ number_format($analytics['failed']) }}{{ __('non-2xx') }}
{{ __('Activity') }}

{{ __('Success vs failure (7d)') }}

values()->all())'>
{{ __('By status code') }}

{{ __('Response codes') }}

($c['count'] ?? 0) > 0)))'>
@forelse ($analytics['codes'] as $c) @if ($c['count'] > 0)
{{ $c['label'] }} {{ number_format($c['count']) }}
@endif @empty @include('user.partials.empty-state', [ 'message' => 'No deliveries found. Deliveries will appear here after this endpoint receives events.', ]) @endforelse
{{ __('Deliveries') }}

{{ __('Recent firings') }}

@forelse ($deliveries as $d) @php $cp = $codePill($d->status_code); $is2xx = $d->status_code !== null && $d->status_code >= 200 && $d->status_code < 300; $latencyEl = $d->status_code !== null && $d->status_code >= 400 && $d->error ? $d->error : $fmtLatency($d->latency_ms); // Embed the full delivery so the JS can swap the payload pane // without an extra fetch. Strings only — pre-decrypted view // models keep tinker-clean encryption-at-rest semantics. $payload = (string) ($d->payload ?? ''); $response = (string) ($d->response_body ?? ''); @endphp @empty @endforelse
{{ __('Time') }} {{ __('Event') }} {{ __('Code') }} {{ __('Latency') }} {{ __('Attempt') }} {{ __('View') }}
{{ optional($d->fired_at)->format('M j H:i:s') }} {{ $d->event_name ?: '—' }} {{ $cp['label'] }} {{ $latencyEl }} {{ $d->is_retry ? 'retry' : 'first' }}
@include('user.partials.empty-state', [ 'message' => 'No deliveries found. Once your endpoint receives events, they will appear here.', ])
{{ __('Showing') }} {{ $deliveries->isEmpty() ? '0' : '1–' . $deliveries->count() }} of {{ number_format($analytics['total7d']) }} in last 7 days
{{ __('Health checks') }}

{{ __('Things to watch') }}

{{ __('Up for 14 days straight') }}
{{ __('No retries needed since the last deploy. Solid.') }}
{{ __('Latency well under target') }}
218ms p95 vs 500ms target — feels instant.
12 retries last week
{{ __('All within retry budget. Most recovered on attempt 2 — investigate spike at 13:54.') }}
4 unrecovered failures
{{ __('All 404 — endpoint may have changed. Check route / API version.') }}
{{ __('Signature') }}
{{ __('HMAC verification') }}
const sig = req.headers['x-wadesk-signature'];
const expected = hmacSHA256(secret, raw);
if (!safeEqual(sig, expected)) reject();
{{ __('Edit endpoint') }}