License Store

Before you open your store

The License Store sells keys for your products using your vendor Stripe account. Create an internal product first, then configure payment credentials, the license issued after checkout, and the details shown to buyers.

Work through a test purchase before sharing the store. Confirm that checkout, payment webhooks, license delivery, invoice details, and cancellation behavior all match your sales model. Use matching Stripe test credentials throughout that test.

For your own PermitCore subscription and account exports, see Account & team. For license lookup and device self-service, see the Customer portal.

Licensing Features

License Store

The License Store lets your customers buy licenses directly from a branded public storefront — no coding required on your end. A customer account is required to check out (see "Customer Accounts" below); PermitCore hosts the checkout page and automatically creates a license key when payment succeeds, emailing the buyer a link to sign in and view it from their account rather than the key itself. You connect your own Stripe account, so revenue goes directly to you with 0% PermitCore commission.

PermitCore Store 2.0 public storefront

A Store 2.0 storefront at /store/{yourSlug} with vendor navigation, hero slides, editorial collections, search, and responsive layouts.

How it works

1
Connect your Stripe account
Go to License Store → Settings and paste your Stripe publishable key, secret key, and webhook secret. PermitCore uses your keys to create Stripe Checkout sessions — all payments flow directly to your Stripe account.
2
Create store products
Each store product links to one of your internal products. You set the display name, tagline, description, feature bullet list, image, pricing (one-time, monthly, or annual), and which license settings to create on purchase.
3
Auto-setup Stripe products (one click)
Click Auto-Setup Stripe Products in Store → Settings. PermitCore creates a Stripe Product and the correct Prices (one-time / monthly / annual) for every active store product in your Stripe account and saves the Price IDs back to the database. Idempotent — re-running skips prices that haven't changed. A progress bar and per-product result list confirm what was created or skipped.
4
Share your store URL
Your store is live at https://permitcore.dev/store/yourSlug. Add it to your website, email footer, or documentation.
5
Customer signs in, pays → key delivered instantly
Customer selects a product and pays via Stripe Checkout — signing in or creating an account first if they haven't already. PermitCore receives the webhook and auto-creates a license key within seconds, emailing a link to view it from their account.

Complete setup tutorial

Use this sequence for a new store. It separates payment setup, product fulfillment, presentation, and launch verification so each layer can be tested before customers see it.

1. Prepare the vendor account and Stripe

  1. Create the software product that the purchased license will belong to.
  2. Open License Store → Settings and enable the Store.
  3. Add Stripe publishable, secret, and webhook signing keys from the same Stripe mode: all test or all live.
  4. Add the vendor legal name, VAT number, default tax rate, and any country overrides used on invoices.
  5. Create the webhook shown below and enable every required event before accepting an order.
Do not mix Stripe modes. A test secret key with a live webhook or live Price ID cannot produce a valid end-to-end purchase. Complete one test-mode checkout first, then replace the entire credential set when going live.

2. Create the product customers will buy

  1. Open License Store → Products → Add Product and link the correct internal product.
  2. Write the public name, short tagline, card description, long product-page description, and up to six feature bullets.
  3. Upload a clear landscape cover image and, where useful, a product gallery. Every active product should have an image before launch.
  4. Choose one-time, monthly, and/or annual pricing and select the currency.
  5. Configure the generated license: activation count, node locking, expiry, trial days, and feature flags.
  6. Add an optional badge, CTA label, featured state, bundle contents, or free trial.
  7. Save, then use Auto-Setup Stripe Products in Store Settings to create missing Stripe Products and Prices.
Store 2.0 product page with gallery pricing trial and discount

The resulting product page combines a gallery, description, features, pricing choices, trial, discount disclosure, cart, and secure checkout.

3. Build the visual identity in Shop Designer

  1. Open License Store → Shop Designer.
  2. In Branding, set the store name, logo, primary/accent colors, text colors, page background color, and optional page background image.
  3. In Visual Style, choose the heading font, card density, hero height, corner style, and desktop product columns.
  4. Configure the default category-tile color or image. Then edit each visible tile—such as Featured, Special offers, Free trials, Bundles, or a product badge—to override its own background color or image. Select Use default to remove an override.
  5. Add hero slides with desktop-safe images, headline, supporting copy, CTA label, and a safe internal or HTTPS destination.
  6. Use the live preview at desktop, tablet, and phone widths before saving.

