Outbound Webhook Registration
Tells the third party where to push events to. Adapters subclass
WebhookRegistrarBase and override EnsureRegisteredAsync with the
vendor-specific list/match/create logic; the SDK provides the lifecycle
(run-on-startup, log-on-failure default).
Pattern
internal sealed class EnodeWebhookRegistrar(
EnodeApiClient api,
IOptions<EnodeOptions> options,
ILogger<EnodeWebhookRegistrar> logger)
: WebhookRegistrarBase(logger)
{
protected override async Task EnsureRegisteredAsync(CancellationToken ct)
{
var url = options.Value.WebhookPublicUrl;
var secret = options.Value.WebhookSecret;
if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(secret))
return; // not configured; provider runs without push
var existing = await api.ListWebhooksAsync(ct);
var match = existing?["data"]?.AsArray()
.FirstOrDefault(w => w?["url"]?.GetValue<string>() == url);
if (match is not null) return; // already there
await api.CreateWebhookAsync(url, secret, ["*"], ct);
}
}
Register it as a hosted service:
builder.Services.AddHostedService<EnodeWebhookRegistrar>();
Algorithm (intentionally simple)
- List existing webhooks at the third party.
- Match by URL (or your reserved tag).
- If absent → create with our secret + event filter.
- If present → no-op.
The base class's default StartAsync catches and logs any exception
from EnsureRegisteredAsync so a transient upstream failure doesn't
take the whole provider down. If your deployment requires guaranteed
registration, override StartAsync to add bounded retry + health-check
integration.
Drift handling
Out of scope for v1. If you need "patch the existing registration when
the URL or events differ", do that explicitly inside
EnsureRegisteredAsync using your client.