Skip to content

Application webhooks (TenancyEngine)

Receive real-time event notifications when tenant lifecycle events occur in your application — tenants created, deleted, entitlements changed, feature flags toggled, and more.

Console: Application workspace → Webhooks (/applications/:id/webhooks)

Requires Applications configure to create, update, or delete endpoints. Read-only access shows existing endpoints.

How it works

When an event occurs (e.g. tenant.created), TenancyEngine queues a signed HTTP POST to every active endpoint configured for that application. Deliveries are retried with exponential back-off (10 s → 1 min → 5 min → 30 min → 2 h → 24 h) for up to 6 attempts. After 6 failures the delivery is dead-lettered.

Adding an endpoint

  1. Click Add endpoint.
  2. Enter the HTTPS URL that will receive events.
  3. Optionally narrow the subscription — enter a comma-separated list of event types (e.g. tenant.created,tenant.deleted) or leave as * to receive all events.
  4. Click Create endpoint — your signing secret is displayed once. Copy it before dismissing.

Verifying signatures

Every delivery includes two headers:

  • X-TE-Event — the event type (e.g. tenant.created)
  • X-TE-Signaturet={unixTimestamp},v1={hexHmac} (Stripe-style)

The signature is HMAC-SHA256(secret, "{timestamp}.{rawBody}") — note the timestamp is prefixed onto the payload before hashing, and verification must use the raw request body string exactly as received (re-serializing a parsed object will not match). Compare using a constant-time comparison to avoid timing attacks.

The easiest way to verify correctly is the WebhookSignatureVerifier helper in TenancyEngine.Sdk (.NET, packages/TenancyEngine.Sdk) or verifyWebhookSignature() in @tenancy-engine/sdk (TypeScript, packages/tenancy-engine-sdk):

csharp
using TenancyEngine.Sdk;

var isValid = WebhookSignatureVerifier.Verify(rawBody, request.Headers["X-TE-Signature"], secret);

If you're hand-rolling verification instead, the equivalent is:

csharp
var parts = signatureHeader.Split(',').Select(p => p.Split('=')).ToDictionary(p => p[0], p => p[1]);
var timestamp = parts["t"];
var receivedSig = parts["v1"];

var expectedSig = Convert.ToHexString(
    HMACSHA256.HashData(Encoding.UTF8.GetBytes(secret), Encoding.UTF8.GetBytes($"{timestamp}.{rawBody}"))
).ToLowerInvariant();

var valid = CryptographicOperations.FixedTimeEquals(
    Convert.FromHexString(expectedSig),
    Convert.FromHexString(receivedSig));

Rotating a secret

Click Rotate secret on an endpoint to invalidate the current signing key and generate a new one. The new secret is shown once — update your receiver before dismissing.

Delivery log

Click Deliveries on an endpoint to see the last 50 delivery attempts — event type, HTTP status code, attempt count, and next retry time.

Disabling an endpoint

Edit an endpoint and uncheck Active to pause deliveries without deleting the endpoint. Reactivate at any time.

TenancyEngine platform documentation