VIP toolBeta

Your Skool, wired into everything else

Skool has no webhooks. SkoolKit does. The moment something happens in your community, a join, a failed payment, a cancel, a tag, a level-up, it is sent to Make, Zapier, n8n, GoHighLevel or your own app. Signed, retried if your tool is down, and logged for 30 days.

Delivered · 200 · 312 msPOST
{
  "type": "member.payment_failed",
  "community": { "name": "Your Community", … },
  "member": {
    "name": "María López",
    "email": "maria@example.com",
    "tier": "premium",
    …
  },
  "data": { "card_last4": "4242", … }
}
X-SkoolKit-Signature ✓Retried if downLogged 30 days
Works with✓Make✓Zapier✓n8n✓GoHighLevel✓Pabbly✓Slack✓Discord✓Your own app

What owners do with it

Every one of these is a short Make scenario or Zap. No code, no API, no copy-paste.

Revoke access the day a payment fails

When a payment fails, then your app removes their access, and restores it when the payment recovers.

member.payment_failedmember.payment_recoveredmember.left

Keep your CRM in step with Skool

When someone joins and answers your membership questions, then their answers, trial, payments and tags land on their record in GoHighLevel, Kit or Flodesk.

member.joinedmember.answeredmember.trial_startedmember.renewedmember.tagged

A Slack ping the moment someone cancels

When a paying member cancels, then a message in your team's channel with their name, tier and the date access ends.

member.cancelledmember.trial_cancelled

Warn annual members before the charge

When an annual plan renews in 30 days, then your email tool sends the notice several regions require.

member.renewal_upcoming

Set it up in three steps

Everything happens inside Skool, in the SkoolKit extension. Two minutes, start to finish.

1

Copy a URL from your tool

In Make, add a Custom webhook. In Zapier, Webhooks by Zapier → Catch Hook. In n8n, a Webhook node. In GoHighLevel, an Inbound Webhook trigger. Each one gives you a URL.

2

Paste it into SkoolKit

Inside Skool, open SkoolKit → Webhooks → Add a webhook. Paste the URL, tick the events you want, pick one community or all of them, and save. A GoHighLevel URL starts on the Flat format, so each membership answer maps on its own.

3

Press Send test

A realistic sample arrives at your tool straight away, so Make's "Determine data structure" or Zapier's "Test trigger" can see every field you can map.

Slack or Discord?Their incoming webhooks want their own message shape, so route through Make, Zapier or n8n and write the message there: "{{first_name}} just cancelled {{tier}}, access ends {{access_ends_at}}".

27 events, in plain words

Tick the ones you want per webhook. Each badge says how soon after it happens on Skool the event usually reaches you.

Within a minuteUp to 8 hours1 to 3 days after

Members

New joins are seen within about five minutes. A payment starting or renewing is confirmed against Skool's invoice ledger within the hour. Levels and tiers are seen by the full member walk, which runs up to every eight hours.

  • Someone joinsmember.joined
    datatierpaidleveltrialanswers (when the page carried them)
    Within ~5 minutes
  • Someone joins on a free trialmember.trial_started
    datatiertrial_ends_atlevel
    Within ~5 minutes
  • Someone has answered your membership questionsmember.answered
    dataanswers [{question, type, answer}]answered_atcount
    Within ~5 minutes
  • A trial converts, or a first payment goes throughmember.paid_start
    datatierfromtoupgradepaid_atamount_centscurrencycard_brandcard_last4
    Within the hour
  • Someone reaches a new levelmember.level_up
    datafromtotier
    Up to 8 hours
  • Someone moves to a higher-priced tiermember.tier_upgrade
    datafromtotier
    Up to 8 hours
  • Someone moves to a lower-priced tiermember.tier_downgrade
    datafromtotier
    Up to 8 hours
  • Someone leaves a review on your About pagemember.reviewed
    dataratingtextreview_id
    Within ~15 minutes

Payments

Read from the billing view Skool shows you as the owner. Card numbers never leave Skool; you get the brand and last four digits, as Skool shows them.

  • A payment is declinedmember.payment_failed
    datacard_brandcard_last4removing_at
    Within ~15 minutes
  • A failed payment goes through after allmember.payment_recovered
    datacard_brandcard_last4
    Within ~15 minutes
  • A subscription renews (the charge went through)member.renewed
    datatierprevious_period_endpaid_atamount_centscurrencycard_brandcard_last4ltv_cents
    Within the hour
  • A paid plan renews in N days (you choose N, 1 to 90)member.renewal_upcoming
    datarenews_atdays_beforedays_lefttierltv_cents
    About hourly

