API 參考
Webhook events
Every event you can subscribe to, by capability domain, with the permission it needs and a sample payload.
Every event uses the envelope described in Webhooks. The samples below show the data field.
Content & Publishing
collections.item.created
Fired when a collection item is created (includes publicVersion and cacheTags).
{
"locale": "en-US",
"collectionId": "col_01",
"collectionKey": "blog",
"itemId": "item_01",
"slug": "hello-world",
"status": "published",
"publishedFieldData": {
"title": "Hello World"
},
"channel": "agent",
"publicVersion": "1729500000000",
"cacheTags": [
"collection:blog",
"item:item_01",
"seo",
"search"
]
}collections.item.updated
Fired when a collection item draft or published payload is updated.
{
"locale": "en-US",
"collectionId": "col_01",
"collectionKey": "blog",
"itemId": "item_01",
"slug": "hello-world",
"status": "published",
"publishedFieldData": {
"title": "Hello World"
},
"channel": "agent",
"publicVersion": "1729500000000",
"cacheTags": [
"collection:blog",
"item:item_01",
"seo",
"search"
]
}collections.item.published
Fired when a collection item is published and visible on the Content Delivery API.
{
"locale": "en-US",
"collectionId": "col_01",
"collectionKey": "blog",
"itemId": "item_01",
"slug": "hello-world",
"status": "published",
"publishedFieldData": {
"title": "Hello World"
},
"channel": "agent",
"publicVersion": "1729500000000",
"cacheTags": [
"collection:blog",
"item:item_01",
"seo",
"search"
]
}collections.item.unpublished
Fired when a collection item is unpublished and removed from the Content Delivery API.
{
"locale": "en-US",
"collectionId": "col_01",
"collectionKey": "blog",
"itemId": "item_01",
"slug": "hello-world",
"status": "draft",
"publishedFieldData": null,
"channel": "agent",
"publicVersion": "1729500000000",
"cacheTags": [
"collection:blog",
"item:item_01",
"seo",
"search"
]
}collections.item.deleted
Fired when a collection item is permanently deleted.
{
"locale": "en-US",
"collectionId": "col_01",
"collectionKey": "blog",
"itemId": "item_01",
"slug": "hello-world",
"status": "draft",
"publishedFieldData": null,
"channel": "agent",
"publicVersion": "1729500000000",
"cacheTags": [
"collection:blog",
"item:item_01",
"seo",
"search"
]
}collections.items.bulkChanged
Fired once per batch operation (bulkCreate, bulkUpdate, publish/unpublish batch, or CSV/JSON import).
{
"locale": "en-US",
"collectionId": "col_01",
"collectionKey": "blog",
"operation": "published",
"itemIds": [
"item_01",
"item_02"
],
"count": 2,
"channel": "agent",
"publicVersion": "1729500000000",
"cacheTags": [
"collection:blog",
"seo",
"search",
"item:item_01",
"item:item_02"
]
}collections.schema.changed
Fired when a collection or its field schema is created, updated, or deleted (triggers `kanorio types` regeneration).
{
"collectionId": "col_01",
"collectionKey": "teachers",
"operation": "updated",
"addedFieldIds": [
"linkedin_url"
],
"updatedFieldIds": [],
"removedFieldIds": [],
"titleFieldId": "name",
"publicVersion": "1729500000000",
"cacheTags": [
"collections",
"collection:teachers",
"collection:teachers:items"
]
}content.site.published
Fired when a site is published, invalidating pages, globals, and redirects caches.
{
"locale": "en-US",
"isFirstPublish": false,
"pageCount": 12,
"publicVersion": "1729500000000",
"cacheTags": [
"site:ws_01",
"pages",
"globals",
"redirects",
"seo"
]
}{
"locale": "en-US",
"pageId": "page_01",
"slug": "/about",
"previousSlug": null,
"title": "About",
"pageType": "generic",
"publicVersion": "1729500000000",
"cacheTags": [
"pages",
"page:page_01",
"seo",
"search"
]
}content.page.updated
Fired when a published page's content or slug is updated (includes previousSlug when renamed).
{
"locale": "en-US",
"pageId": "page_01",
"slug": "/about",
"previousSlug": "/about-us",
"title": "About",
"pageType": "generic",
"publicVersion": "1729500000000",
"cacheTags": [
"pages",
"page:page_01",
"seo",
"search",
"redirects"
]
}{
"locale": "en-US",
"pageId": "page_01",
"slug": "/about",
"previousSlug": null,
"title": "About",
"pageType": "generic",
"publicVersion": "1729500000000",
"cacheTags": [
"pages",
"page:page_01",
"seo",
"search"
]
}{
"locale": "en-US",
"pageId": "page_01",
"slug": "/about",
"previousSlug": null,
"title": "About",
"pageType": "generic",
"publicVersion": "1729500000000",
"cacheTags": [
"pages",
"page:page_01",
"seo",
"search"
]
}Customers, Membership & Entitlements
customers.sharedSender.softCap
Fired once per day when sign-in code and similar emails sent from Kanorio's shared address exceed the site's daily soft cap; the bot check before sign-in is strengthened automatically. Nothing to do.
{
"day": "2026-11-04",
"level": "T0"
}customers.sharedSender.paused
Fired when those emails are paused for the site because of bounces, complaints or unusual volume; passkey, Google and signed-in customers are unaffected. Kanorio reviews and restores sending.
{
"reason": "volume",
"level": "T0"
}customers.sharedSender.resumed
Fired when paused sign-in code emails resume after review.
{
"level": "T1"
}customers.contact.created
Fired when a contact is created from any source (checkout, form, import, manual, customer sign-up). Identities are listed by kind only; the data never includes the email address or phone number.
{
"contactId": "cnt_01",
"channel": "checkout",
"source": "CHECKOUT",
"identities": [
"EMAIL",
"PHONE"
]
}customers.contact.updated
Fired when a contact's fields change (name, tags, note, locale, invoice preference, metadata, external reference, profile attributes). Lists the changed field names; fetch the contact to read the values.
{
"contactId": "cnt_01",
"channel": "backoffice",
"fields": [
"tags",
"note"
]
}customers.contact.merged
Fired when two contacts become one, either automatically (the same person arrived with another identity) or by the owner. mergedContactId no longer exists; move your references to contactId.
{
"contactId": "cnt_01",
"channel": "form",
"mergedContactId": "cnt_02",
"movedIdentities": [
"PHONE"
]
}customers.contact.access_changed
Fired when the owner blocks or unblocks a customer's sign-in. BLOCKED revokes every session and refuses new sign-ins; orders, consent and emails are unaffected.
{
"contactId": "cnt_01",
"channel": "backoffice",
"status": "BLOCKED",
"previousStatus": "ACTIVE",
"reason": "Chargeback fraud",
"revokedSessions": 2
}customers.consent.updated
Fired when a contact's marketing consent on one channel changes (subscribed, pending confirmation, unsubscribed, bounced, complained).
{
"contactId": "cnt_01",
"channel": "EMAIL",
"status": "UNSUBSCRIBED",
"previousStatus": "SUBSCRIBED",
"source": "UNSUBSCRIBE_LINK"
}deliverables.entitlement.granted
Fired when a contact is granted access (Entitlement) to a deliverable or unit.
{
"entitlementId": "ent_01",
"contactId": "cnt_01",
"deliverableId": "deliv_01",
"unitId": null,
"source": "ORDER_LINE",
"endsAt": null,
"channel": "order"
}deliverables.entitlement.revoked
Fired when a contact's Entitlement is revoked (e.g. refund or manual revocation).
{
"entitlementId": "ent_01",
"contactId": "cnt_01",
"deliverableId": "deliv_01",
"unitId": null,
"source": "ORDER_LINE",
"endsAt": null,
"channel": "backoffice"
}Promotions & Pricing Rules
promotions.redeemed
Fired when a paid order redeems a promotion (automatic discount or discount code). Carries the promotion, the order and how the discount was split across lines; never the buyer email.
{
"redemptionId": "prd_01",
"promotionId": "prm_01",
"promotionCode": "AUTUMN10",
"promotionName": "Autumn 10% Off",
"orderId": "ord_01",
"orderNumber": 1001,
"contactId": "ct_01",
"discountAmount": 290,
"currency": "USD",
"lineAllocations": [
{
"orderLineId": "line_01",
"amount": 290
}
]
}promotions.redemption_revoked
Fired when a full refund revokes a redemption (the promotion usage count is given back). Partial refunds do not revoke.
{
"redemptionId": "prd_01",
"promotionId": "prm_01",
"promotionCode": "AUTUMN10",
"promotionName": "Autumn 10% Off",
"orderId": "ord_01",
"orderNumber": 1001,
"contactId": "ct_01",
"discountAmount": 290,
"currency": "USD",
"lineAllocations": [
{
"orderLineId": "line_01",
"amount": 290
}
]
}Reviews & Ratings
reviews.submitted
Fired when a buyer submits or edits a review (it is pending moderation).
{
"reviewId": "rev_01",
"targetKind": "PRODUCT",
"targetId": "prod_01",
"status": "PENDING",
"rating": 5,
"source": "BUYER"
}reviews.published
Fired when a review becomes public: approved by the store, or imported.
{
"reviewId": "rev_01",
"targetKind": "PRODUCT",
"targetId": "prod_01",
"status": "APPROVED",
"rating": 5,
"source": "BUYER"
}{
"reviewId": "rev_01",
"targetKind": "PRODUCT",
"targetId": "prod_01",
"status": "APPROVED",
"rating": 5,
"source": "BUYER"
}Transactions & Fulfillment
{
"orderId": "ord_01",
"orderNumber": 1001,
"amount": 2900,
"currency": "USD",
"itemCount": 1,
"customerName": "Alex Buyer",
"customerEmail": "buyer@example.com",
"lines": [
{
"id": "line_01",
"kind": "PRODUCT",
"refId": "tier_01",
"productId": "prod_01",
"title": "Workshop ticket",
"variantTitle": null,
"quantity": 1,
"unitAmount": 2900,
"lineAmount": 2900,
"lineDiscountAmount": 0
}
],
"promotionId": null,
"promotionCode": null
}ec.shipment.statusChanged
Fired when a shipment status transitions (in transit, arrived at store, delivered, or exception).
{
"orderId": "ord_01",
"orderNumber": 1001,
"shipmentId": "shp_01",
"status": "IN_TRANSIT",
"carrier": "PAYUNI",
"trackingNumber": "TRK123456",
"storeName": null
}ec.order.refunded
Fired once per successful refund (partial or full, issued from the dashboard, at the payment provider, or by a lost chargeback) with the refunded lines and the order's refund status after it.
{
"orderId": "ord_01",
"orderNumber": 1001,
"refundId": "rf_01",
"amount": 2900,
"currency": "USD",
"shippingAmount": 0,
"source": "MERCHANT",
"reason": "REQUESTED_BY_CUSTOMER",
"lines": [
{
"id": "line_01",
"quantity": 1,
"amount": 2900
}
],
"orderRefundedAmount": 2900,
"orderFinancialStatus": "REFUNDED",
"customerName": "Alex Buyer",
"customerEmail": "buyer@example.com"
}Protected Deliverables & Progress
deliverables.progress.completed
Fired once when a learner first meets the deliverable's completion rule (completion snapshot; never fires again for that learner even if units are added later).
{
"contactId": "cnt_01",
"deliverableId": "deliv_01",
"percent": 100
}deliverables.progress.unit_completed
Fired when a learner completes one unit (video/audio watched to 90%, or marked complete). Use it for per-chapter automations.
{
"contactId": "cnt_01",
"deliverableId": "deliv_01",
"unitId": "unit_01"
}deliverables.progress.stalled
Fired by the daily check when a learner stalls: granted access 14+ days ago and never started (not_started), or has progress but no activity for 7+ days (inactive). At most once per learner, deliverable and reason per ISO week. Use it for reminder automations.
{
"contactId": "cnt_01",
"deliverableId": "deliv_01",
"unitId": "unit_01",
"reason": "inactive",
"days": 9
}deliverables.quiz.attempted
Fired for every graded quiz attempt (score 0–100, passed, attemptNo). A passed attempt also completes the unit.
{
"contactId": "cnt_01",
"deliverableId": "deliv_01",
"unitId": "unit_01",
"attemptNo": 1,
"score": 80,
"passed": true
}deliverables.certificate.issued
Fired when a completion certificate is issued (serial); the PDF is fetched through the Customer API.
{
"contactId": "cnt_01",
"deliverableId": "deliv_01",
"serial": "2026-K7P2QW4D"
}Forms & Data Collection
customers.form.submitted
Fired when a visitor submits an online form (notifies team and webhooks).
{
"formId": "form_01",
"formName": "Contact Us",
"submissionId": "sub_01",
"submitter": {
"name": "Alex",
"email": "alex@example.com",
"phone": null
},
"answers": [
{
"fieldId": "f_name",
"type": "text",
"label": "Name",
"value": "Alex",
"display": "Alex"
},
{
"fieldId": "f_email",
"type": "email",
"label": "Email",
"value": "alex@example.com",
"display": "alex@example.com"
}
]
}Identity, Tenant & Authorization
site.subscription.upcomingRenewal
Fired before an annual plan renews when annual add-ons or pending add-on / platform fees will be charged on the same invoice.
{
"periodKey": "2027-01-01T00:00:00.000Z",
"totalAmountLabel": "US$348.00"
}site.subscription.addOnPriceChange
Fired at least 30 days before add-on prices change for the site, with the per-level price changes and effective date.
{
"toVersion": "2027-01"
}team.accessRequest.created
Fired when a team member requests permissions they are missing, so people who manage the team can review it.
{
"requestId": "areq_01",
"requesterUserId": "usr_01",
"permissions": [
"commerce:refund"
]
}Media & Assets
media.asset.ready
Fired when background processing of a media file (thumbnail, visibility move, transcoding) finishes and the file is ready to use.
{
"assetId": "ckasset01",
"fileName": "workbook.pdf",
"kind": "pdf",
"mimeType": "application/pdf",
"visibility": "protected",
"processingKind": "DOCUMENT_THUMBNAIL",
"jobId": "ckjob01",
"errorCode": null
}media.asset.failed
Fired when background processing of a media file fails after retries; the site team also gets an in-app notification.
{
"assetId": "ckasset01",
"fileName": "workbook.pdf",
"kind": "pdf",
"mimeType": "application/pdf",
"visibility": "protected",
"processingKind": "DOCUMENT_THUMBNAIL",
"jobId": "ckjob01",
"errorCode": "THUMBNAIL_FAILED"
}site.storageQuota.alert
Fired when site storage reaches 80%, is exhausted, auto-upgrades, or add-on payment fails.
{
"reason": "near_limit",
"usedBytes": 8600000000,
"quotaBytes": 10737418240
}Messaging & Reach
customers.sendingDomain.degraded
Fired when a verified custom sender domain fails DNS verification and campaign sending is paused.
{
"domain": "mail.example.com"
}customers.messagingQuota.alert
Fired when monthly messaging quota is exhausted, auto-upgraded, or add-on billing fails.
{
"reason": "exhausted",
"quota": 2000,
"levels": 0,
"periodStart": "2026-10-01T00:00:00.000Z"
}customers.teamDestination.disabled
Fired when a team notification destination (webhook or email) is automatically paused after repeated delivery failures.
{
"destinationId": "dest_01",
"failures": 3,
"lastError": "HTTP 500"
}Publishing Delivery, Discovery & Measurement
{
"milestone": 100
}site.externalFrontend.degraded
Fired when the daily external frontend health check detects failing core endpoints (unreachable storefront or broken SEO rewrites).
{
"externalStorefrontUrl": "https://shop.example.com",
"failedChecks": [
"storefront_reachable"
]
}Locale & Localization
content.translation.published
Fired when one record's translation in one locale goes live on its own (editor correction, Management API write, incremental or on-demand machine translation). cacheTags carry only that locale's tags. Not fired per record during a full-site translation job; see localization.job.completed.
{
"entityType": "post",
"entityId": "item_01",
"locale": "fr-FR",
"paths": [
"title",
"excerpt",
"contentMarkdown"
],
"translatedBy": "AGENT",
"publicVersion": "1729500000000",
"cacheTags": [
"collection:blog@fr-FR",
"item:item_01@fr-FR",
"seo@fr-FR",
"search@fr-FR"
]
}content.translation.deleted
Fired when a live translation of one record in one locale is deleted; visitors see the primary-locale text until it is translated again.
{
"entityType": "post",
"entityId": "item_01",
"locale": "fr-FR",
"paths": [],
"translatedBy": null,
"publicVersion": "1729500000000",
"cacheTags": [
"collection:blog@fr-FR",
"item:item_01@fr-FR",
"seo@fr-FR",
"search@fr-FR"
]
}localization.locale.published
Fired when a locale goes live for visitors and the Content Delivery API (a full-site translation job finished, or the owner published it). cacheTags is site:<id>: rebuild the language switcher and hreflang on every page.
{
"locale": "fr-FR",
"primaryLocale": "en-US",
"status": "PUBLISHED",
"pathPrefix": "fr",
"change": null,
"previous": null,
"removed": false,
"locales": [
{
"locale": "en-US",
"isPrimary": true,
"pathPrefix": null
},
{
"locale": "fr-FR",
"isPrimary": false,
"pathPrefix": "fr"
}
],
"publicVersion": "1729500000000",
"cacheTags": [
"site:ws_01"
]
}localization.locale.unpublished
Fired when a live locale is taken offline or removed (removed: true); its URL prefix now 301-redirects to the primary locale.
{
"locale": "fr-FR",
"primaryLocale": "en-US",
"status": "REMOVED",
"pathPrefix": "fr",
"change": null,
"previous": null,
"removed": true,
"locales": [
{
"locale": "en-US",
"isPrimary": true,
"pathPrefix": null
}
],
"publicVersion": "1729500000000",
"cacheTags": [
"site:ws_01"
]
}localization.locale.updated
Fired when a live locale's URL prefix (change: path_prefix, previous holds the old prefix), its position in the language switcher (order) or the site's primary locale (primary) changes.
{
"locale": "fr-FR",
"primaryLocale": "en-US",
"status": "PUBLISHED",
"pathPrefix": "fr",
"change": "path_prefix",
"previous": "fr-fr",
"removed": false,
"locales": [
{
"locale": "en-US",
"isPrimary": true,
"pathPrefix": null
},
{
"locale": "fr-FR",
"isPrimary": false,
"pathPrefix": "fr"
}
],
"publicVersion": "1729500000000",
"cacheTags": [
"site:ws_01"
]
}localization.job.completed
Fired when a full-site translation job finishes. cacheTags is locale:<code>: every response of that locale may have changed. A locale going live for the first time also fires localization.locale.published.
{
"jobId": "ltj_01",
"locale": "fr-FR",
"kind": "FULL",
"done": 42,
"failed": 0,
"skipped": 3,
"calls": 11,
"errorCode": null,
"publicVersion": "1729500000000",
"cacheTags": [
"locale:fr-FR"
]
}localization.job.failed
Fired when a full-site translation job fails (the model provider stayed unavailable or retries ran out; the daily limit only pauses a job). Retry it with localization.jobs.retry.
{
"jobId": "ltj_01",
"locale": "fr-FR",
"kind": "FULL",
"done": 12,
"failed": 5,
"skipped": 3,
"calls": 11,
"errorCode": "PROVIDER_UNAVAILABLE",
"publicVersion": "1729500000000",
"cacheTags": []
}Automation
automations.run.failed
Fired when a run of an owner-built automation ends in FAILED after retries (compensation already applied). Not fired for test runs or platform-default automations; at most once per automation revision every 30 days.
{
"automationId": "auto_01",
"runId": "run_01",
"triggerEventKey": "ec.order.paid",
"error": "HTTP 500 (gave up after 5 attempts)"
}automations.flow.paused
Fired when Kanorio turns an owner-built automation off automatically because its current revision ran more than 20 times in the past 7 days and 95% or more of those runs failed.
{
"automationId": "auto_01",
"revision": 4,
"runs": 23,
"failed": 23
}