Licensing
HeadlessCore uses an open-core licensing model. The core codebase is MIT-licensed and works fully without a license key. A valid key unlocks pro features.
Free tier (no key required)
- All 8 site modes and demo layouts
- WPGraphQL schema, CPTs, contact form
- ISR, revalidation, preview mode
- CLI scaffold, Docker, documentation
- Footer shows:
POWERED BY WP-GRAPHQL & NEXTJS APP ROUTER
Pro tier (valid license key)
Currently unlocked with a valid key:
- Removes frontend attribution footer automatically
- White-label branding — custom brand name (replaces "HeadlessCore" in wp-admin menu, page titles, JSON-LD, and frontend chrome), custom wp-admin footer text, custom login-screen logo, and an option to hide WordPress version/links from wp-admin entirely. Configure under Headless Core → Settings → White-Label Branding.
- Pro Gutenberg blocks — CTA Banner, Pricing Table, FAQ Accordion,
Testimonial Slider, Team Grid, Stats Counter, Logo Cloud, Tabs,
Countdown Timer, Newsletter Signup, Contact Form, Image Gallery, Video
Embed, Comparison Table, Team Slider, Photo Album, Feature Grid,
Hero Banner, Steps, Callout, Icon List, and Magazine Category Grid blocks become insertable in
the editor.
Newsletter Signup and Contact Form are functionally wired to the real
subscribeNewsletter/submitContactFormmutations (via/api/newsletter-blockand/api/contact-block), not just static display. Content built with these blocks keeps rendering even if the license later lapses — only inserting new pro blocks requires an active key. - Pluggable search — Meilisearch/Algolia cross-content-type indexing (configure under Headless Core → Settings → Search).
- AI content tools — Claude/OpenAI SEO descriptions and image alt text from the post editor sidebar.
- CRM integration — HubSpot/Mailchimp push from contact form and newsletter submissions.
- Theme auto-updates — License-gated downloads via your Next.js URL (see Auto-Updates).
Purchasing a key no longer has to be manual — see Automated delivery via Stripe below.
Future pro features (planned):
- Priority support tier
How verification works
- License keys are RSA-2048 signed offline — no license server, no telemetry
- Public key ships in
functions.php(HEADLESSCORE_LICENSE_PUBLIC_KEY_PEM) - Private key is generated offline and never distributed — unless you opt into the Stripe integration below, which changes this specific guarantee
- WordPress verifies signature with
openssl_verify()on eachthemeSettingsGraphQL request - Result is cached in WordPress transients
Verification is always fully offline, regardless of which signing path you use — the section below only changes how (and where) keys are signed.
Generating keys (project owner only)
1. Generate keypair
node scripts/generate-license-keypair.js
Creates keys/ at the repo root (gitignored):
license-private.pem— keep secret, never commitlicense-public.pem— embed in theme or distribute
2. Issue a license key
node scripts/generate-license-key.js \
--tier=pro \
--customer="Acme Agency" \
--expires=2027-12-31
Output format: hc1.{base64url-payload}.{base64url-signature}
3. Activate in WordPress
Headless Core → Settings → Licensing → License Key
Paste the key and save. The status indicator shows:
- ✓ Active — tier: pro
- Free tier — no valid license key configured
GraphQL license fields
themeSettings {
license {
valid
tier
customer
expiresAt
}
brandName
}
Next.js reads license.valid in layout.tsx to conditionally hide the attribution footer.
brandName resolves to your configured brand name only when the license is
valid — otherwise it always resolves to "HeadlessCore", even if a brand
name is saved in WordPress. This is resolved WordPress-side (not just hidden
on the frontend) so a lapsed license can't leak a stale brand name through
the API.
Automated delivery via Stripe
The manual CLI flow above remains the lower-risk default — it's fully offline and never puts the signing key anywhere near a running server. Stripe-integrated delivery is opt-in and trades some of that isolation for automation. Full setup: Stripe Licensing.
The tradeoff, stated plainly: enabling this means the RSA private key
lives as LICENSE_SIGNING_PRIVATE_KEY_PEM, a server-only env var on your
Next.js deployment, read at request time inside /api/stripe-webhook to
sign new keys on the fly. This is a real, permanent change to the threat
model — before, minting a valid license required local/physical access to
the offline keys/ directory; with Stripe delivery enabled, compromising
your Next.js deployment's environment also compromises the ability to mint
valid licenses. Verification stays exactly as offline as before (the
public key + openssl_verify() path is unchanged) — only signing moves
online, and only if you deliberately set that env var.
If you'd rather not accept that tradeoff, skip the Stripe route and keep
using node scripts/generate-license-key.js manually — everything else in
this doc still applies.
Security properties
| Property | Detail |
|---|---|
| Offline verification | No network calls to license server |
| No telemetry | Key validation is local only |
| Tamper-resistant | RSA signature prevents forgery |
| Expiry support | Optional expiresAt in payload |
FAQ
Can I use HeadlessCore commercially without a key?
Yes. MIT license allows commercial use. Attribution footer remains unless you have a pro key.
What if my key expires?
Frontend reverts to free tier (attribution returns). Content and functionality are unaffected.
Can I self-issue keys?
Only if you generate your own keypair and replace the public key in functions.php.
Does automated (Stripe) delivery weaken the offline verification guarantee?
No — verification is still fully offline (public key, openssl_verify(), no network calls). Signing is no longer offline once you opt into the Stripe integration, since the private key then lives in a server-side env var. See Automated delivery via Stripe above.