Leaving

A cancel is seen within minutes. Access actually ending is confirmed by the next full member check, which trails it by a day or so.

  • A paying member cancelsmember.cancelled
    datakindtieraccess_ends_atmrr_centscurrencyinterval
    Within ~15 minutes
  • A member cancels during a free trialmember.trial_cancelled
    datakindtieraccess_ends_atmrr_centscurrencyinterval
    Within ~15 minutes
  • A member who cancelled is staying after allmember.saved
    datakindtiermrr_centscurrency
    1 to 3 days after
  • Access ended after a cancel, or Skool removed them for non-paymentmember.left
    datareasondeclined_at / access_ends_atcard_last4
    1 to 3 days after

Tags

SkoolKit's own Member Tags: by hand, in bulk, by an Inbox rule or by an Auto DM. Your tags go only to your webhooks, never a co-owner's.

  • A tag goes on a membermember.tagged
    datatagtag_idsourcesource_ref
    Within a minute
  • A tag comes off a membermember.untagged
    datatagtag_idtagged_atsource
    Within a minute

Auto DMs

Your Auto DM sequences, as members move through them.

  • A member enters a sequenceautodm.enrolled
    dataautomationautomation_idtriggerenrollment_idstatustier
    Within a minute
  • A member replied and is waiting on youautodm.reply_waiting
    dataautomationautomation_idtier
    Within a minute
  • A sequence ends for a memberautodm.finished
    dataautomationoutcomereasonsteps_sentrepliedenrolled_at
    Within a minute

Posts

Your scheduled posts, from the queue to Skool.

  • A post is scheduled, moved, or scheduled from a draftscheduler.scheduled
    datascheduled_idtitlescheduled_atprevious_scheduled_atchangenotify_memberscategory
    Within a minute
  • A scheduled post is deleted or pulled back to draftscheduler.cancelled
    datascheduled_idtitlescheduled_atchange
    Within a minute
  • A scheduled post went livescheduler.published
    datapost_idurltitlescheduled_id
    Within a minute
  • A scheduled post failed after every retryscheduler.failed
    datatitletextscheduled_id
    Within a minute

SkoolKit

About SkoolKit itself.

  • A community stops working in SkoolKit: the session expired, the login is gone, or it lost admin rightsskoolkit.connection_lost
    datareasonstatuscommunity_slugerror
    Within a minute
  • An AI app changed something through Connect to AI (a post scheduled, an automation switched on…)skoolkit.ai_action
    datatoolsummaryappcall_id
    Within a minute

Filters

Joins can be limited to paid members or chosen tiers, level-ups to a minimum level, member.leftto the reasons you care about, and renewals to the number of days' notice. Set N to 32 or more and member.renewal_upcoming only ever fires for annual plans, since a monthly period is never that long.

Whose webhooks get what

Events about the community (joins, cancels, payments) go to every admin who subscribed. Events about something of yours (a tag, an Auto DM, a post, a connection, an AI action) go only to your own webhooks. It is the same list SkoolKit Alerts offers, less the nine Skool-notification alerts (your bell and DMs), which only your own Skool tab can see and so stay alerts. Members who leave a free community on their own are not reported yet.
For developers

The wire format

One POST per event, JSON body, payload version 1. Fields are only ever added, never renamed or removed, within a version.

Payload

Standard is nested: community, member and data as their own objects. Best for Make, Zapier and n8n, which map nested fields directly.

Flat puts every field at the top level, with the data fields prefixed data_. Best for GoHighLevel, whose Inbound Webhook cannot pick one answer out of a list, and for tools that cannot map nested JSON. Choose it per webhook.

  • member.email and ltv_cents are what Skool shows an admin: present for billed members, usually not for free ones. Null means not known.
  • member is null for the Scheduler's events and skoolkit.connection_lost, which are about a post or a community.
  • id is the event's id. Two of your webhooks subscribed to the same event receive the same id; use it to drop a duplicate.
  • Money is in cents: 14700 is 147.00.
  • Membership-question answers arrive as data.answers, a list of {question, type, answer}. In the flat format they are also spread out as question_1 / answer_1, question_2 / answer_2…, so GoHighLevel can map a field without parsing JSON.

Nested and versioned. The default.

