Webhook events
The events Transakt sends to your endpoints, and their payloads.
Webhook endpoints belong to an API client and receive the event types they subscribe to. subscription.* and seat.* events arrive only for products the API client may read; customer.created only for API clients with access to all your products. Every message is signed: see Verifying webhooks.
Envelope
{
"id": "msg_0193a8f2c4b17d3e9f0a1b2c3d4e5f60",
"type": "subscription.plan_changed",
"timestamp": "2026-10-01T08:15:02.123Z",
"data": {}
}| Member | Meaning |
|---|---|
id | The message id, equal to the webhook-id header; the same on retries and replays. |
type | The event type (below). |
timestamp | When the change was committed (UTC), not when this attempt was sent. |
data | The event data: identifiers, your product, plan and edition slugs, the customer's tenant id, the subscription and an entitlement snapshot. |
Payloads carry identifiers only: no names, email addresses, keys, tokens or payment data. Re-read anything else through the product API. Bodies are UTF-8 JSON of at most 64 KiB, with the conventions of the API (camelCase, PascalCase enumeration values, UTC timestamps, nullable members always present).
Event types
| Type | Sent when |
|---|---|
subscription.activated | A subscription becomes Active for the first time, or again after it ended: Marketplace activation, key redemption, online purchase, manual activation, resumption. |
subscription.plan_changed | The plan changed. |
subscription.quantity_changed | The quantity (licences) changed. |
subscription.suspended | The subscription was suspended (by Microsoft, or after failed payments and the grace period). |
subscription.reinstated | A suspended subscription became Active again. |
subscription.renewed | The validity was extended for a new term. |
subscription.cancelled | The subscription ended as Cancelled: a cancellation, a Marketplace unsubscribe, the end of a period with renewal off, or non-payment. |
subscription.expired | A non-Marketplace subscription passed its end date. |
seat.assigned | A seat was given to a user. |
seat.revoked | A seat was taken back, including when a subscription ends. |
customer.created | A new customer organisation was created in your workspace. |
webhook.test | You pressed Send test event in the Admin Portal (sent to that endpoint only). |
An event is written in the same transaction as the change, so every change produces its event whichever way it was made, and a change that is not applied (a duplicate notification, for example) produces none. Moving a plan to another edition, or reordering editions, sends no event.
Event data
Subscription events
All eight subscription.* types share one shape:
| Member | Type | Meaning |
|---|---|---|
product | slug | Your product. |
plan | slug | The plan. |
editionSlug | slug | The plan's edition. |
previousPlan | slug | Only on subscription.plan_changed. |
previousEditionSlug | slug | Only on subscription.plan_changed (equal to editionSlug for a lateral change). |
previousQuantity | integer | Only on subscription.plan_changed and subscription.quantity_changed. |
subscription | object | id, version, status, channel, quantity, isTrial, validUntil, autoRenew, cancelledAt. |
customer | object | id (the organisation id) and tenantId. |
entitlement | object | The tenant's entitlement for the product as of this change, exactly as the entitlement API returns it. |
{
"id": "msg_0193a8f2c4b17d3e9f0a1b2c3d4e5f60",
"type": "subscription.plan_changed",
"timestamp": "2026-10-01T08:15:02.123Z",
"data": {
"product": "planner",
"plan": "business",
"editionSlug": "business",
"previousPlan": "basic",
"previousEditionSlug": "basic",
"subscription": {
"id": "0193a8f2-7d1e-7b3a-9c51-3f0e2b7a1d44",
"version": 7,
"status": "Active",
"channel": "Marketplace",
"quantity": 25,
"isTrial": false,
"validUntil": "2027-09-30T23:59:59.000Z",
"autoRenew": true,
"cancelledAt": null
},
"customer": { "id": "0193a8f2-1111-7b3a-9c51-3f0e2b7a1d44", "tenantId": "72f988bf-86f1-41af-91ab-2d7cd011db47" },
"entitlement": { "tenantId": "72f988bf-86f1-41af-91ab-2d7cd011db47", "status": "Active", "version": 7 }
}
}(The entitlement above is shortened; it carries every member of the entitlement answer.)
Seat events
seat.assigned and seat.revoked:
| Member | Meaning |
|---|---|
product, plan, editionSlug | As for subscription events. |
seat | id, userObjectId (may be null), userTenantId, assignedAt, revokedAt. No email. |
customer | id and tenantId. |
entitlement | The tenant's entitlement as of this change. |
Other events
customer.created:{ "customer": { "id": "…", "tenantId": "…" } }.webhook.test:{ "endpointId": "…" }.
Ordering and versions
Delivery is at least once and unordered. Each subscription event carries subscription.version, which increases with every committed change of the subscription; entitlement.version carries the same number for the tenant and product. Keep the highest version you have applied per subscription and ignore lower ones, or re-read the entitlement.
Versioning
Event payloads change only additively: new members, new enumeration values and new event types (delivered only to endpoints that subscribe to them). Ignore unknown members and treat unknown accessLevel or licenceOutcome values as the most restrictive. A breaking change publishes a new event type (for example subscription.plan_changed.v2) next to the old one, which keeps being delivered for at least 12 months.
Prove control of an Entra application POST
Activates a pending Entra application credential of an API client. Call it from the application with a client-credentials token for the Transakt API and the one-time challenge shown in the Admin Portal (valid 24 hours). The token must be issued in the tenant you recorded for the application. Errors: [`auth.credentials_invalid`](/errors/auth.credentials_invalid/), [`api_client.application_verification_failed`](/errors/api_client.application_verification_failed/), [`auth.forbidden`](/errors/auth.forbidden/), [`request.rate_limited`](/errors/request.rate_limited/).
Errors
Every error code the API can return, with its status and meaning.