Webhooks (TenaBill)
Register outbound HTTPS endpoints that receive signed POST payloads when billing events occur in your merchant account.
Console: TenaBill merchant console → Webhooks (/webhooks)
Create an endpoint
- Enter a public HTTPS URL that accepts
POSTrequests. - Select one or more event types to subscribe to.
- Click Create endpoint.
- Copy the signing secret shown once — TenaBill does not display it again.
Event types
| Event | When it fires |
|---|---|
invoice.paid | An invoice is paid successfully |
invoice.payment_failed | A payment attempt on an invoice fails |
subscription.created | A new subscription is created |
subscription.canceled | A subscription is canceled |
checkout.session.completed | A hosted checkout session completes |
Verify signatures
Each delivery includes headers:
| Header | Value |
|---|---|
X-TenaBill-Event | Event type (e.g. invoice.paid) |
X-TenaBill-Signature | t={unix_timestamp},v1={hex_hmac} |
Compute HMAC-SHA256 over {timestamp}.{raw_json_body} using your signing secret as the key. Compare the hex digest (lowercase) to v1. Reject requests with stale timestamps to limit replay risk.
Example signed payload string: 1700000000.{"invoiceId":"..."}
Signing secret storage (security)
- Secrets are generated with a
whsec_prefix at creation. - TenaBill encrypts secrets at rest using ASP.NET Data Protection (
dp:v1:prefix in the database). The console shows the plaintext secret only once at creation. - You cannot retrieve a lost secret from the console — create a new endpoint and rotate your receiver configuration.
- Disable unused endpoints instead of leaving stale URLs active.
Legacy endpoints created before encryption may still store plaintext secrets; delivery decrypts both formats transparently.
Manage endpoints
- Enable / Disable — disabled endpoints stop receiving events until re-enabled.
- Endpoints cannot be edited in place; create a new endpoint to change URL or events.
Related
- TenaBill API:
POST /api/v1/console/webhooks(merchant bearer token) - Stripe Connect and payment events are separate from merchant webhooks