You’ve built an AI copywriter, an image generator, an SEO analyser, or a conversion rate tool. Subscribers pay monthly and receive a credit allowance: 100 AI generations or 50 site audits per month. When they run out of credits, they can’t generate more until the next billing cycle. When they cancel, their credit access ends entirely.
The license key for subscription model handles the access layer cleanly. Vandly generates a unique key when someone subscribes and emails it to them. Your website validates the key on each session or each credit-consuming action. When the subscription lapses, Vandly revokes the key. The next validation returns invalid and access is blocked without any action from you.
This article covers the full integration: how to set it up in Vandly, how to validate the key in a web app, how to combine key validation with your credit system, and what to do after setup to make it production-ready.
The Use Case: Website Credits
A website credit system typically works like this: subscribers pay for a plan that includes a monthly credit allowance. Each action they take (generating content, running a scan, exporting a file) consumes one or more credits. When the allowance is exhausted, they’re blocked until it resets or they upgrade.
The license key for subscription model handles the subscription gate, confirming the user has an active plan. Your own database handles the credit balance. Together, they give you a complete access control system with minimal infrastructure:
| Layer | Handled By |
| Subscription access gate | Vandly license key validation, one API call confirms the key is active |
| Credit balance | Your database, you store and decrement credits per action |
| Credit reset | Triggered by currentPeriodEnd from the key validation response |
| Access revocation | Vandly revokes the key automatically on cancellation or payment failure |
You don’t need webhooks to make this work. The currentPeriodEnd field in a valid key response tells you when the current billing period ends, use it to reset credits on the client or server side without needing to receive a renewal event. If you want real-time renewal handling, you can add a webhook alongside the key validation, but it’s not required.
How to Set Up a License Key Subscription Product on Vandly
Setting up a license key for subscription product in Vandly takes 5 steps in the product wizard.
Step 1: Product Type
From the Products page, click + New Product. On the Create New Product screen:
- Under ‘How will customers pay?’, select Subscription
- Under ‘How do you want to manage subscriber access?’, select License key. Vandly generates a unique license key for each purchase, no extra setup needed
No URL or server configuration required for the access method. Vandly handles key generation and email delivery automatically.
Step 2: Details and Pricing
- Product Name: e.g. ‘ContentAI Pro’ or ‘SiteAudit Monthly’
- Description: describe the credit allowance per plan: how many credits, what each credit does, what happens when credits run out
- Category: select the category that best fits your tool
- Billing model: Recurring (monthly and/or yearly) or Lifetime
- If Recurring: check Monthly, Yearly, or both and set prices for each
- If Lifetime: set the price for customers pay once and keep access forever
- Delivery Method — Email Delivery (the license key is sent in the purchase confirmation email)
Step 3: Policy
Vandly auto-configures three subscription policies:
- Refund Policy: No Partial Refunds — subscribers can cancel anytime; access continues until the end of the current billing period
- Access Duration: Active Subscription — access ends automatically if a renewal fails or the subscription is canceled
- Delivery Failure Policy: A new license key is issued automatically on every successful renewal. If a key fails to arrive, Vandly’s support team will resend it or issue a replacement
No action needed. Click Next.
Step 4: Additional Information
- Previous Platform URL: if you’ve sold this tool elsewhere
- Demo Link: link to a live demo of your tool
- Embedded URL: iframe-friendly preview URL if available
- Expected Monthly Sales: helps Vandly optimise your product page
Step 5: Review and Confirm
- Confirm product name, price, and billing model are correct
- Delivery Information: Delivery Method: Email, Access Duration: Subscription
- Pricing & Policy: Fulfillment shows Subscription · License key
- Tick all three confirmations: No illegal or harmful content, Accurate information, I own the rights
- Click Save Changes to submit for review
After approval, go to Product Details > Overview & Settings. Configure your Payment Link to generate the checkout URL to share with subscribers. The Subscriptions tab shows all active subscribers and a Show License Keys button to view and look up individual keys for support.
How Validation Works in a Web App
Unlike plugins or desktop apps, a web app has a backend. That backend is the right place to validate the license key for subscription. Keep validation server-side so the key and the API response never touch the browser.
Where the key lives
When a subscriber activates their account, ask them to enter their license key. Store it in your database against their user record, not in localStorage or a cookie. Every subsequent request that consumes a credit validates the key server-side before proceeding.
The validation request
// Server-side — Node.js / Express example async function validateLicenseKey(key) { const res = await fetch(“https://api.vandly.co/license-keys/validate”, { method: “POST”, headers: { “Content-Type”: “application/json” }, body: JSON.stringify({ key }), }); return await res.json(); } app.post(“/api/generate”, requireAuth, async (req, res) => { const user = await db.users.findById(req.user.id); // 1. Validate subscription const license = await validateLicenseKey(user.vandlyKey); if (!license.valid || license.productId !== YOUR_PRODUCT_ID) { return res.status(403).json({ error: “subscription_required” }); } // 2. Check credit balance if (user.creditsRemaining <= 0) { return res.status(403).json({ error: “no_credits” }); } // 3. Decrement credits and perform action await db.users.decrement(user.id, “creditsRemaining”, 1); const result = await runAction(req.body); return res.json({ result }); }); |
Always check productId, not just valid. The endpoint returns valid: true for any active Vandly key. Without the productId check, a subscriber from a different Vandly product could access your tool.
Resetting Credits on Renewal
Credits need to reset at the start of each new billing period using currentPeriodEnd.
The currentPeriodEnd field in a valid key response tells you when the current period ends. Store it alongside the user’s credit balance. On each validation, compare the stored period end to the one in the response, if it’s changed, a renewal has occurred and you should reset credits.
const license = await validateLicenseKey(user.vandlyKey); if (license.valid) { const newPeriodEnd = license.currentPeriodEnd; // If the period has rolled over, reset credits if (newPeriodEnd !== user.currentPeriodEnd) { await db.users.update(user.id, { creditsRemaining: MONTHLY_CREDIT_ALLOWANCE, currentPeriodEnd: newPeriodEnd, }); } } |
Validation Response Fields
| Field | What It Tells You |
| valid | true if the key is active right now. Gate all credit-consuming actions on this. |
| status | active, revoked (canceled or lapsed), or expired. Only present when valid is true. |
| productId | The Vandly product this key belongs to. Always verify it matches your product ID. |
| productName | The name of the product on Vandly. |
| currentPeriodEnd | When the current billing period ends in UTC. Use to detect renewals and reset credits. |
Error Messages by Failure Case
Return clear, actionable errors from your API so the frontend can show the right message:
| What Happened | What to Show the User |
| valid: false, status: revoked | “Your subscription has ended. Renew at [your site] to restore access and credits.” |
| valid: true, wrong productId | “Your license key is not valid for this product.” |
| valid: false (no status) | “License key not recognised. Check your purchase confirmation email.” |
| creditsRemaining: 0 | “You’ve used all your credits for this period. They reset on [currentPeriodEnd date].” |
| Network error on validation | “Could not verify your subscription. Please try again in a moment.” |
What to Do After Setup
1. Decide where and how often to validate
For a credit-based tool, the right validation points are:
- On sign-in: confirm the user has an active subscription before showing the app
- Before each credit-consuming action: prevent a revoked key from consuming credits
- On the credits display: show live subscription status alongside remaining credits
Validating before every action adds a small latency overhead per request. If that’s a concern, validate on sign-in and cache the result for the session, then check credits only per action, and re-validate the subscription at session start the next time the user logs in.
2. Show credits and renewal date in the UI
Use the currentPeriodEnd from a valid response to show subscribers when their credits reset. This reduces support requests and churn:
const periodEnd = new Date(license.currentPeriodEnd); const formatted = periodEnd.toLocaleDateString(“en-US”, { month: “long”, day: “numeric” }); // e.g. “You have 43 credits remaining. They reset on August 25.” showCreditsDisplay(user.creditsRemaining, formatted); |
3. Test all scenarios before launch
| Test Scenario | What to Verify |
| Valid key, correct productId, credits available | Action runs, credit is decremented |
| Valid key, correct productId, zero credits | Action blocked, reset date shown |
| Valid key, wrong productId | Action blocked with subscription error |
| Revoked key | Action blocked, renewal message shown |
| currentPeriodEnd changed (renewal detected) | Credits reset to monthly allowance |
| End-to-end: subscribe, receive key, activate, use credits | Full flow works in production |
4. Use the Subscriptions tab for support
When a subscriber says their credits didn’t reset or their key isn’t working, go to Product Details > Subscriptions tab > Show License Keys. Look up their key status, active or revoked, without writing any code. If the key is active but your app shows an error, check your productId logic and your credit reset detection.
5. Handle the activation flow clearly
When a new subscriber arrives on your site, they need to know where to find their key and how to enter it. The key is in the purchase confirmation email from Vandly. Your activation screen should:
- Include a text input labelled ‘License key from your purchase email’
- Show a ‘Check your Vandly purchase confirmation email’ prompt
- On successful validation, store the key server-side and redirect to the app
- On failure, show the specific error (revoked vs invalid vs wrong product) so the user knows what to do next
Frequently Asked Questions
Do credits carry over to the next billing period?
That’s your policy to define. Vandly doesn’t manage credit balances. If you want credits to expire at period end, reset them when currentPeriodEnd changes. If you want them to roll over, accumulate instead of resetting.
What happens to a user’s credits when their subscription is canceled?
Vandly revokes the key automatically. Your next validation returns valid: false. At that point, block any further credit-consuming actions. Whether you retain the remaining credit balance in your database is your decision, most tools clear it on cancellation.
Can a user share their license key with others?
The validation endpoint doesn’t track who is using the key or from where. If you need to limit a key to one user, enforce that on your side. For example, by storing the key against a specific user account and rejecting validation requests from any other account using the same key.
Do I need webhooks as well as license key validation?
Not necessarily. For most credit-based tools, detecting renewal via currentPeriodEnd change is sufficient. Add a webhook only if you need credits to reset at the exact moment of renewal, rather than at the user’s next sign-in.
How do I handle a subscriber who upgrades to a higher plan mid-month?
Vandly would generate a new subscription with a new key for the higher plan. Handle it as a new subscription.created event if you’re using webhooks, or detect the productId change during validation and update their credit allowance accordingly.
Where do I find my productId?
It appears in your product’s URL on Vandly and in the productId field of a valid validation response. Hard-code it on your server, it doesn’t change.
Start selling credit-based subscriptions on Vandly → Your first sale is free.
Need real-time renewal handling with server-side events? See Webhook for SaaS Subscription: SaaS Use Case Guide.
