Event types: organization, accounts, billing
The subscribable event types from organization, storage connections, access, accounts and delegated access, sessions, billing, and joining, with their core payload.
12 minute readWebhooksUpdated: 10/25/2026
On this page
Before you start
- For
- Anyone who chooses the events of an endpoint or reads the body of a delivery.
- Prerequisite
- None for reading. To subscribe, an endpoint under Settings › Organization › Webhooks.
The subscribable event types from organization, storage connections, access, accounts, sessions, billing, and joining, for reference when you create an endpoint or interpret a delivery.
How to read the tables
- Event type is the string you subscribe to on the endpoint. It arrives in the header
X-Event-Typewith every delivery. Instead of single types you can also subscribe to a whole area (composition.*) or to everything with*. There are no other forms, and the server rejects anything else, see Fetch the event catalog through the API. - Core payload names two to four of the most important fields that are in the body of the delivery. It is an excerpt. Each area determines the full shape, which can carry more fields. The time, the event identifier, and the trigger do not travel in the body.
- When it is raised is a short phrase for context, not a statement about frequency.
Under Subscribed events, the portal offers exactly the types of this page and of the page Event types: content, programs, devices, apps for selection, the same list that GET /v1/webhooks/event-types returns. Everything else cannot be subscribed to, and creating an endpoint rejects it. Which types these are is described under What never arrives. Only what is raised in the context of your organization is delivered.
The event types
Organization
Lifecycle of the organization, brand, custom portal address, and company sign-in. tenancy.tenant.suspended and .deleted are the triggers that other areas follow.
| Event type | Core payload | When it is raised |
|---|---|---|
tenancy.tenant.created |
tenantId, slug, displayName |
An organization was created. |
tenancy.tenant.updated |
tenantId, changedFields |
The master data of the organization was changed. |
tenancy.tenant.suspended |
tenantId, reason, suspendedById, deletionDueAt |
The organization was suspended, and deletionDueAt gives the deletion date. |
tenancy.tenant.reactivated |
tenantId, reactivatedById |
A suspension was lifted. |
tenancy.tenant.frozen |
tenantId, reason, frozenById |
The organization was frozen. |
tenancy.tenant.unfrozen |
tenantId, unfrozenById |
The freeze was lifted. |
tenancy.tenant.deletion-warned |
tenantId, deletesAt, daysLeft |
Warning before deletion. daysLeft gives the remaining days. |
tenancy.tenant.deleted |
tenantId, slug, deletedById |
The organization was deleted. |
tenancy.branding.updated |
tenantId, changedFields |
The brand (logo, colors) was changed. |
tenancy.custom-domain.verified |
tenantId, customDomain |
A custom portal address was verified. |
tenancy.custom-domain.removed |
tenantId, domain |
A custom portal address was removed. |
tenancy.sso.configured |
tenantId, providerId, protocol, status |
The company sign-in was set up or changed. |
tenancy.sso.disabled |
tenantId, providerId, protocol |
The company sign-in was switched off. |
tenancy.sso.domain-changed |
tenantId, providerId, domain, status |
The domain of the company sign-in was changed. |
tenancy.sso.enforcement-changed |
tenantId, providerId, enforce, breakGlassUserIds |
Enforcement of the company sign-in was turned on or off. |
tenancy.sso.break-glass-used |
tenantId, providerId, userId, email |
A break-glass account signed in, bypassing the company sign-in. |
Storage connections
Standing authorizations for third-party storage accounts. broken tells you since when no new files have arrived.
| Event type | Core payload | When it is raised |
|---|---|---|
cloud-connections.connection.connected |
connectionId, provider, accountLabel, repaired |
A storage account was connected, and repaired distinguishes the first connection from a repair. |
cloud-connections.connection.disconnected |
connectionId, provider, revocationAcknowledged |
The connection was disconnected. |
cloud-connections.connection.broken |
connectionId, provider, reason |
The authorization no longer holds. From here on, syncing stops. It cannot be triggered from the portal. |
Access: roles and grants
Roles of the organization and grants on individual resources.
| Event type | Core payload | When it is raised |
|---|---|---|
access.role.created |
roleId, tenantId, name, permissions |
A role was created. |
access.role.updated |
roleId, changedFields, newPermissions, newVersion |
The permissions or the name of a role were changed. |
access.role.deleted |
roleId, tenantId, requesterId |
A role was deleted. |
access.grant.created |
grantId, userId, resourceType, resourceId |
A grant on a single resource was issued. |
access.grant.revoked |
grantId, userId, resourceType, resourceId |
A grant was revoked. |
access.grant.expired |
grantId, userId, resourceId, expiredAt |
A time-limited grant has expired. |
access.permission-catalog.rebuilt |
tenantId, trigger, entryCount |
The permission catalog of the organization was rebuilt, and trigger gives the reason. |
Accounts, keys, and device identities
User accounts, API keys, SCIM tokens, applications with delegated access, and the identity of devices. The accounts and keys of the operator do not belong here, they cannot be subscribed to (see What never arrives).
| Event type | Core payload | When it is raised |
|---|---|---|
identity.user.created |
userId, tenantId, email, initialRoles |
A user account was created. |
identity.user.updated |
userId, changedFields, newValues |
Profile data of an account was changed. |
identity.user.role.changed |
userId, previousRoles, newRoles |
The roles of an account were changed. |
identity.user.suspended |
userId, reason, cascadeSource |
An account was suspended. |
identity.user.deleted |
userId, deletedById, pseudonymizationJobId |
An account was deleted, and pseudonymization was triggered. |
identity.user.pseudonymized |
userId, pseudonymId, entriesReplaced |
Entries with personal data in a deleted account were replaced. |
identity.user.mfa.enabled |
userId, tenantId, enabledAt |
The second factor was set up. |
identity.user.mfa.disabled |
userId, tenantId, disabledAt |
The second factor was removed. |
identity.user.mfa.recovery-codes.regenerated |
userId, tenantId, regeneratedAt |
New recovery codes were generated. |
identity.user.password-changed |
userId, via, changedAt |
The password was changed, and via gives the route. |
identity.api-key.minted |
apiKeyId, name, keyPrefix, scope |
An API key was created. |
identity.api-key.revoked |
apiKeyId, revokedById, reason |
An API key was revoked. |
identity.scim-token.minted |
scimTokenId, tenantId, tokenPrefix, createdById |
A SCIM token for the personnel directory of the organization was issued. |
identity.scim-token.revoked |
scimTokenId, tenantId, revokedById, reason |
A SCIM token was revoked. Provisioning from the personnel directory stops. |
identity.oauth.client.registered |
clientId, name, redirectUris, registeredIp |
A third-party application registered for delegated access. It gains nothing until a person consents. |
identity.oauth.client.blocked |
clientId, name, blockedById, reason, revokedGrants |
Platform operations blocked an application, and revokedGrants counts the grants that expired with it. |
identity.oauth.client.unblocked |
clientId, name, unblockedById |
The block on an application was lifted. The grants that expired do not come back. |
identity.oauth.grant.granted |
clientId, clientName, tenantId, userId, scopes |
An account delegated rights to an application, scoped to this organization. |
identity.oauth.grant.denied |
clientId, clientName, tenantId, userId, requestedScopes |
An account declined the request of an application, and no access was created. |
identity.oauth.token.issued |
tokenId, clientId, userId, scopes, rotated |
An application received an access token and a refresh token, after a consent or as a rotation (rotated). |
identity.oauth.token.revoked |
clientId, userId, revokedGrants, reason |
Grants of an application were invalidated, and reason gives the cause. |
identity.device.registered |
deviceId, certFingerprint, hardwareInfo |
A device registered with the platform for the first time. |
identity.device.cert.rotated |
deviceId, oldFingerprint, newFingerprint |
The certificate of a device was renewed. |
identity.device.reconnected |
deviceId, reconnectedById, previousHardwareSerial |
A web display was moved to another browser. It stays paired. |
identity.device.released |
deviceId, previousTenantId, reason, wipeLevel |
A device has left your organization, and its displays are removed. reason gives the cause (reconnect, factory, removed, ops, tenant-deleted), and wipeLevel the level to which it wipes itself. |
identity.device.blocked |
deviceId, previousTenantId, reason, blockedAt |
A device was reported lost or blocked by the operator. It no longer belongs to any organization and cannot sign in until the block is lifted. |
identity.device.reregistration-requested |
deviceId, tenantId, deviceName, requestedAt |
A paired device registered with a new key, probably because it was set up again. It waits until someone decides in the device record. |
identity.device.reregistration-decided |
deviceId, decision, decidedById, allowedUntil |
A decision was made about a re-registered device. decision is keep (keep the displays), reconnect (pair again), or block (block it). |
identity.renderer.minted |
rendererSessionId, playerId, expiresAt |
A playback session of a display was issued (machine traffic). |
identity.renderer.revoked |
rendererSessionId, playerId, reason |
A playback session was revoked (machine traffic). |
Sessions and sign-in
Sign-ins, renewal of sessions, magic links, and actions by platform operations on behalf of an account. sessions.session.theft-detected is the alarm for a reused session token.
| Event type | Core payload | When it is raised |
|---|---|---|
sessions.login.succeeded |
sessionId, userId, kind, method |
A sign-in succeeded, and method gives the route. |
sessions.login.failed |
email, reason, ipAddress |
A sign-in failed. |
sessions.mfa.verified |
sessionId, userId, via |
The second factor was confirmed. |
sessions.mfa.failed |
sessionId, userId, attemptCount |
The second factor was entered incorrectly. |
sessions.session.refreshed |
sessionId, familyId, userId |
A session was renewed (constant traffic). |
sessions.session.theft-detected |
sessionId, familyId, replayedHashPrefix |
A session token that had already been used up was presented again. |
sessions.session.terminated |
sessionId, userId, reason |
A session was ended. |
sessions.session.all-terminated |
userId, revokedCount, keptSessionId |
All sessions of an account were ended. |
sessions.password-reset.requested |
passwordResetId, subjectKind, purpose |
A password reset was requested. |
sessions.password-reset.completed |
passwordResetId, userId, subjectKind |
A new password was set through the reset. |
sessions.magic-link.requested |
magicLinkId, email, expiresAt |
A magic link was requested. |
sessions.magic-link.consumed |
magicLinkId, sessionId, userId |
A magic link was used. |
sessions.impersonation.started |
operatorUserId, targetUserId, reason, expiresAt |
Platform operations act on behalf of an account. |
sessions.impersonation.ended |
operatorUserId, targetUserId, endedBy |
Acting on behalf of an account was ended. |
Billing
Contract, invoices, payment methods, and the unlocked features. A package change reports twice: subscription.package-changed says that the contract is on a different package (on every change), and feature-entitlements.changed says that one of the feature switches has changed, and changedKeys shows which one. There are no separate events for upgrade and downgrade. The direction is in from and to.
| Event type | Core payload | When it is raised |
|---|---|---|
billing.subscription.created |
subscriptionId, tenantId, status, billingCycle, currentPeriodEnd |
A contract was created. |
billing.subscription.activated |
subscriptionId, tenantId, from (trial/past_due) |
The contract is active, and from gives the previous state. |
billing.subscription.past-due |
subscriptionId, graceUntil, reason (payment-failed/trial-ended) |
Payment did not arrive or the trial ended. graceUntil gives the deadline. |
billing.subscription.grace-lapsed |
subscriptionId, tenantId, graceLapsedAt, suspendsAt |
The deadline has passed, and suspendsAt gives the suspension date. |
billing.subscription.trial-ending |
subscriptionId, tenantId, trialEndsAt, daysLeft |
The trial ends soon, and daysLeft gives the remaining days. |
billing.subscription.suspended |
subscriptionId, tenantId |
The contract was suspended. |
billing.subscription.canceled |
subscriptionId, reason |
The contract was canceled. |
billing.subscription.package-changed |
tenantId, from (nullable), to, at |
The contract is on a different package. It comes on every change, and the direction is in from and to. |
billing.subscription.period-rolled |
subscriptionId, tenantId, periodStart, periodEnd, cameFromTrial |
A new billing period has begun. |
billing.subscription.cancel-scheduled |
subscriptionId, tenantId, effectiveAt, reason |
A cancellation was scheduled for its date. |
billing.subscription.cancel-revoked |
subscriptionId, tenantId, at |
A scheduled cancellation was withdrawn. |
billing.subscription.trial-extended |
subscriptionId, tenantId, days, trialEndsAt, reason |
The trial was extended. |
billing.subscription.license-conflict |
subscriptionId, tenantId, devices, licenses, deadline |
The paid reduction of the booked displays has taken effect, and more devices are running than displays are booked. The surplus ones keep running until deadline. |
billing.subscription.license-conflict-enforced |
subscriptionId, tenantId, frozen, licenses |
The grace period has ended, and frozen counts the frozen displays. They stay frozen until the organization books more displays or unpairs a device. |
billing.subscription.pending-change-failed |
subscriptionId, tenantId, kind (quantity/package), pendingQuantity, usedDisplays, effectiveAt |
A scheduled change did not take effect, because more displays are in use than it allows. It stays in place and takes effect at the end of the next period. |
billing.invoice.issued |
invoiceId, invoiceNumber, amountCents, currency |
An invoice was issued. |
billing.invoice.paid |
invoiceId, invoiceNumber, amountCents, paidAt |
An invoice was paid. |
billing.invoice.payment-failed |
invoiceId, amountCents, attemptCount |
A payment failed. |
billing.invoice.refunded |
invoiceId, reason, refundId |
An invoice was refunded. |
billing.invoice.credited |
invoiceId, creditNoteId, creditNoteNumber, amountCents, settlement, reason |
A credit note was created for an invoice. |
billing.invoice.voided |
invoiceId, invoiceNumber, reason |
An invoice was voided. |
billing.invoice.written-off |
invoiceId, invoiceNumber, amountCents, reason |
An invoice was written off. |
billing.invoice.dunned |
invoiceId, noticeId, noticeNumber, level, deadlineAt |
A reminder was created, and level gives its level. |
billing.vat-id.confirmed |
tenantId, countryCode, requestId |
The VAT ID was confirmed. |
billing.vat-id.invalidated |
tenantId, countryCode, previousStatus |
The VAT ID is no longer valid. |
billing.payment-method.attached |
tenantId, stripePaymentMethodId, kind, lastFour |
A payment method was stored. |
billing.payment-method.removed |
tenantId, stripePaymentMethodId |
A payment method was removed. |
billing.payment-way.switched |
tenantId, before, after (invoice/stripe) |
The payment way was switched (invoice or stripe). |
billing.feature-entitlements.changed |
tenantId, before, after, changedKeys |
One of the feature switches has changed, and changedKeys shows which. |
billing.item-override.ending |
tenantId, subscriptionId, skuCode, validUntilDate, effectiveUnitPriceCents, listUnitPriceCents |
Special terms are about to expire. |
billing.item-override.expired |
tenantId, subscriptionId, skuCode, validUntilDate, listUnitPriceCents |
Special terms have expired. |
billing.checkout.started |
checkoutRef, tenantId, purpose, packageCode, billingCycle, entry |
A checkout was started. |
billing.checkout.finished |
checkoutRef, tenantId, purpose, outcome, paymentWay |
A checkout has ended, and outcome gives the result. |
Joining and setup
Invitations, the setup wizard, provisioning of a new organization, join requests, and self-registration.
| Event type | Core payload | When it is raised |
|---|---|---|
onboarding.invitation.sent |
invitationId, email, defaultRoleId, expiresAt |
An invitation was sent. |
onboarding.invitation.resent |
invitationId, email, expiresAt |
An invitation was sent again. |
onboarding.invitation.revoked |
invitationId, email, revokedById |
An invitation was revoked. |
onboarding.invitation.accepted |
invitationId, email, acceptedByUserId |
An invitation was accepted. |
onboarding.invitation.expired |
invitationId, tenantId, email |
An invitation has expired. |
onboarding.setup-step.completed |
tenantId, step, via |
A step of the setup wizard was completed. |
onboarding.setup-wizard.completed |
tenantId, completedAt |
The setup wizard was completed. |
onboarding.tenant.provisioning-started |
tenantId, slug, provisionedById |
Provisioning of a new organization has begun. |
onboarding.tenant.provisioning-completed |
tenantId, subscriptionId, ownerEmail |
Provisioning of a new organization is complete. |
onboarding.join-request.received |
joinRequestId, tenantId, email, displayName |
A join request has arrived. |
onboarding.join-request.decided |
joinRequestId, tenantId, email, decision (accepted/rejected), decidedById |
A join request was decided (accepted or rejected). |
onboarding.self-registration.changed |
enabled, reason, changedById |
The platform switch for self-registration was flipped (platform operations). |
onboarding.signup.started |
funnelRef, entry |
A self-registration was started. |
onboarding.signup.verified |
funnelRef, route (create/join/sso) |
The address of a self-registration was verified, and route gives the route. |
onboarding.signup.completed |
funnelRef, tenantId |
A self-registration is complete. |
onboarding.terms.accepted |
tenantId, userId, occasion, documents, locale, acceptedAt |
Contract documents were accepted, and documents lists which. |