webhooks.* procedures), with the endpoint’s vertical set
to vpn.
The console screen at VPN → Webhooks is a thin client over those
procedures: it creates endpoints, renders the subscribable event groups
from the server-side registry, sends signed test pings, and shows the
delivery log with redelivery.
What you can subscribe to
The event-group picker is not hardcoded in the console. It renders fromwebhooks.catalog, which returns the BFF’s webhook registry keyed
by vertical. That means the picker can never offer a token that no
producer emits, and the registry is the authoritative list of vpn.*
event types for your build of the platform.
Read it directly to enumerate the tokens:
When you create or update an endpoint you submit event types, not
group keys — the console expands the checked groups into their
types
before calling webhooks.create. create and update both run
assertKnownEventTypes, so a token that is not in the registry is
rejected as a bad request.
Session lifecycle events
The VPN group set covers the session lifecycle: a session connecting, a session closing, and a connection attempt being rejected. A rejection event is what you subscribe to if you need to see attempts that never became a session, rather than only completed sessions. The exact token for each of these — and any additional session events in your build — comes from thetypes array of the corresponding group in
webhooks.catalog. Subscribe by group rather than by literal token
where you can: group membership is maintained server-side, so an
endpoint subscribed to a whole group keeps working when the group gains
a type.
Credential and access events
The second VPN concern is credentials: TeleQuick emits an event when a VPN credential is revoked. Revocation events are the ones that security tooling normally cares about most, because they are the signal that an issued credential can no longer be used — pair them with the session events above to reconstruct “who could connect, and who did”. As with session events, take the literal tokens from the credential group’stypes in the catalog response.
Event type matching
The dispatcher matches a delivery’s event type against the endpoint’sevent_types array using three forms, and the console applies the same
contract when it decides which group labels to show on an endpoint row:
If you tick every group in the picker, the console collapses the
selection to
['*'] rather than listing the current tokens. That is a
deliberate difference in behaviour: a * endpoint receives future event
types automatically, while an endpoint pinned to explicit tokens does
not.
Create an endpoint and store the signing secret
webhooks.create takes the org, the vertical, the URL, an optional
description, the event types, and the private-egress flag:
The response contains the signing secret in cleartext once. The row
stores it sealed, plus a
signing_secret_preview (the first 12
characters) for display. The console shows the secret in a
copy-once card; if you lose it, your only option is
webhooks.rotateSecret.
Verify the signature
Every POST carries a signature header:v1 is hex(hmac_sha256(secret, "<t>.<body>")). Compute it over
the raw request body, before any JSON parsing or re-serialisation,
and compare with a constant-time equality check. HTTP header names are
case-insensitive, so match the header without regard to case.
Test sends
webhooks.sendTest delivers a signed test.ping to one endpoint
immediately and returns the outcome synchronously:
Use it to prove signature verification works on your side before you
depend on real events. The test delivery is written to the delivery log
like any other.
Delivery log and redelivery
webhooks.deliveries.list is the delivery log. It is org-scoped and
takes optional filters:
Pass
vertical: 'vpn' rather than filtering client-side. A busy org with
heavy voice or streams traffic can fill an unfiltered page entirely with
other verticals’ rows.
Each row carries created_at, event_type, endpoint_id, status,
attempts, last_status_code and last_error. Payloads are
deliberately excluded from the list because they are large — the console
fetches the full payload separately when you open a delivery’s detail
drawer.
webhooks.deliveries.redeliver({ orgId, id }) queues a row again. The
console offers it for rows in delivered or dead status — that is, for
ones that are no longer in flight.
Pause, resume and rotate
webhooks.update covers the operational controls:
status: 'paused'stops deliveries to the endpoint.status: 'active'resumes it and resetsconsecutive_failures, which is how you clear an endpoint the platform auto-paused into thefailingstate. The endpoint list shows that state as afailingpill together with the consecutive-failure count.urlandeventTypescan be changed in place. A new URL is re-validated against the row’s ownallow_private_egressflag, so an endpoint created as public-only cannot be edited into anhttp://target.
webhooks.rotateSecret mints a new secret and seals it in place,
returning the cleartext once. The old secret stops verifying
immediately, so stage the new secret on your receiver first — the
console’s confirmation dialog says the same thing.
Every one of create, update, rotate and delete records an audit entry
(webhooks.endpoint.create, .update, .rotate_secret) against the
endpoint id with the acting user.
On-prem and private-network endpoints
By default an endpoint must behttps:// and must resolve to a
deliverable public target. Tick On-prem / private-network endpoint
(allowPrivateEgress: true) when the receiver is a collector inside your
own network: that flag is what permits RFC1918 targets and http://
URLs. Without it, create rejects an http:// URL with a
BAD_REQUEST.
The flag is a property of the endpoint row, not of the request, and the
console marks such rows with private egress under the URL.
Wiring deliveries into a SIEM
A practical shape for security tooling:- Create one
vertical: 'vpn'endpoint per collector, and put the collector’s name indescription— the console shows the description in place of the secret preview, which makes the endpoint list readable during an incident. - Subscribe to all groups (
*) if the SIEM should see every VPN event including types added later; subscribe to the session and credential groups explicitly if you want a fixed, reviewable set. - Verify the signature over the raw body and reject unsigned or mismatched requests at the collector’s edge.
- Set
allowPrivateEgressif the collector is on-prem. - Monitor the
failingstate anddeaddeliveries. Pollwebhooks.deliveries.listwithstatus: 'dead'andvertical: 'vpn'; the console polls the log every 15 s and surfaces the same rows. - Backfill gaps with
webhooks.deliveries.redeliveronce the collector is healthy again.
Related
- Authentication — API keys for calling the control-plane procedures
- Telemetry — metrics and traces alongside webhook deliveries