4. Compose the homepage

Under Homepage Sections, add the blocks that tell the product story. The section list is the published page order.

  1. Add a Featured spotlight for the strongest product story.
  2. Add horizontal shelves for offers, trials, bundles, badges, or products under a selected price.
  3. Add Category tiles for fast discovery and Discovery tabs for compact comparison.
  4. Keep a Product catalog so every active product remains searchable and sortable.
  5. Use the up/down arrows to reorder sections and the Visible switch to prepare a block without publishing it.
  6. Set Space above and Space below independently from 0–160 px. New sections start with a balanced 32 px top gap; reduce a gap when two related blocks should read as one group.
Store 2.0 category tiles shelves and discovery tabs

Collections, individually branded category tiles, and discovery tabs make a larger catalog easy to scan.

5. Configure offers without weakening checkout

  1. Open a Store Product and create a discount campaign with a name, percentage, label color, UTC start, and UTC end.
  2. Leave Show lowest price in the previous 30 days enabled when the disclosure is useful or required for the product and market.
  3. Preview the crossed-out regular price, colored percentage badge, campaign label, effective price, and 30-day comparison text.
  4. Test at least one cart and Stripe test checkout. The API—not browser state—selects the currently valid campaign and calculates the effective price.

6. Run the launch test

  • Check the homepage, product page, cart, sign-in, account, invoices, and license view on desktop and a real mobile viewport.
  • Buy one one-time item, start one trial, and test a recurring product if the store offers subscriptions.
  • Confirm the Stripe webhook creates exactly one order and license, even if Stripe retries the event.
  • Verify the issued license has the intended activation and feature settings.
  • Cancel a test subscription and confirm the linked license follows the configured lifecycle.
  • Review every product image, CTA, currency, tax rule, vendor invoice detail, and external link before switching to live Stripe credentials.
Store product editor with live preview

The Create Store Product form before entry, with display fields and a live preview. Pricing and generated-license settings continue below.

License Store admin management

A new Store before setup: Products, Orders, Settings, and Shop Designer. Add a product and configure Stripe before accepting purchases.

Auto-Setup Stripe Products

After creating your store products, click Auto-Setup Stripe Products in Store → Settings. PermitCore automatically creates the matching Stripe Products and Prices in your Stripe account and stores the Price IDs. You never need to copy-paste price_xxx IDs manually. Re-running the setup is safe — prices that haven't changed are skipped.

Store product settings

SettingDescription
Name & SlugDisplay name and URL identifier (e.g. /store/yourco/pro-edition)
Tagline & DescriptionShort marketing text shown on the product card
Long DescriptionFull marketing copy shown on the product detail page
Feature BulletsUp to 6 bullet points shown on the card and detail page (e.g. "Unlimited exports")
PricingOne-time, monthly, and/or annual prices. Set at least one. Currency selectable.
Stripe Price IDsAuto-filled by "Auto-Setup Stripe Products" button, or enter manually for recurring subscriptions managed directly in Stripe.
BadgeOptional label on the card (e.g. "Most Popular") with custom color
Generated licenseMax activations, node-locked, trial days, expiry days, feature flags — applied to every license created on purchase
FeaturedFeatured products are shown larger at the top of the store grid
Discount campaignSchedule a 1–90% discount with start/end time, campaign name and color. The server applies the effective price at checkout.
Lowest price disclosureOptional checkbox, enabled by default, showing the lowest applied price during the 30 days before the campaign started. Price history is recorded even when the label is hidden.

Shop Designer reference

Store → Shop Designer is organized as a visual page builder. Branding controls the shared visual system and full-page background; Visual Style controls typography, hero height, card density and desktop columns; Category Tiles adds per-tile artwork; Homepage Sections controls page order, content, visibility, and spacing.

