Webhooks
Updated 6 November 2026
Webhooks
Webhooks are how TechWolf tells an organisation's systems that something has changed, the moment it changes. TechWolf sends a notification to an endpoint the organisation exposes. The notification says what changed, for example which employee's skill profile was updated, so the receiving system knows what to act on and can fetch the new data.
That is what lets an organisation build real-time integrations and automations on TechWolf data: each change triggers the work, and only the data that changed is revisited.
Key attributes
Event types Notifications cover changes to employee, job, and course skill profiles, with validated profiles and newly suggested skills carried as separate event types, and changes to the skill vocabulary and the organisation's taxonomy. A consumer subscribes only to the event types it needs, and every registered endpoint also answers a health-check event that TechWolf uses to confirm the endpoint is live. |
Thin events Each notification signals that something changed and for which entity, and the changed data itself always comes from the SkillEngine API. That keeps the API the single authoritative source: since a notification can arrive more than once and out of order, a copy of the data travelling with it could already be out of date on arrival. |
Delivery One notification is sent per request, and is delivered at least once, without a guaranteed order. A delivery that fails because of a temporary problem is retried, with increasing backoff time between retries. Consumers deduplicate by event identifier and process each event idempotently, so a repeated notification has the same effect as a single one. |
Security Every notification carries an Ed25519 signature and a timestamp, which the consumer verifies before acting on it. Optionally, OAuth 2.0 or a key in an HTTP header can be used to authenticate with the organisation's endpoint. |
How it works
The organisation exposes an HTTPS endpoint and registers it with TechWolf, together with the event types it wants to receive. When a subscribed change happens, TechWolf sends the notification in the CloudEvents format; the consumer verifies it, acknowledges receipt, and fetches the changed resource from the SkillEngine API.
Webhooks make changes visible in near real time. A scheduled reconciliation alongside them is what keeps two systems aligned: it re-reads both sides, settles any difference, and closes the gap left when an endpoint was unavailable for the whole of a delivery's retries. A notification signals that something changed, not what the change was. The current state, and the history behind a profile, come from the SkillEngine API.
Signed-in customers can find how to set up a webhook, verify its signature, handle deliveries and re-send events in the guides listed under Related pages.
Webhook status
A webhook is Active, Paused or Disabled. A new webhook starts paused, and receives events once it is enabled in the Console, which first sends it a health check that has to pass. An organisation pauses a webhook to stop its deliveries for a while, for example during maintenance of its endpoint, and enables it again afterwards.
Delivery problems are handled so that none goes unnoticed and no event is lost for good. A temporary problem is retried. A problem that retrying cannot fix makes TechWolf disable the webhook and tell the organisation, and the events of that time stay available to be sent again once the endpoint is fixed. These are the responses that point to such a problem, because they come from the webhook's configuration:
| Request to | Responses that count |
|---|---|
| The endpoint | A redirect (3XX), 400, 401, 403, 404 or 405, or a connection that cannot be made |
| The OAuth2 token endpoint | 401, 403, 404 or 405, or a connection that fails for a reason other than a timeout |
A temporary problem, such as a 5XX status, a 408, a 429 or an endpoint that is too slow to respond, never disables a webhook. TechWolf disables it once at least five events failed with one of the responses above, with no successful delivery since, and the first of those failures is at least 24 hours old. Note that the hourly health check counts too, so a webhook with few events is also disabled when its endpoint stops accepting requests.
When TechWolf disables a webhook, the organisation's integration managers in the Console are notified by email and in the Console. The webhook's page says which response the endpoint returned and what to check. While the webhook is disabled, its events are not sent. After the cause is fixed, the webhook is re-enabled in the Console, which again sends a health check first, and the events it missed are re-sent from its page.
TechWolf keeps every event of a webhook, with its delivery attempts, for 30 days. In that time the events are listed on the webhook's page in the Console, and any of them can be sent again.
Event types
Every notification has an event type, which says what changed, and a data object, which holds the tenant and resource identifiers needed to fetch that change from the SkillEngine API. The specifications below are grouped by entity, and each one gives when the event is emitted, its expected frequency, the suggested consumer action and the payload format of the latest version of the event. You only need to support the event types you consume; only the health check event is required for all consumers.
The skill events and the taxonomy event differ in granularity. The three skill events (created, updated and deleted) fire for one skill at a time and point you at that skill's endpoint. The taxonomy event fires for the tenant's taxonomy as a whole and points you at the taxonomy changes export, where each event corresponds to a single operation (identified by external_id).
The expected frequency is expressed per affected entity (for example per employee or per job), so this is not the total number of webhooks per day. Note that this is only a high-level indication; the actual frequency depends on the activity levels in the SkillEngine API and in any linked system, such as the TechWolf Skill Assistant, the TechWolf Console or external platforms with integrations. As for when the events are emitted, TechWolf delivers an event at least once for each of the triggers specified for it, and may also send it in other situations.
TechWolf may add new fields to existing webhook versions, for example extra fields in the data object. Your endpoint should tolerate unknown fields and not break when new ones are sent.
The event types are:
- Employee: Skill profile updated, Suggested skill profile updated
- Job: Skill profile updated, Suggested skill profile updated
- Course: Skill profile updated
- Skill vocabulary: Skill created, Skill updated, Skill deleted
- Taxonomy: Taxonomy updated
- Health check: Health check
Employee skill profile updated
| Detail | Specification |
|---|---|
| Emitted when | Inference completes for the employee (including the initial inference after the employee is created, which may produce an empty skill profile), skills are validated or rejected, or the skill attributes (for example proficiency) of existing validated skills are updated. |
| Expected frequency | Daily (per employee) |
| Suggested action | Retrieve the employee skill profile from the SkillEngine API (GET /employees/{external_id}/skill_profile) and propagate changes. |
Note that an empty skill profile ("skills": []) is a valid state: it means inference has run for the employee, but no skills could be inferred (yet). Treat these webhooks like any other and fetch the skill profile by external_id, without special-casing them. As soon as skills are inferred or validated, they will flow through on a subsequent webhook.
Event type: ai.techwolf.employee.skill_profile.updated.v1
| Field | Description |
|---|---|
tenant_name | Identifies the tenant. |
external_id | The employee's external ID; use in the path when calling the API. |
{ "specversion": "1.0", "type": "ai.techwolf.employee.skill_profile.updated.v1", "source": "https://{tenant}.{region}.techwolf.ai/employees/{employee_external_id}/skill_profile", "id": "{event_uuid}", "time": "2024-01-15T10:30:00Z", "data": { "tenant_name": "{tenant}", "external_id": "{employee_external_id}" } }
Employee suggested skill profile updated
| Detail | Specification |
|---|---|
| Emitted when | The set of suggested (inferred, not yet validated or rejected) skills for the employee changes. |
| Suggested action | Retrieve the employee skill profile from the SkillEngine API (GET /employees/{external_id}/skill_profile) and read the skills with validation_state suggested. |
Note that this event covers suggested skills only (inferred, not yet validated or rejected). It is separate from Employee skill profile updated, which covers changes to the validated skill profile.
Event type: ai.techwolf.employee.skill_profile.suggested_updated.v1
| Field | Description |
|---|---|
tenant_name | Identifies the tenant. |
external_id | The employee's external ID; use in the path when calling the API. |
{ "specversion": "1.0", "type": "ai.techwolf.employee.skill_profile.suggested_updated.v1", "source": "https://{tenant}.{region}.techwolf.ai/employees/{employee_external_id}/skill_profile", "id": "{event_uuid}", "time": "2024-01-15T10:30:00Z", "data": { "tenant_name": "{tenant}", "external_id": "{employee_external_id}" } }
Job skill profile updated
| Detail | Specification |
|---|---|
| Emitted when | Inference completes for the job (including the initial inference after the job is created, which may produce an empty skill profile), skills are validated or rejected, or the skill attributes (for example proficiency, criticality) of existing validated skills are updated. |
| Expected frequency | Weekly to monthly (per job) |
| Suggested action | Retrieve the job skill profile from the SkillEngine API (GET /job_architecture/jobs/{job_external_id}/skill_profile) and propagate changes. |
Note that an empty skill profile ("skills": []) is a valid state: it means inference has run for the job, but no skills could be inferred (yet). Treat these webhooks like any other and fetch the skill profile by external_id, without special-casing them. As soon as skills are inferred or validated, they will flow through on a subsequent webhook.
Event type: ai.techwolf.job_architecture.job.skill_profile.updated.v1
| Field | Description |
|---|---|
tenant_name | Identifies the tenant. |
external_id | The job's external ID; use in the path when calling the API. |
{ "specversion": "1.0", "type": "ai.techwolf.job_architecture.job.skill_profile.updated.v1", "source": "https://{tenant}.{region}.techwolf.ai/job_architecture/jobs/{job_external_id}/skill_profile", "id": "{event_uuid}", "time": "2024-01-15T10:30:00Z", "data": { "tenant_name": "{tenant}", "external_id": "{job_external_id}" } }
Job suggested skill profile updated
| Detail | Specification |
|---|---|
| Emitted when | The set of suggested (inferred, not yet validated or rejected) skills for the job changes. |
| Suggested action | Retrieve the job skill profile from the SkillEngine API (GET /job_architecture/jobs/{job_external_id}/skill_profile) and read the skills with validation_state suggested. |
Note that this event covers suggested skills only (inferred, not yet validated or rejected). It is separate from Job skill profile updated, which covers changes to the validated skill profile.
Event type: ai.techwolf.job_architecture.job.skill_profile.suggested_updated.v1
| Field | Description |
|---|---|
tenant_name | Identifies the tenant. |
external_id | The job's external ID; use in the path when calling the API. |
{ "specversion": "1.0", "type": "ai.techwolf.job_architecture.job.skill_profile.suggested_updated.v1", "source": "https://{tenant}.{region}.techwolf.ai/job_architecture/jobs/{job_external_id}/skill_profile", "id": "{event_uuid}", "time": "2024-01-15T10:30:00Z", "data": { "tenant_name": "{tenant}", "external_id": "{job_external_id}" } }
Course skill profile updated
| Detail | Specification |
|---|---|
| Emitted when | Skills are added to or removed from the course skill profile. |
| Expected frequency | Monthly (per course) |
| Suggested action | Retrieve the course skill profile from the SkillEngine API (GET /courses/{external_id}/skill_profile) and propagate changes. |
Event type: ai.techwolf.course.skill_profile.updated.v1
| Field | Description |
|---|---|
tenant_name | Identifies the tenant. |
external_id | The course's external ID; use in the path when calling the API. |
{ "specversion": "1.0", "type": "ai.techwolf.course.skill_profile.updated.v1", "source": "https://{tenant}.{region}.techwolf.ai/courses/{course_external_id}/skill_profile", "id": "{event_uuid}", "time": "2024-01-15T10:30:00Z", "data": { "tenant_name": "{tenant}", "external_id": "{course_external_id}" } }
Skill created
| Detail | Specification |
|---|---|
| Scope | A single skill in the vocabulary (a vocabulary skill or a custom skill). |
| Emitted when | New skills are added to the TechWolf vocabulary, or custom skills are created. |
| Expected frequency | Monthly to quarterly (per skill) |
| Suggested action | Retrieve the new skill from the SkillEngine API (GET /taxonomy/skills/{skill_id}) and propagate changes. |
Event type: ai.techwolf.taxonomy.skill.created.v1
| Field | Description |
|---|---|
tenant_name | Identifies the tenant. |
external_id | Identifies the skill; use in the path when calling the API. |
external_vendor | Indicates the skill's vendor; pass as the vendor query parameter when fetching the skill from the API. |
{ "specversion": "1.0", "type": "ai.techwolf.taxonomy.skill.created.v1", "source": "https://{tenant}.{region}.techwolf.ai/taxonomy/skills/{skill_external_id}", "id": "{event_uuid}", "time": "2024-01-15T10:30:00Z", "data": { "tenant_name": "{tenant}", "external_id": "{skill_external_id}", "external_vendor": "{skill_external_vendor}" } }
Skill updated
| Detail | Specification |
|---|---|
| Scope | A single skill in the vocabulary (a vocabulary skill or a custom skill). |
| Emitted when | Skills are updated in the TechWolf vocabulary, or custom skills are updated. |
| Expected frequency | Monthly to quarterly (per skill) |
| Suggested action | Retrieve the updated skill from the SkillEngine API (GET /taxonomy/skills/{skill_id}) and propagate changes. |
Event type: ai.techwolf.taxonomy.skill.updated.v1
| Field | Description |
|---|---|
tenant_name | Identifies the tenant. |
external_id | Identifies the skill; use in the path when calling the API. |
external_vendor | Indicates the skill's vendor; pass as the vendor query parameter when fetching the skill from the API. |
{ "specversion": "1.0", "type": "ai.techwolf.taxonomy.skill.updated.v1", "source": "https://{tenant}.{region}.techwolf.ai/taxonomy/skills/{skill_external_id}", "id": "{event_uuid}", "time": "2024-01-15T10:30:00Z", "data": { "tenant_name": "{tenant}", "external_id": "{skill_external_id}", "external_vendor": "{skill_external_vendor}" } }
Skill deleted
| Detail | Specification |
|---|---|
| Scope | A single skill in the vocabulary (a vocabulary skill or a custom skill). |
| Emitted when | Skills are removed from the TechWolf vocabulary, or custom skills are deleted. |
| Expected frequency | Monthly to quarterly (per skill) |
| Suggested action | The skill will no longer be available from the SkillEngine API (404). To handle out-of-order events, you can verify with GET /taxonomy/skills/{skill_id} and propagate the deletion. |
Event type: ai.techwolf.taxonomy.skill.deleted.v1
| Field | Description |
|---|---|
tenant_name | Identifies the tenant. |
external_id | Identifies the skill; use in the path when calling the API. |
external_vendor | Indicates the skill's vendor; use as the vendor query parameter when verifying via the API. |
{ "specversion": "1.0", "type": "ai.techwolf.taxonomy.skill.deleted.v1", "source": "https://{tenant}.{region}.techwolf.ai/taxonomy/skills/{skill_external_id}", "id": "{event_uuid}", "time": "2024-01-15T10:30:00Z", "data": { "tenant_name": "{tenant}", "external_id": "{skill_external_id}", "external_vendor": "{skill_external_vendor}" } }
Taxonomy updated
| Detail | Specification |
|---|---|
| Scope | The tenant's taxonomy as a whole, covering structural and vocabulary operations. Each event corresponds to one operation, identified by external_id. |
| Emitted when | The tenant's skills taxonomy changes or the vocabulary is updated. |
| Expected frequency | Weekly (per tenant) |
| Suggested action | Retrieve taxonomy changes from the SkillEngine API (POST /taxonomy/changes). Filter by operation_type to get only the kind of change you need, and use external_id from the event to request the specific change that triggered the webhook. |
Note that a single vocabulary update can send many of these events at once, as every skill it adds, renames, changes the description of or removes results in its own event. The expected frequency above therefore says little about the peak load on your endpoint. Deliveries that still fail after all retries are lost, so make sure your endpoint can handle such a burst, and run a periodic reconciliation alongside the webhooks to catch anything that was missed.
Event type: ai.techwolf.taxonomy.updated.v1
| Field | Description |
|---|---|
tenant_name | Identifies the tenant. |
operation_type | Type of change; use to filter when calling the taxonomy or vocabulary export API. See POST /taxonomy/changes for the full list of values. |
external_id | Identifies the specific change; pass when calling the taxonomy export API to fetch only that change. |
{ "specversion": "1.0", "type": "ai.techwolf.taxonomy.updated.v1", "source": "https://{tenant}.{region}.techwolf.ai/taxonomy/export", "id": "{event_uuid}", "time": "2024-01-15T10:30:00Z", "data": { "tenant_name": "{tenant}", "operation_type": "{operation_type}", "external_id": "{operation_external_id}" } }
Health check
This event is required for all endpoints. The requests are signed like any other webhook request, and an hourly health check that your endpoint rejects counts towards disabling the webhook, like any other delivery.
| Detail | Specification |
|---|---|
| Emitted when | TechWolf checks that your webhook consumer is live: every hour for an active webhook, and when a test is sent or the webhook is enabled in the Console. |
| Expected frequency | Hourly (per active webhook) |
| Suggested action | Respond with a 2XX status code. No business logic is required. |
Event type: ai.techwolf.health_check
{ "specversion": "1.0", "type": "ai.techwolf.health_check", "source": "https://{tenant}.{region}.techwolf.ai/", "id": "{event_uuid}", "time": "2024-01-15T10:30:00Z", "data": {} }
Prerequisites
Webhooks are part of TechWolf's output integrations. They require an HTTPS endpoint operated by the organisation and SkillEngine API access to fetch the changed resources. TechWolf sends webhooks from a fixed set of IP addresses per region. If the organisation's network filters inbound traffic, the organisation must allowlist the addresses for its region.
Availability
- Console: webhooks are configured, tested, paused and enabled in the Console, as an outbound integration in the Integration Manager. The Console also lists each webhook's events of the last 30 days, and sends them again on request.