Webhook Events and Payloads
Integrations pro Pro featurePro feature. Available in Learnomy Pro, with the Webhooks Pro extension on.
Every event Learnomy Pro delivers, and the exact JSON a subscriber receives. Use this to build a Zap, map WPFusion fields, or wire a BuddyNext membership sync without reading any PHP.
Payload shape#
{
"event": "enrollment.created",
"version": 2,
"timestamp": "2026-08-29T18:43:40+00:00",
"data": {
"enrollment_id": 4242,
"user_id": 222,
"course_id": 20,
"source": "purchase"
}
}
datais always a JSON object, never an array - for every event, without exception. A field that is sometimes a list and sometimes a map cannot be mapped reliably, and Zapier will not offer the fields at all.versionis bumped whenever the shape changes, so a consumer can detect a change rather than silently mis-mapping. Version 2 is the first named-field release; version 1 was a positional array and is no longer emitted.- Entity ids are always
<entity>_id, never a bareid, so the same concept has the same name in every event. - If an event ever delivers an argument this reference does not name, it arrives as
arg_<n>rather than being dropped. Seeingarg_5in a payload means this table needs updating - please report it.
Filtering by purchase type#
Every purchase emits purchase.completed regardless of what was bought. Filter on the
purchase_type field (course, membership, learning_path, gift, space, space_seats)
rather than subscribing to a per-type event - there is one event and one named field, so
"when someone buys a Space plan" is a single condition in Zapier.
Events#
AI#
| Event | data fields |
|---|---|
ai.overage |
user_id, kind, used, limit |
Assignments#
| Event | data fields |
|---|---|
assignment.created |
assignment_id, data |
assignment.deleted |
assignment_id |
assignment.graded |
submission_id, score, submission |
assignment.resubmit_requested |
submission_id, feedback |
assignment.submitted |
submission_id, assignment_id, user_id |
assignment.updated |
assignment_id, data |
Certificates#
| Event | data fields |
|---|---|
certificate.expired |
certificate_id, user_id, course_id |
certificate.issued |
certificate_id, user_id, course_id |
certificate.revoked |
certificate_id, certificate |
certificate.verified |
certificate_id, uuid |
Cohorts#
| Event | data fields |
|---|---|
cohort.created |
cohort_id, data |
cohort.deleted |
cohort_id |
cohort.member_added |
cohort_id, user_id |
cohort.member_removed |
cohort_id, user_id |
cohort.updated |
cohort_id, data |
Commissions#
| Event | data fields |
|---|---|
commission.calculated |
transaction_id |
commission.overpaid |
amount, transaction_id, gateway |
Coupons#
| Event | data fields |
|---|---|
coupon.exhausted |
coupon_id |
Courses#
| Event | data fields |
|---|---|
course.approved |
course_id |
course.created |
course_id, data |
course.deleted |
course_id |
course.duplicated |
course_id, source_course_id |
course.pending_review |
course_id |
course.published |
course_id |
course.rejected |
course_id, reason |
course.updated |
course_id, data |
Enrollments#
| Event | data fields |
|---|---|
enrollment.access_restored |
enrollment_id, user_id, course_id |
enrollment.cancelled |
enrollment_id, user_id, course_id |
enrollment.completed |
enrollment_id, user_id, course_id |
enrollment.created |
enrollment_id, user_id, course_id, source |
enrollment.expired |
enrollment_id, user_id, course_id |
enrollment.external_requested |
user_id, course_id, request |
enrollment.progress_reset |
user_id, course_id |
enrollment.purchase_failed |
user_id, course_id, result, provider, context |
enrollment.restarted |
user_id, course_id |
enrollment.retaken |
user_id, course_id, reset_progress |
Gifts#
| Event | data fields |
|---|---|
gift.issued |
codes, plan_id, buyer_id |
gift.redeemed |
code, user_id, subscription_id |
Instructors#
| Event | data fields |
|---|---|
instructor.application_submitted |
application_id, user_id |
instructor.approved |
application_id, user_id |
instructor.courses_reassigned |
user_id, target_user_id, count |
instructor.rejected |
application_id, user_id, reason |
instructor.resumed |
user_id |
instructor.suspended |
user_id |
Learning paths#
| Event | data fields |
|---|---|
learning_path.completed |
certificate_id, user_id, path_id |
learning_path.enrolled |
enrollment_id, user_id, path_id, source |
learning_path.purchased |
path_id, user_id, transaction_id |
Lessons#
| Event | data fields |
|---|---|
lesson.attachment_downloaded |
attachment_id, lesson_id, user_id |
lesson.comment_posted |
comment_id, lesson_id, user_id |
lesson.comment_replied |
comment_id, parent_id, lesson_id, user_id |
lesson.completed |
user_id, lesson_id, course_id |
lesson.copied |
lesson_id, source_lesson_id, course_id |
lesson.created |
lesson_id, course_id, data |
lesson.deleted |
lesson_id, course_id |
lesson.media_served |
lesson_id, media_id, user_id |
lesson.unlocked |
lesson_id, user_id, course_id |
lesson.updated |
lesson_id, data |
LTI#
| Event | data fields |
|---|---|
lti.link_refused |
user_id, issuer, reason |
Memberships#
| Event | data fields |
|---|---|
membership.created |
subscription_id, user_id, plan_id |
membership.invoice_paid |
subscription_id, provider_subscription_id |
Membership plans#
| Event | data fields |
|---|---|
membership_plan.archived |
plan_id |
membership_plan.deleted |
plan_id |
membership_plan.saved |
plan_id, is_new |
Milestones#
| Event | data fields |
|---|---|
milestone.earned |
user_id, milestone_id, source |
milestone.revoked |
user_id, milestone_id |
Payments#
| Event | data fields |
|---|---|
payment.completed |
txn_id, user_id, gateway |
payment.failed |
session_id, gateway, payment_status |
payment.refunded |
transaction_id, amount, gateway, is_full_refund |
Payouts#
| Event | data fields |
|---|---|
payout.reversal_failed |
payout_id, error, debt_id |
payout.reversed |
payout_id, instructor_id, amount |
payout.transfer_created |
instructor_id, transfer_id, amount, currency |
Purchases#
| Event | data fields |
|---|---|
purchase.completed |
transaction_id, user_id, purchase_type, item_id, extra, gateway |
purchase.external_completed |
transaction_id, user_id, purchase_type, extra, gateway |
Quizzes#
| Event | data fields |
|---|---|
quiz.attempts_granted |
user_id, quiz_id, granted, attempts |
quiz.created |
quiz_id, data |
quiz.deleted |
quiz_id, course_id |
quiz.failed |
attempt_id, user_id, quiz_id, score |
quiz.graded |
attempt_id, user_id, quiz_id |
quiz.passed |
attempt_id, user_id, quiz_id, score |
quiz.started |
attempt_id, user_id, quiz_id |
quiz.submitted |
attempt_id, user_id, quiz_id |
quiz.updated |
quiz_id, data |
Refunds#
refund.partial_revocation is the one to subscribe to if you automate refunds. It fires when the
money went back but something it bought could NOT be taken back - canonically a gift code a third
party has already redeemed, who legitimately keeps their membership. notice carries the
owner-facing explanation. Before 1.9.4 this was shown only to the admin who clicked Refund, on that
one screen, so an owner refunding through an integration never learned about it.
| Event | data fields |
|---|---|
refund.issued |
refund_transaction_id, transaction_id, amount, reason |
refund.partial_revocation |
notice, transaction, refund_transaction_id |
Reports#
| Event | data fields |
|---|---|
report.resolved |
report_id, status, resolved_by |
report.submitted |
report_id, object_type, object_id, user_id, reason |
Reviews#
| Event | data fields |
|---|---|
review.submitted |
review_id, user_id, course_id |
Spaces#
| Event | data fields |
|---|---|
space.course_assigned |
space_id, course_id |
space.course_removed |
space_id, course_id |
space.course_scope_changed |
space_id, course_id, scope, previous |
space.created |
space_id, data |
space.deleted |
space_id |
space.member_added |
space_id, user_id, role |
space.member_removed |
space_id, user_id |
space.member_resumed |
space_id, user_id |
space.member_role_changed |
space_id, user_id, role |
space.member_suspended |
space_id, user_id |
space.provisioned |
space_id, user_id, plan, txn_id |
space.request_created |
request_id, space_id, user_id, type, args |
space.request_declined |
request_id, space_id, type, requested_by, request |
space.request_resolved |
request_id, space_id, type, requested_by, request |
space.seats_added |
space_id, user_id, seats_added, new_limit, pack, txn_id |
space.status_changed |
space_id, status, previous_status |
space.subscription_cancelled |
space_id, subscription_id, provider_subscription |
space.subscription_expired |
space_id, subscription_id |
space.subscription_past_due |
space_id, subscription_id, invoice |
space.subscription_renewed |
space_id, subscription_id, invoice |
space.trial_ended |
space_id, subscription_id |
space.updated |
space_id, data |
Space groups#
| Event | data fields |
|---|---|
space_group.course_assigned |
group_id, course_id, space_id |
space_group.course_removed |
group_id, course_id, space_id |
space_group.created |
group_id, space_id |
space_group.deleted |
group_id, space_id |
space_group.manager_assigned |
group_id, user_id, space_id |
space_group.manager_removed |
group_id, user_id, space_id |
space_group.member_added |
group_id, user_id, space_id |
space_group.member_removed |
group_id, user_id, space_id |
space_group.updated |
group_id, space_id |
Stripe Connect#
| Event | data fields |
|---|---|
stripe.account_connected |
instructor_id, stripe_user_id |
Subscriptions#
| Event | data fields |
|---|---|
subscription.approved |
subscription_id, user_id, plan_id, context_type |
subscription.auto_expired |
subscription_id, user_id, plan_id |
subscription.cancelled |
subscription_id, user_id, target_id, immediate, context_type |
subscription.created |
subscription_id, user_id, plan_id, context_type |
subscription.declined |
subscription_id, user_id, plan_id, context_type |
subscription.deleted |
subscription_id |
subscription.expired |
subscription_id, user_id, target_id, context_type |
subscription.extended |
subscription_id, user_id, plan_id |
subscription.past_due |
subscription_id, user_id, target_id, failure_reason, context_type |
subscription.paused |
subscription_id, user_id, plan_id, context_type |
subscription.pending |
subscription_id, user_id, plan_id, context_type |
subscription.plan_change_completed |
subscription_id, from_plan_id, to_plan_id, change_id, quote |
subscription.plan_change_failed |
subscription_id, to_plan_id, change_id, reason |
subscription.plan_changed |
subscription_id, old_price_id, new_price_id, context |
subscription.renewed |
subscription_id, user_id, target_id, context_type |
subscription.resumed |
subscription_id, user_id, target_id, context_type |
subscription.trial_ended |
subscription_id, user_id, plan_id, context_type |
Users#
| Event | data fields |
|---|---|
user.account_deleted |
user_email |
user.app_credential_issued |
user_id, app_id, app_name |
user.blocked |
user_id, blocked_user_id |
user.data_purged |
user_id, summary |
user.provisioned |
user_id, context |
user.registered |
user_id, role |
user.unblocked |
user_id, unblocked_user_id |
Withdrawals#
| Event | data fields |
|---|---|
withdrawal.approved |
instructor_id, withdrawal |
withdrawal.failed |
withdrawal_id, error |
withdrawal.paid |
withdrawal_id, stripe_transfer_id |
withdrawal.rejected |
withdrawal_id, instructor_id, reason |
withdrawal.requested |
withdrawal_id, instructor_id, settled |
Generated from Webhooks_Pro\Extension::get_event_fields(), which derives its names from each
hook's own do_action() signature. Regenerate after changing that map so this reference and the
delivered payload cannot drift apart.