SectionUse it forAvailable controls
Featured spotlightOne large editorial product story with a selectable rail.Title, subtitle, product filter, maximum items, visibility and order.
Horizontal shelfFast, touch-friendly browsing similar to a marketplace collection.All/featured/trial/bundle/badge/under-price filter and maximum items.
Category tilesShortcuts generated from featured items, offers, trials, bundles and product badges.Title, subtitle, visibility, order, shared fallback style, and a color/image override for each visible tile.
Discovery tabsCompact lists for popular products, offers, trials and bundles.Title, subtitle, maximum items, visibility and order.
Product catalogThe searchable and sortable card grid.Title, visibility, order and global products-per-row setting.

Every section also has independent Space above and Space below controls. Use the arrow controls to reorder sections and the Visible switch to prepare a section without publishing it. If the catalog is removed, PermitCore still adds a safe catalog fallback so products never become impossible to browse.

Discounts and the EU 30-day rule

PermitCore stores regular and promotional price events and calculates the comparison period from the 30 days immediately before a campaign starts. The promotional price itself is excluded, so it cannot become its own “lowest price.” Display and checkout use the same percentage and UTC schedule, but checkout always recalculates on the server.

Article 6a of the EU Price Indication Directive applies to goods. The European Commission guidance explicitly says it does not apply to services, including digital services and digital content. Software-license stores therefore get a configurable disclosure rather than automatic country enforcement; it defaults on for transparency. General rules against misleading promotions and any stricter local law still apply. See the official Commission guidance and obtain legal advice for your own product classification.

Store security and performance

  • Server-authoritative checkout: browser cart prices are display-only. The API reloads the active product, price type, campaign and tax before creating Stripe Checkout.
  • Payment boundary: card details are entered on Stripe Checkout. PermitCore stores encrypted vendor credentials and issues a paid license only after verifying the tenant-specific Stripe webhook signature.
  • Tenant isolation: store products, customers, orders, designs and price history are protected by tenant filters and PostgreSQL Row-Level Security.
  • Safe customization: colors, image URLs and slide links are validated; legacy rows are sanitized again on public read; Enterprise CSS blocks network loads and executable/breakout constructs.
  • Traffic resilience: public catalog/product responses use shared Valkey caching and dedicated browse rate limits; checkout and trial endpoints use stricter limits. Cache failure falls back to PostgreSQL.
  • Responsive storefront: grids collapse for tablets/phones, shelves remain horizontally scrollable, controls are touch-sized and reduced-motion preferences are respected.

Stripe webhook setup

In your Stripe Dashboard, create a webhook endpoint pointing to:

Webhook URL
https://api.permitcore.dev/api/store/webhook/yourSlug

Enable these events: checkout.session.completed, payment_intent.payment_failed, checkout.session.expired, customer.subscription.deleted

Copy the webhook signing secret and paste it into Store → Settings → Webhook Secret.

Monthly/annual licenses are revoked on cancellation.

If you sell a monthly or annual store product, PermitCore listens for customer.subscription.deleted and automatically deactivates the license when the customer's Stripe subscription ends — no manual revoke needed. Make sure this event is enabled on your webhook endpoint, or cancelled customers will keep an active license.

0% PermitCore commission. PermitCore does not charge a sales commission. Your payment processor's fees depend on your Stripe account, region, and payment method.

Tax & Pricing

PermitCore supports configurable tax rates at checkout — a default rate that applies to all countries, plus optional per-country overrides for any country in the world (not just EU). Tax is added on top of the product price and shown as a separate line in the cart.

SettingWhereDescription
Default tax rate (%)Store → Settings → TaxApplied when no country-specific rate matches. Set to 0 for untaxed by default.
Per-country ratesStore → Settings → Tax → Country overridesEnter a comma-separated list of CC:rate pairs, e.g. DE:19, AT:20, US:0. Supports all ISO 3166-1 alpha-2 country codes.
Country shown on PDPProduct detail pageWhen a non-zero tax rate is configured, the product detail page shows a "+X% tax may apply at checkout" notice.

At checkout, the customer selects their country from a dropdown. The cart immediately recalculates and shows a subtotal / tax / total breakdown. If the buyer later enters a valid EU VAT number, the tax drops to 0% (see B2B exemption below).

