Your checkout doesn't change. What changes is who grants access.
Mentorflix doesn't enter the flow of money — it enters the flow of access: your gateway's webhook arrives, the package is resolved, and the student gets access traced back to the transaction id.
The subscription has a fixed monthly price, and nothing is charged per sale.
You keep selling where you already sell. This is where the student comes in.
Your sales page works. Your checkout already converts. Your traffic is calibrated on top of it. What hurts isn't the sale — it's the percentage the hosting platform takes out of each one, every month, to serve video.
Mentorflix doesn't ask you to change that. It doesn't replace your gateway, doesn't create your sales page, and doesn't sit in the middle of your money. You sell on Hotmart, Kiwify, Eduzz, Monetizze, Mercado Pago, Stripe, or your own checkout. The money lands where it lands today, on your timeline, in your account, at your gateway's rate.
What comes in here is the sale notice. Your gateway fires a webhook, the platform verifies the signature, resolves what that product unlocks, and grants access to the student. One track for the money, another for access. Mentorflix only exists on the second one.
The math is a fixed subscription price per month, and nothing per sale. Where a percentage does exist inside the product — because one does — is written at the end of this page.
The platform doesn't touch your money. It receives notice that the sale happened, and stops there.
One address, seven readers, one verified signature
Each integration gets its own address: POST /api/webhooks/receive/<key>. The key identifies the integration and nothing more — on its own, it isn't the security control. The signature is.
Each provider has a reader written for its own format, and each reader checks the signature the way that provider signs it. Hotmart accepts two forms: the static token in the X-Hotmart-Hottok header, or HMAC-SHA256 in X-Hotmart-Signature. Kiwify signs with HMAC-SHA1 in the X-Kiwify-Signature header. Eduzz, with HMAC-SHA256. Monetizze doesn't sign in the header: it sends the shared key inside the body, in the key field, and the comparison runs against the endpoint's secret. Stripe signs the timestamp+body pair and the comparison accepts up to 5 minutes of clock drift. Mercado Pago builds the id;request-id;ts manifest from the headers and the body, and accepts up to 10 minutes. Every comparison runs in constant time, over the raw body, byte by byte, without re-serializing the JSON.
Anyone not using one of the six uses the generic receiver: you point, in dot notation, to where the email, the name, the transaction id, the event name, and the SKU sit inside your JSON, and the signature is HMAC-SHA256 in the header you choose.
The response contract is deliberately boring: 200 for everything — unknown endpoint, disabled integration, unmapped event, unrouted product — and 401 only when the signature doesn't match. No gateway ends up in a retry queue because one of your products hasn't been mapped yet.
The key in the address only identifies the integration. What protects the door is the verified signature, and nothing beyond it.
Gateway product, package here. And the category rule absorbs the course that doesn't exist yet.
The sale notice arrives with one or more product ids. They need to turn into unlocked content. Between the two sits the package.
A package is built from rules, not a fixed list. A rule can be a course, a track, or an entire category. Each rule includes or excludes, and the exclusion is applied after the inclusion — meaning it always wins. You can sell "everything in Marketing except the intensive" without duplicating the catalog. The category rule has two modes. Switched on to "include future courses," it's resolved at the moment of purchase and returns every published course in that category: you launch a new course inside it, and whoever buys afterward already gets it. Switched off, it freezes the course list at the moment the rule was created, and it doesn't change again.
Routing has two layers. With the product→package map turned on, the id that came in the payload decides which package to unlock — a single endpoint can serve an entire catalog. Without a map, or when no id matches an active mapping, the endpoint's fixed association applies. If nothing matches, the event is logged as unrouted, the purchase is recorded, and no access is granted by mistake.
The same package feeds the internal showcase: an external-type offer points to your own checkout URL and expands, at click time, the {userId}, {email}, {name}, {bundleId}, and {returnUrl} placeholders, each with URL escaping. The student leaves here already identified on your gateway, and comes back the same way.
If no id matches an active mapping, nothing is unlocked: the purchase is recorded as unrouted and the event ends there.
Between payment and first access
There are two paths, and they end differently.
When the purchase starts inside the community, the student clicks the offer, your checkout opens in another tab, and they land on a waiting screen. That screen asks the server, every 4 seconds, whether access has gone out yet. As soon as the gateway's webhook arrives and access is granted, the screen detects it and takes the student straight to the destination: the course, if the package resolves to just one; the track, if it resolves to just one; the products area, when it's a seller delivery. Polling pauses if the tab is in the background and gives up after 20 minutes, offering to reopen the checkout instead of spinning forever.
When the purchase happens outside — on your sales page, in your funnel, on your ad link — the student was never logged in here. The webhook arrives with their email. If an account with that email already exists in the community, access is attached to the existing account. If it doesn't exist, the account is created on the spot, with the name that came in the payload and a random password no one knows — including us.
And here's the limit, stated plainly: the platform doesn't send a welcome email at that moment. There's no automatic credential dispatch on webhook-triggered access. First access is your communication's responsibility: the email you already send after the purchase, with the community's address and the instruction to set a password through "forgot my password." The dashboard also generates a reset link per student, and returns that link to the admin even when email sending isn't configured, so you can resolve a case by hand.
What happens on its own is the rest: beyond the course and the track, the student is automatically added to the private spaces linked to that course whose link is active and has automatic release turned on. The entry is tagged with its origin — the course access that produced it — and the student gets an in-platform notification about the new space.
The platform doesn't send the first-access email. That email is yours.
Every access knows where it came from. Reversal uses that.
Each grant carries three marks: the origin (webhook), which integration produced it, and the transaction id on the gateway.
When a refund, cancellation, chargeback, or subscription-end event arrives, the system deactivates only the access that integration granted — the query filters by origin and by endpoint id before changing any row. Access you granted by hand, or that came from another package, isn't touched. The purchase is recorded with the correct state, derived from the event name: chargeback, canceled, expired, or refunded.
Access with an expiration has an hourly checker: a routine walks through course and track access that has already come due, changes the state to expired, and triggers removal from the linked spaces configured for that. What fills in that expiration date today is the Hotmart reader, which reads the subscription's next billing date and records it as the access's validity. The other six readers don't extract an expiration date from the payload — for them, validity stays blank and access doesn't expire on its own.
A repeated event doesn't turn into duplicate access. The key is provider + transaction + event type, protected by a Postgres lock inside the transaction and by a uniqueness constraint in the database: a gateway resend gets a 200 and doesn't do anything twice.
When something fails, the event is recorded whole. Each event turns into a record with the full payload, the state, the email, the transaction id, whether the signature checked out, the headers filtered through an allowlist, and how long processing took — searchable by transaction id. You can reprocess an old event with one click, after fixing the map. You can fire a test event, choosing the type and the destination email, before you announce anything. You can turn on sandbox mode, which logs everything and grants nothing. And there's a health panel per integration: events in the last 24 hours, error rate, p95 latency, and last event received, with the integration marked as degraded when the error rate exceeds tolerance and as down when most events fail.
Validity only exists when the gateway sends the next billing date. Today only the Hotmart reader sends it — for the other six, access has no expiration and doesn't expire on its own.
Where a fee exists — and where the platform stops
There is a percentage in the product. It doesn't touch your sale.
It lives in the marketplace: when a member of your community sells something to another member, the payment runs through the platform, with a seller account on Stripe Connect. In that case, and only that one, the platform retains a slice of the gross, and your community keeps the commission you set, within the limit the system accepts. The seller absorbs the Stripe fee. A service offer goes into escrow until the buyer confirms, with disputes arbitrated by you. That's a different flow, a different offer type, and different code: when the sale is external, the system just expands your checkout URL, and no internal sale is created.
Now what the platform doesn't do, so you don't find out later.
It doesn't process payment on your sale. It doesn't generate a charge, doesn't split into installments, doesn't bill recurring payments, doesn't split revenue, doesn't issue an invoice, and doesn't handle the financial side of a chargeback — that stays with your gateway.
It doesn't recover sales. There's no abandoned-cart sequence and no past-due subscription billing; what exists is reading whatever your gateway decides to report.
It doesn't report revenue. Each purchase is recorded with amount, currency, and state, and shows up in the student's profile. There's no revenue dashboard: the platform's analytics cover growth, engagement, retention, content, and gamification, not sales.
Buying inside the community requires an account. The course showcase can be shown to visitors, depending on the visitor mode configured in the community, but the offer catalog and the checkout button require a signed-in user — whoever buys through your external funnel doesn't have that limit.
And one setting we won't pretend is automatic: an integration with no signing secret configured starts accepting events without verification, and that's logged in the event record. Generating the secret and pasting it into the gateway's dashboard is your step, and it's the one that matters.
The platform stops at access. Billing, installments, invoices, sale recovery, and revenue reporting stay on your gateway's side.
Continues in
The webhook grants access. What that access unlocks — nine lesson types, tracks with date-based release, classes and certificates: 02 · Courses →
The first-access email is yours. Which sender it goes out from today, and what changes when you turn on your own SMTP: 06 · Brand and infrastructure →