---
title: "Webhook event catalog"
description: "All eleven notification events, captured Sandbox payloads, field definitions, triggers and safe receiver actions."
slug: "/docs/v1/guides/webhook-events"
section: "Webhooks and integrations"
order: 66
audience: "all"
level: "intermediate"
last_updated: "2026-10-18"
version: "v1"
related: ["/docs/v1/guides/webhooks-overview","/docs/v1/guides/webhook-delivery"]
draft: false
---
Use this catalog to recognize notifications that [KDPika Licensing](/docs/v1/start/glossary#kdpika-licensing) actually emits.

## What you will learn

- Identify the trigger and fields for every event.
- Separate notifications from authoritative [license](/docs/v1/start/glossary#license) validation.
- Handle known gaps without inventing additional event types.

## Prerequisites

- Complete [endpoint setup](/docs/v1/guides/webhooks-overview).
- Implement [signature verification](/docs/v1/guides/verify-webhook-signatures).
- Read [license lifecycle rules](/docs/v1/start/license-lifecycle).

## Envelope shared by every event

| Field | Type | Meaning |
| --- | --- | --- |
| id | string | Event ID beginning evt_; not a UUID contract. Stable across [delivery](/docs/v1/start/glossary#delivery) retries. |
| event | string | Name from this catalog. |
| created_at | string | UTC ISO 8601 notification-creation time, not the delivery attempt time. |
| environment | string | [sandbox](/docs/v1/start/glossary#sandbox) or [live](/docs/v1/start/glossary#live); pin the expected value in your receiver. |
| data | object | Event-specific fields described below. |

The payloads below were captured from real local Sandbox service and maintenance operations on 2026-10-14. All identifiers and values are synthetic. They were queued locally, not delivered by a third-party service. Formatting here is for readability; verify the original incoming HTTP bytes, not this displayed JSON formatting.

Only subscribed active endpoints in the same [organization](/docs/v1/start/glossary#organization) and environment receive ordinary events. A product-scoped endpoint receives its [product](/docs/v1/start/glossary#product); an All products endpoint receives eligible events across that environment. The envelope does not include an organization ID or product ID: your endpoint configuration and your saved license mapping establish that context. Do not assume resource ownership from a supplied license ID alone.

## license.created

A successful license creation commits, then queues this notification. It contains a masked key, never the complete key.

```json
{
  "id": "evt_6db5fc08a2fdc0664fd58904",
  "data": {
    "license": {
      "id": "lic_18d0daa92fddced51a44ed14",
      "status": "active",
      "expires_at": "2026-11-13T17:43:50+00:00",
      "license_key_mask": "TESTDOCS-••••-••••-7CCL"
    }
  },
  "event": "license.created",
  "created_at": "2026-10-14T17:43:50+00:00",
  "environment": "sandbox"
}
```

| Field inside data | Type | Meaning |
| --- | --- | --- |
| `license.id` | string | Created license ID. |
| `license.status` | string | active at creation. |
| `license.expires_at` | string or null | UTC expiration or null for an unbounded license. |
| `license.license_key_mask` | string | Display-only key mask; cannot activate a license. |

Recommended action: Record the license ID in your server-side order mapping. Do not issue another license or attempt to email the mask as a key.


## license.activated

A successful [activation](/docs/v1/start/glossary#activation), including a new [activation token](/docs/v1/start/glossary#activation-token) for an existing installation, queues this notification.

```json
{
  "id": "evt_c8213ce9e0751fcbb2079e82",
  "data": {
    "device": {
      "id": "dev_af3087ec2eeb536a4f4c61a7"
    },
    "license": {
      "id": "lic_18d0daa92fddced51a44ed14",
      "status": "active"
    }
  },
  "event": "license.activated",
  "created_at": "2026-10-14T17:43:50+00:00",
  "environment": "sandbox"
}
```

| Field inside data | Type | Meaning |
| --- | --- | --- |
| `license.id` | string | Activated license ID. |
| `license.status` | string | active at activation. |
| `device.id` | string | Server device-record ID, not the [installation ID](/docs/v1/start/glossary#installation-id) you supplied. |

Recommended action: Update installation activity in your backend. Authorize application [features](/docs/v1/start/glossary#feature) using the validated signed response, not this notification.


## license.deactivated

Client deactivation or a [device](/docs/v1/start/glossary#device) release from the [customer](/docs/v1/start/glossary#customer) portal queues this notification. Deactivating a device from the [developer](/docs/v1/start/glossary#developer) Devices screen does not emit this event.

```json
{
  "id": "evt_47da0040c780d987b4662467",
  "data": {
    "device": {
      "id": "dev_af3087ec2eeb536a4f4c61a7"
    },
    "license": {
      "id": "lic_18d0daa92fddced51a44ed14"
    }
  },
  "event": "license.deactivated",
  "created_at": "2026-10-14T17:43:50+00:00",
  "environment": "sandbox"
}
```

| Field inside data | Type | Meaning |
| --- | --- | --- |
| `license.id` | string | Affected license ID. |
| `device.id` | string | Released server device ID. |
| `source` | string, optional | customer_portal for the portal release path; absent on client deactivation. |

Recommended action: Update your device activity view. Do not infer that every possible device change generates this notification.


## license.suspended

An allowed suspension queues this event. Repeating suspension can create a new event even when the license was already suspended.

```json
{
  "id": "evt_863acadaee69a2a86662efc1",
  "data": {
    "reason": "",
    "license": {
      "id": "lic_18d0daa92fddced51a44ed14",
      "status": "suspended"
    }
  },
  "event": "license.suspended",
  "created_at": "2026-10-14T17:43:50+00:00",
  "environment": "sandbox"
}
```

| Field inside data | Type | Meaning |
| --- | --- | --- |
| `license.id` | string | Affected license ID. |
| `license.status` | string | suspended. |
| `reason` | string or null | Operation reason; can be an empty string. |

Recommended action: Notify your support workflow and refresh your backend license view. Do not run another suspension in response to the same notification.


## license.restored

The suspended-to-active transition queues this event. Setting an already active license to active does not produce license.restored.

```json
{
  "id": "evt_0f5d4d8a4ee2ab283d1822bc",
  "data": {
    "reason": "",
    "license": {
      "id": "lic_18d0daa92fddced51a44ed14",
      "status": "active"
    }
  },
  "event": "license.restored",
  "created_at": "2026-10-14T17:43:50+00:00",
  "environment": "sandbox"
}
```

| Field inside data | Type | Meaning |
| --- | --- | --- |
| `license.id` | string | Restored license ID. |
| `license.status` | string | active. |
| `reason` | string or null | Operation reason; can be an empty string. |

Recommended action: Refresh current license state. Previously revoked activation tokens do not become usable merely because restoration was reported; the application may need to activate again.


## license.revoked

An allowed revocation queues this event. Repeating revocation can create another event ID.

```json
{
  "id": "evt_0d29f4ae752612f98e63f18e",
  "data": {
    "reason": "Synthetic test",
    "license": {
      "id": "lic_18d0daa92fddced51a44ed14",
      "status": "revoked"
    }
  },
  "event": "license.revoked",
  "created_at": "2026-10-14T17:43:50+00:00",
  "environment": "sandbox"
}
```

| Field inside data | Type | Meaning |
| --- | --- | --- |
| `license.id` | string | Revoked license ID. |
| `license.status` | string | revoked. |
| `reason` | string or null | Operation reason; can be an empty string. |

Recommended action: Flag the order/license mapping for support. Revocation is terminal in the current lifecycle; do not promise automatic restoration after a reversed refund or won dispute.


## license.renewed

A successful renewal queues this event. The API adds days to a future expiration, or to the current time if the expiration has passed or is absent.

```json
{
  "id": "evt_25995883974e153db0cf8860",
  "data": {
    "days": 365,
    "license": {
      "id": "lic_18d0daa92fddced51a44ed14",
      "status": "active",
      "expires_at": "2027-11-13T17:43:50+00:00"
    }
  },
  "event": "license.renewed",
  "created_at": "2026-10-14T17:43:50+00:00",
  "environment": "sandbox"
}
```

| Field inside data | Type | Meaning |
| --- | --- | --- |
| `license.id` | string | Renewed license ID. |
| `license.status` | string | State after renewal; a suspended license stays suspended. |
| `license.expires_at` | string | New UTC expiration. |
| `days` | integer | Days added, from 1 through 3650 inclusive. |

Recommended action: Record the resulting expiration and reconcile it with your store ledger. Never call renew again merely because this notification is delivered twice.


## license.expiring

A maintenance run selects active licenses due within seven days and emits reminders when the remaining rounded-up whole days equal seven or one. The reminder marker is license ID plus day count, not expiration revision.

```json
{
  "id": "evt_c237ff96e67f2e36ecb4f0ad",
  "data": {
    "license": {
      "id": "lic_f8f3017881fdbc8307163c79",
      "expires_at": "2026-10-15T17:46:36+00:00",
      "days_remaining": 1
    }
  },
  "event": "license.expiring",
  "created_at": "2026-10-14T17:46:36+00:00",
  "environment": "sandbox"
}
```

| Field inside data | Type | Meaning |
| --- | --- | --- |
| `license.id` | string | License approaching expiration. |
| `license.expires_at` | string | UTC expiration. |
| `license.days_remaining` | integer | Rounded-up reminder bucket: 7 or 1. |

Recommended action: Schedule a customer reminder with your own deduplication and consent policy. After renewal the same reminder bucket can be suppressed by the existing marker; reconcile scheduled communications independently.


## license.expired

A maintenance run persists an elapsed active or suspended license as expired and expires its active activation tokens. A rejected API validation by itself does not guarantee this event or the stored state transition.

```json
{
  "id": "evt_4c8cbd02e77bfc62c54484c4",
  "data": {
    "license": {
      "id": "lic_f8f3017881fdbc8307163c79",
      "status": "expired"
    }
  },
  "event": "license.expired",
  "created_at": "2026-10-14T17:46:36+00:00",
  "environment": "sandbox"
}
```

| Field inside data | Type | Meaning |
| --- | --- | --- |
| `license.id` | string | Expired license ID. |
| `license.status` | string | expired. |

Recommended action: Refresh the license view and offer your own renewal route if supported. A delayed notification does not extend paid access or SDK [offline grace](/docs/v1/start/glossary#offline-grace).


## device.reset

A developer resets all [active devices](/docs/v1/start/glossary#active-devices) for a license. Active device rows are deactivated and active activation tokens are revoked.

```json
{
  "id": "evt_eb4ce6fbdcc85b9e5384e935",
  "data": {
    "license": {
      "id": "lic_18d0daa92fddced51a44ed14"
    }
  },
  "event": "device.reset",
  "created_at": "2026-10-14T17:43:50+00:00",
  "environment": "sandbox"
}
```

| Field inside data | Type | Meaning |
| --- | --- | --- |
| `license.id` | string | License whose devices were reset. |

Recommended action: Tell your application/support workflow that reactivation may be required. This event does not contain a complete device list.


## test.ping

Send test queues a synthetic notification for the selected endpoint even if test.ping is not in its business-event subscription. A disabled endpoint can queue it but does not send it until enabled.

```json
{
  "id": "evt_ffa11b785e0ede73d9e69801",
  "data": {
    "message": "Signed webhook test",
    "webhook_id": "whk_2bf9c0559190a2101b3b9d1b"
  },
  "event": "test.ping",
  "created_at": "2026-10-14T17:46:36+00:00",
  "environment": "sandbox"
}
```

| Field inside data | Type | Meaning |
| --- | --- | --- |
| `message` | string | Signed [webhook](/docs/v1/start/glossary#webhook) test. |
| `webhook_id` | string | Selected endpoint ID. |

Recommended action: Confirm signature verification and durable receipt only. Do not issue, renew or unlock a license.

## Events that do not exist

There is no license.validated, plan.changed, customer.created, email.delivered or store-payment event in this outbound contract. Device deactivation from the developer Devices screen does not emit license.deactivated. A recurring-payment integration receives payment-provider events on your backend, calls the appropriate licensing API, then may receive the corresponding licensing notification. Do not create an event feedback loop.

## Expected result

Every recognized event has an authenticated envelope, an explicit handler and a durable event-ID deduplication record. Unrecognized names are rejected or quarantined without a business action.

## Common mistakes

- Treating a [license key](/docs/v1/start/glossary#license-key) mask as a usable key.
- Assuming all events include customer email, plan, product or a full license object.
- Extending a license again when license.renewed is redelivered.
- Assuming a reminder or expiration notification arrives at an exact wall-clock instant.

## Security notes

Event data can be delayed or arrive out of order. Use [get license](/docs/v1/api/get-license) on your authenticated backend when you need current resource details. Client feature access still requires a valid, verified signed activation/validation response. Treat reason text as untrusted display content and escape it in HTML, notifications and logs.

## Troubleshooting

| Symptom | Cause | Fix |
| --- | --- | --- |
| No customer email in license.created | The contract only sends a key mask and license fields | Use your secured order/customer mapping; do not scrape logs for a key |
| No reminder after a later renewal | Reminder deduplication is not keyed by expiration revision | Reconcile reminders from your own billing schedule |
| No expiry event after rejected validation | Maintenance performs the persistent transition | Check signed/API validity now; do not wait for a notification |
| Several activation events for one installation | Reactivation can rotate a token | Track server device ID and do not count events as new seats |

## Next steps

Implement the [delivery and duplicate-handling rules](/docs/v1/guides/webhook-delivery), then run the [local receiver test](/docs/v1/guides/test-webhooks-locally).

## Related

- [Webhook setup](/docs/v1/guides/webhooks-overview)
- [Signed responses](/docs/v1/security/signed-responses)
- [Idempotency limitations](/docs/v1/api/idempotency)