Country selection is optional — customers can still purchase without entering a country. When no country is selected, the default tax rate applies. Customers may browse and build a cart anonymously, but must sign in or register before checkout.

EU VAT B2B Exemption

When a business customer provides their EU VAT number at checkout, PermitCore validates it in real time via the VIES SOAP API (the official EU VAT Information Exchange System). If valid, the tax rate is set to 0% under the reverse-charge mechanism — the buyer accounts for VAT in their own country.

How it works at checkout:

  1. Buyer enters their country (EU member state) in the cart.
  2. A VAT number field appears for EU countries.
  3. Buyer enters their VAT number (e.g. DE123456789).
  4. PermitCore calls VIES in real time — validation result shown instantly.
  5. If valid: tax drops to 0%. The order is flagged VatExempt = true.
  6. The generated invoice includes a reverse-charge notice as required by EU law.
VIES validation has a 5-second timeout. If the VIES service is temporarily unavailable, validation is skipped and the buyer proceeds without exemption. The VAT number is still stored on the order for your records.

B2B Invoicing

PermitCore generates professional HTML invoices for every order that can be printed as PDF from the browser. Invoices include your vendor details, the buyer's details, a line-item breakdown, tax treatment, and a reverse-charge notice when applicable.

Setup: your vendor details

Before invoices are meaningful, add your company details in Store → Settings → Invoicing:

FieldDescription
Legal Company NameYour registered company name — printed as "Sold by" on every invoice.
Your VAT NumberYour own VAT registration number — printed on invoices for B2B compliance.

Cart fields collected from buyer

FieldRequiredDescription
Company NameOptionalPrinted on the invoice as "Buyer company". Leave blank for personal purchases.
CountryOptionalDetermines the applicable tax rate. Also printed on invoice.
VAT NumberOptional (EU only)VIES-validated. When valid, triggers reverse-charge (0% tax).

Accessing invoices

WhoHow
Admin Store → Orders → click Invoice next to any order. Opens in a new tab and auto-triggers the print dialog.
Customer My Account → Orders → click Invoice next to any order. Link uses a short-lived access token — no separate login required.
The invoice opens as a full HTML page and immediately calls window.print(). Use your browser's Save as PDF option in the print dialog to get a PDF copy. Keep a downloaded copy for your accounting records.

Customer Accounts (My Account)

