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-Signature — t={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