{
  "id": "evt_18342",
  "type": "member.payment_failed",
  "schema_version": 1,
  "occurred_at": "2026-10-04T09:00:00.000Z",
  "detected_at": "2026-10-04T09:06:12.000Z",
  "community": {
    "id": "70de958d88024bf68f57bf90247a3b84",
    "slug": "your-community",
    "name": "Your Community",
    "url": "https://www.skool.com/your-community"
  },
  "member": {
    "id": "8b61634af64c4276aca3c1c7e5a67904",
    "handle": "maria-lopez",
    "name": "María López",
    "first_name": "María",
    "email": "maria@example.com",
    "tier": "premium",
    "level": 4,
    "ltv_cents": 14700,
    "joined_at": "2026-08-28T21:10:00.000Z",
    "avatar": null,
    "profile_url": "https://www.skool.com/@maria-lopez"
  },
  "data": {
    "card_brand": "visa",
    "card_last4": "4242",
    "removing_at": "2026-10-09T09:00:00.000Z"
  }
}

Check the signature

Each webhook has its own secret (whsec_…), shown in SkoolKit → Webhooks. The signature is an HMAC-SHA256 of<t>.<raw body> made with that secret, so a captured request cannot be replayed later with a fresh timestamp. Make and Zapier users can skip this; if you run your own app, check it.

Headers on every request

  • X-SkoolKit-Eventthe event type, e.g. member.payment_failed
  • X-SkoolKit-Event-Idthe same as id in the body
  • X-SkoolKit-Delivery-Idthis delivery to this URL
  • X-SkoolKit-Signaturet=<unix seconds>,v1=<hex>, see below
  • X-SkoolKit-Test1 on samples sent with the Send test button, absent otherwise
  • User-AgentSkoolKit-Webhooks/1

Your own header

If your app wants a key instead of a signature check, add one header to the webhook in SkoolKit → Webhooks, for exampleAuthorization: Bearer your-key or X-Api-Key: your-key. It goes with every delivery and every Send test. It can be any name except one SkoolKit sets itself.

import crypto from "node:crypto";

// secret:  the whsec_… value from SkoolKit → Webhooks → Signing secret
// rawBody: the request body exactly as received, before any JSON parsing
export function isFromSkoolKit(rawBody, signatureHeader, secret, toleranceSeconds = 300) {
  const parts = Object.fromEntries(signatureHeader.split(",").map((p) => p.split("=")));
  const t = Number(parts.t);
  if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false; // too old: a replay
  const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1 ?? ""));
}

Delivery and retries

Any 2xx within 10 seconds counts as delivered. Answer fast and do the slow work afterwards.

Now1 min5 min30 min2 h6 h24 hthen it stops, and the log says so
In order. One webhook's events go out one at a time, oldest first. Redirects are not followed: if your tool gives you a new URL, update it.
Paused when broken. 72 hours of nothing but failures, or a 410 Gone, pauses the webhook and emails you. Switch it back on when the URL works.
Never late. An event that could not be delivered within 72 hours is not sent late. Anything from the last 30 days can be resent from the log.

URLs must be https:// on the public internet.

Questions

Is it instant?

Payments and cancels arrive within about 15 minutes of Skool showing them. Tags, Auto DM steps and post changes arrive within a minute. New joins (with their answers and trial flag) arrive within about five minutes. Level-ups, tier changes, paid starts and renewals are seen by the full member walk, which runs up to every eight hours. A member actually leaving is confirmed by the next full member check, a day or so after their access ends.

Why is the member's email sometimes empty?

Skool shows you an email for members who have paid or been billed, and usually not for free members. When Skool doesn't show one, the field is null: it means "not known", never "has no email".

Do I need a paid Zapier plan?

Zapier puts its Catch Hook trigger on paid plans. Make's Custom webhook works on every Make plan, and n8n and GoHighLevel include theirs. A native Zapier app that works on free plans is on the list.

Will my co-owner's webhooks get my tags and automations?

No. Events about something of yours (a tag, an Auto DM, a scheduled post, a connection) go only to your own webhooks. Events about the community itself (a join, a cancel, a payment) go to every admin who has subscribed.

What happens if my URL is down?

SkoolKit tries again after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours and 24 hours, then stops and the delivery log says so. If every delivery fails for 72 hours, or your URL answers 410 Gone, the webhook is paused and you get an email. Switch it back on once the URL works; you can resend anything from the log for 30 days.

Which plan is it on?

Webhooks is a VIP tool.

Where does the data go?

Only to the URLs you enter, at your direction. What the receiving service does with it is governed by your agreement with it. The privacy policy has the detail.

Wire it up tonight

Webhooks comes with VIP, alongside every other SkoolKit tool. Open SkoolKit inside Skool, paste a URL, press Send test.