A store account is required to buy anything — including a free trial. Browsing products and adding to cart needs no account, but the checkout/trial button always requires sign-in first: an unauthenticated buyer is prompted to sign in or register (returning straight back to the product/cart afterward) before payment even starts. This is deliberate, not a gap that got closed by accident — a purchase with nowhere to log into afterward had no way to ever see the key/activations again except contacting you directly. Accounts are per-store (each vendor's store has its own account system, distinct from the separate, always-anonymous Customer Portal).

Registration & Login

A Sign In button appears in the store header. Customers can register with name, email, password, and optional address. After registration, a verification email is sent automatically.

PageURLDescription
Login/store/{slug}/loginSign in with email + password. Includes "Forgot password?" link and a "Resend verification email" prompt if the account isn't verified yet.
Register/store/{slug}/registerNew account: name, email, password, country, address.
My Account/store/{slug}/accountTabs: My Orders (purchase history, invoices), My Keys (every license linked to the account — purchase date, expiry, activation/device list, "Add a license" to self-link one you hold the key for), Profile, Security.

Email verification

After registering, customers receive a verification link valid for 48 hours. Until verified, a yellow banner is shown in My Account with a Resend link — also reachable directly from the Login page's error message if a customer tries to sign in before verifying. Verification is not required to buy — sign-in alone is enough; verification is a separate, softer reminder shown after the fact.

Verification URL format
/store/yourSlug/verify-email?token=token

Forgot / Reset password

The login page has a Forgot password? link. The customer enters their email and receives a reset link valid for 1 hour. For security, the forgot-password endpoint always returns HTTP 200 regardless of whether the email exists (prevents email enumeration).

Reset URL format
/store/yourSlug/reset-password?token=token

What customers can do in My Account

TabFeatures
OrdersFull order history with product name, date, amount. Click Reveal Key to decrypt and display the license key. Click Invoice to open a printable invoice.
ProfileUpdate name, email, country, and address.
SecurityChange password. Email verification status badge + Resend button if not yet verified.
Browsing and cart building are anonymous; checkout is not. A customer signs in or registers before PermitCore creates a Stripe session or free trial. This lets the resulting order, key and device activations remain available in My Account without relying on an email address supplied by the browser.


Licensing Features

End-Customer Expiry Notifications

PermitCore can send expiry reminder emails directly to your end customer — not just to you as the admin. When a Customer Email is set on a license, that address receives branded reminder emails at 30, 7, and 1 day before the license expires, prompting the customer to renew.

Customer Email field in Edit Metadata modal

The Customer Email field in the Edit Metadata modal — set per license, completely optional.

How to set it up

  1. Go to Licenses → View → Edit Metadata
  2. Enter the customer's email in the Customer Email field
  3. Save — the email will be used for all future expiry notifications for this license

Setting a Customer Email does not replace admin notifications — admins still receive their daily digest. This is an additional, per-license notification that goes directly to the end user.

The customer email

The email sent to the customer:

  • Is delivered using the instance's configured mail provider
  • Shows your company name as the sender — PermitCore is not mentioned
  • Includes the product name, expiry date, and days remaining
  • Asks the customer to contact you to renew
Use case: You sell annual desktop app licenses. Instead of customers manually tracking expiry dates, PermitCore sends them a reminder 30 days before expiry — giving them time to renew before their software stops working.


Licensing Features

Reseller Portal

The Reseller Portal lets you invite partner companies or distributors to issue licenses on your behalf. Each reseller gets their own login and can create licenses only for the products you authorize — with optional caps on how many they can issue.

Available on the Enterprise plan.
Resellers admin page

The reseller invitation form before submission. Choose product access and configure the partner before sending the invitation.

How it works

  1. Go to Resellers in the sidebar and click Invite Reseller
  2. Enter the reseller's name, email, and a temporary password
  3. Select which products they can sell and optionally set a max license count per product
  4. The reseller logs in with their credentials and creates licenses from their own dashboard
  5. New live activations of reseller-issued keys count against your monthly activation allowance; creating the key itself does not consume an activation

Reseller permissions

Can doCannot do
Create licenses for assigned productsAccess products not assigned to them
View their own created licensesSee other users or company settings
View order/activation counts for their licensesAccess billing or payment settings
Generate up to their per-product capExceed the license cap set by you

Managing resellers

From the Resellers page you can:

  • Deactivate a reseller — immediately blocks their login without deleting their account or the licenses they've created
  • Adjust product access — add or remove products, change the license cap
  • Monitor issuance — see how many licenses each reseller has created per product
Use case: You have a desktop app sold through 3 regional distributors. Each distributor gets a Reseller account with access to the relevant product. You cap each at 100 licenses. They log in, generate license keys for their customers, and you see all activations in your analytics dashboard.

Commission tracking

When you invite a reseller, you can set a commission percentage per product (0–100%). Every order placed through a reseller link automatically records the commission amount at the time of sale — so changing the rate later does not retroactively affect existing orders.

  1. Go to Resellers → Invite Reseller and enter a commission % for each product.
  2. When a customer purchases through a reseller link, the order records ResellerId, CommissionPercent, and the computed CommissionAmount.
  3. Open the Commissions tab on the Resellers page to see all pending and paid commissions grouped by reseller.
  4. Select one or more orders and click Mark as Paid to record payment. The system logs CommissionPaidAt and updates the reseller's running total.
FieldDescription
CommissionPercentRate set per reseller × product pair (snapshot taken at sale time)
CommissionAmountPre-computed: OrderTotal × CommissionPercent / 100
TotalEarnedRunning total of all commission amounts ever assigned
TotalPaidRunning total of commissions marked as paid
Unpaid balanceTotalEarned − TotalPaid — shown in the Commissions tab
Commission percentages are snapshots — captured at the moment of purchase. You can update a reseller's rate at any time without affecting historical orders. Resellers can view their own earned and unpaid totals via the self-service summary endpoint.