Skip to main content

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)

  1. List existing webhooks at the third party.
  2. Match by URL (or your reserved tag).
  3. If absent → create with our secret + event filter.
  4. 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.

See also