Compare commits

...

10 Commits

Author SHA1 Message Date
Grant b253b7bacf Social share image: replace old key-thumbnail with current scroll mark + KEYSAT wordmark
The previous og:image (assets/keysat-thumbnail.png) showed an older
brand asset — a small key icon next to "KEYSAT" in a serif-ish
typeface — that no longer matches the site. iMessage / Slack / X
were rendering that old card, creating a mismatch between what people
clicked and what they landed on.

New asset: assets/keysat-social.svg (1200x1200 source) +
assets/keysat-social.png (1200x1200 rendered). Cream brand
background, current scroll mark centered, "KEYSAT" wordmark in the
Manrope-style spacing the lockup uses, gold "SELF-HOSTED LICENSING
SERVER" tagline beneath. og:image + twitter:image on both
index.html and support.html now point at the new asset; width/height
attributes updated to 1200.

Old assets/keysat-thumbnail.png left in place — harmless, and the
1.7MB file was only referenced from the meta tags this commit
rewires, so no broken links elsewhere.
2026-05-14 14:03:40 -05:00
Grant 5a9ede9247 Landing + support: add Open Graph + Twitter Card meta tags
Pasting keysat.xyz into iMessage / Slack / Discord / X was falling
back to just the <meta name=description> tag (which truncated mid-
sentence and showed no image). Add proper og:* and twitter:* tags so
the share card uses the hero copy + the existing 1024×1024
keysat-thumbnail.png as the social image. Same treatment on support.html
with its own title/description.

Also update the homepage meta description to match the hero copy
verbatim so the on-page lede and the share-card description tell the
same story.
2026-05-14 13:51:23 -05:00
Grant f6b85bdcdb Landing + support: remove ~21 em-dashes across copy
Same pattern set used on the docs site (elaboration→period, list-intro→colon, tight clarification→comma). The decorative "— Certificate of License —" stamp ornament in the artwork section stays verbatim.
2026-05-12 09:26:16 -05:00
Grant 69d4d69d0c Tier cards: add navy-pill buy CTAs per policy
Each live tier card now ends in a navy-950 pill linking to
licensing.keysat.xyz/buy/keysat?policy=<slug>. margin-top:auto on
the CTA anchors it to the bottom of each card so buttons line up
across tiers of different heights.
2026-05-12 00:28:18 -05:00
Grant 8d41e42eef footer: link to /license page; clarify daemon source-available + SDKs MIT 2026-05-11 21:51:56 -05:00
Grant 3eb8ea5129 "Limited" → "Limited discount" on launch-special meta
Matches buy page (v0.2.0:37). Disambiguates the limit so buyers
don't read it as a license-count cap.
2026-05-11 18:36:37 -05:00
Grant fcfbb95354 Launch-special remaining: drop the total
Dynamic tier-card JS now renders "Limited: N remaining" instead of
"Limited: N of M remaining". Matches the buy page (v0.2.0:36); the
operator's initial launch volume stays private.
2026-05-11 18:30:46 -05:00
Grant a8a0e39fe0 Landing pricing: delete sovereign section, dynamic tier cards, FAQ fix
Pricing section overhaul:
- Delete the "Sovereign by default / Everything stays on your
  hardware" section (left + right panels weren't really telling
  one story, and the lede repeats what the hero already says).
- Tier intro: drop the dense self-license framing; keep just
  "Every Keysat instance ships at a highly functional Creator
  tier; pay only when you outgrow it."
- Drop the "No fake feature gates" trailing blurb.
- FAQ tier-difference answer: reflect Patron as a perpetual
  license + direct 1:1 support (not just "Pro with a badge").

Tier cards now render LIVE from the master Keysat:
- On page load, fetches /v1/products/keysat (for the entitlements
  catalog) and /v1/products/keysat/policies (for the tier list),
  then re-renders #tier-grid-live with the operator-configured
  data — prices, marketing bullets, hidden-entitlement filter,
  and any active featured (launch-special) discount applied.
- Matches the buy page's visual treatment: diagonal LAUNCH SPECIAL
  ribbon, struck-through original price, discounted headline
  price, "Limited: N of M remaining" meta line. Single source of
  truth between landing and /buy.
- Static markup stays as a graceful fallback when the fetch fails
  (offline, daemon down, CORS hiccup). The script only mutates
  the DOM on a successful response from both endpoints.
2026-05-11 17:54:06 -05:00
Grant d36de2c501 Agent CTA points at docs.keysat.xyz/agent.html
The agent integration guide is now a first-class page on the docs
site rather than a raw markdown link on GitHub. Cleaner UX (docs
chrome + sidebar nav + on-this-page toc), no more punting visitors
out to GitHub's markdown renderer.
2026-05-11 17:48:59 -05:00
Grant a9f8162473 Value-grid reorder + testimonial timeframe + sideload back to GH releases
- Value-grid: top row now starts with the key-ownership pitch
  (signing key → offline verification → sell however you want).
  Renamed and rewrote the prior "Bitcoin payments, your store" box
  to "Payment channels you control" and moved it to the bottom-left.
- SeasonsOfLearning testimonial: tightened the timeframe from
  "October → January" to "over a weekend → two weeks later" so the
  speed-to-launch story lands harder.
- Sideload link points at github.com/keysat-xyz/keysat/releases/latest
  now that the repo is public. files.keysat.xyz stays as the
  canonical s9pk host for the StartOS registry's package-add URL.
2026-05-11 17:36:10 -05:00
4 changed files with 322 additions and 72 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

+39
View File
@@ -0,0 +1,39 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 1200" fill="none">
<!-- Cream brand background. Same #FBF9F2 used everywhere on the
landing page; keeps the social card visually consistent with
the site a visitor lands on after clicking. -->
<rect width="1200" height="1200" fill="#FBF9F2"/>
<!-- Scroll-style brand mark, centered horizontally, sitting in the
upper third so the wordmark below reads as the focal pairing.
The mark is the same construction as keysat-mark.svg, just
translated + scaled so its 100x100 source viewBox occupies a
420x420 area starting at x=390, y=260. -->
<g transform="translate(390,260) scale(4.2)">
<ellipse cx="50" cy="22" rx="28" ry="5" fill="#1E3A5F"/>
<rect x="22" y="22" width="56" height="56" fill="#FBF9F2" stroke="#1E3A5F" stroke-width="3"/>
<ellipse cx="50" cy="78" rx="28" ry="5" fill="#1E3A5F"/>
<line x1="32" y1="36" x2="68" y2="36" stroke="#1E3A5F" stroke-width="1.5" stroke-linecap="round"/>
<line x1="32" y1="44" x2="62" y2="44" stroke="#1E3A5F" stroke-width="1.5" stroke-linecap="round"/>
<circle cx="42" cy="60" r="6" fill="none" stroke="#BFA068" stroke-width="2.5"/>
<rect x="48" y="58.5" width="14" height="3" fill="#BFA068"/>
<rect x="58" y="61.5" width="2" height="4" fill="#BFA068"/>
<rect x="62" y="61.5" width="2" height="3" fill="#BFA068"/>
</g>
<!-- "KEYSAT" wordmark in Manrope (with sans-serif fallbacks for
renderers that lack the typeface). Letter-spacing tuned to
match the lockup's wide tracking; size sized so the wordmark
is the second focal element, balanced against the mark above. -->
<text x="600" y="900" text-anchor="middle"
font-family="Manrope, Inter, system-ui, sans-serif"
font-weight="500" font-size="140" letter-spacing="34"
fill="#1E3A5F">KEYSAT</text>
<!-- Tagline beneath the wordmark, a touch of gold to echo the
brand accent without competing with the wordmark itself. -->
<text x="600" y="970" text-anchor="middle"
font-family="Manrope, Inter, system-ui, sans-serif"
font-weight="500" font-size="28" letter-spacing="6"
fill="#BFA068">SELF-HOSTED LICENSING SERVER</text>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

+265 -69
View File
@@ -3,8 +3,26 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Keysat Bitcoin-native self-hosted licensing service for software creators</title>
<meta name="description" content="Keysat is a Bitcoin-native, self-hosted licensing service for software creators. Runs on Start9. Pays in Bitcoin or fiat. Verifies offline. You own the signing key, the customer list, and the payment rails.">
<title>Keysat: Bitcoin-native self-hosted licensing service for software creators</title>
<meta name="description" content="Keysat is a self-hosted licensing server. Buyers pay you for the software you create, and their license can be verified offline. Your licensing key, customer list, and payment rails all live on your hardware. No SaaS, no middleman, no platform risk.">
<!-- Social sharing (Open Graph + Twitter Card). Used by iMessage,
Slack, X/Twitter, Facebook, LinkedIn, Discord, etc. when someone
pastes a keysat.xyz link. Description tracks the homepage hero
copy so the share card and the landing page tell the same story. -->
<meta property="og:type" content="website">
<meta property="og:site_name" content="Keysat">
<meta property="og:title" content="Keysat: Bitcoin-native self-hosted licensing service for software creators">
<meta property="og:description" content="Keysat is a self-hosted licensing server. Buyers pay you for the software you create, and their license can be verified offline. Your licensing key, customer list, and payment rails all live on your hardware. No SaaS, no middleman, no platform risk.">
<meta property="og:url" content="https://keysat.xyz/">
<meta property="og:image" content="https://keysat.xyz/assets/keysat-social.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="1200">
<meta property="og:image:alt" content="Keysat — self-hosted licensing server">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Keysat: Bitcoin-native self-hosted licensing service for software creators">
<meta name="twitter:description" content="Self-hosted licensing for software creators. Buyers pay you for the software you create; licenses verify offline. You own the signing key, the customer list, and the payment rails.">
<meta name="twitter:image" content="https://keysat.xyz/assets/keysat-social.png">
<link rel="icon" type="image/svg+xml" href="assets/favicon.svg">
<link rel="preconnect" href="https://fonts.googleapis.com">
@@ -334,6 +352,43 @@ pre.code .p { color:rgba(245,241,232,0.55); }
content:'\2713'; position:absolute; left:0; top:0;
color:var(--gold-700); font-weight:700;
}
/* Launch-special discount treatment on the live tier cards. Matches
the buy page's diagonal ribbon + slashed-price visual so the
landing page and the buy page tell the same pricing story. */
.tier-card.has-launch {
position:relative;
clip-path:polygon(0 -20px, 100% -20px, 100% 100%, 0 100%);
}
.tier-launch-ribbon {
position:absolute; top:14px; right:-44px;
background:var(--gold-500); color:var(--navy-950);
font-family:var(--font-display); font-weight:700; font-size:10.5px;
letter-spacing:0.14em; text-transform:uppercase;
padding:4px 50px; transform:rotate(35deg);
box-shadow:0 2px 6px rgba(14,31,51,0.15);
z-index:2; pointer-events:none;
}
.tier-launch-meta {
font-size:11.5px; color:var(--gold-700); font-weight:600;
margin-bottom:6px;
}
.tier-price-original {
font-family:var(--font-display); font-weight:500; font-size:14px;
color:var(--ink-500); margin:0 0 4px;
text-decoration:line-through; text-decoration-color:rgba(14,31,51,0.4);
}
.tier-card .tier-features-list { margin-top:4px; }
.tier-card .tier-buy-cta {
display:block; margin-top:auto;
align-self:stretch; text-align:center;
padding:12px 22px; border-radius:999px;
background:var(--navy-950); color:var(--cream-50);
font-family:var(--font-display); font-weight:600; font-size:14px;
letter-spacing:-0.005em; text-decoration:none;
transition:background 100ms;
}
.tier-card .tier-features-list { margin-bottom:18px; }
.tier-card .tier-buy-cta:hover { background:var(--navy-800); }
/* ---------- Install ---------- */
.install-grid { display:grid; grid-template-columns:1fr 1fr; gap:24px; }
@@ -570,7 +625,7 @@ footer.site .bottom a { color:rgba(245,241,232,0.6); }
<div class="eyebrow">Software licensing for independent creators</div>
<h1>Self-hosted licensing for software creators.</h1>
<p class="lede">
Keysat is a self-hosted licensing server. Buyers pay you for the software you create, and their license can be verified offline. Your licensing key, customer list, and payment rails all live on your hardware &mdash; no SaaS, no middleman, no platform risk.
Keysat is a self-hosted licensing server. Buyers pay you for the software you create, and their license can be verified offline. Your licensing key, customer list, and payment rails all live on your hardware. No SaaS, no middleman, no platform risk.
</p>
<div class="cta-row">
<a class="btn primary lg" href="#install">Install Keysat <span class="arrow">&rarr;</span></a>
@@ -619,11 +674,6 @@ footer.site .bottom a { color:rgba(245,241,232,0.6); }
<p>Keysat is the licensing layer. Your hardware holds the keys and controls payment rails. No third party can mint, revoke, or read your sales records.</p>
</div>
<div class="value-grid">
<div class="item">
<div class="icon-wrap"><i data-lucide="zap"></i></div>
<h3>Bitcoin payments, your store</h3><div class="accent-bar"></div>
<p>BTCPay Server on your own Start9 takes the payment. Lightning settles in seconds. Funds land in your wallet &mdash; no intermediary holds them.</p>
</div>
<div class="item">
<div class="icon-wrap"><i data-lucide="key-round"></i></div>
<h3>You own the signing key</h3><div class="accent-bar"></div>
@@ -637,7 +687,12 @@ footer.site .bottom a { color:rgba(245,241,232,0.6); }
<div class="item">
<div class="icon-wrap"><i data-lucide="ticket"></i></div>
<h3>Sell however you want</h3><div class="accent-bar"></div>
<p>One-time purchases for the whole app. Free / paid splits. Trials. Recurring renewals. Time-limited licenses, multi-seat licenses, comp keys for press. The licensing layer is a primitive — you decide the business model.</p>
<p>One-time purchases for the whole app. Free / paid splits. Trials. Recurring renewals. Time-limited licenses, multi-seat licenses, comp keys for press. The licensing layer is a primitive. You decide the business model.</p>
</div>
<div class="item">
<div class="icon-wrap"><i data-lucide="zap"></i></div>
<h3>Payment channels you control</h3><div class="accent-bar"></div>
<p>BTCPay Server on your own server manages bitcoin and lightning payments. Funds land in your wallet without intermediaries.</p>
</div>
<div class="item">
<div class="icon-wrap"><i data-lucide="tag"></i></div>
@@ -647,7 +702,7 @@ footer.site .bottom a { color:rgba(245,241,232,0.6); }
<div class="item">
<div class="icon-wrap"><i data-lucide="wrench"></i></div>
<h3>SDKs in your language</h3><div class="accent-bar"></div>
<p>Rust, TypeScript, Python, Go &mdash; wire-compatible offline verifiers. Five lines of code in your app and you're verifying real signatures.</p>
<p>Rust, TypeScript, Python, Go: wire-compatible offline verifiers. Five lines of code in your app and you're verifying real signatures.</p>
</div>
</div>
</div>
@@ -687,7 +742,7 @@ footer.site .bottom a { color:rgba(245,241,232,0.6); }
<p class="product-tag">Schedule C + 1099 reconciler for solo accountants. Replaces a $1,200/yr software stack with one focused tool.</p>
</div>
</div>
<blockquote>&ldquo;I worked with bloated tax software for twelve years. With AI I built one that fits how I actually think &mdash; in three months, on weekends. Now Keysat lets me sell it to the other solo CPAs who were stuck with the same bad tools.&rdquo;</blockquote>
<blockquote>&ldquo;I worked with bloated tax software for twelve years. With AI I built one that fits how I actually think, in three months, on weekends. Now Keysat lets me sell it to the other solo CPAs who were stuck with the same bad tools.&rdquo;</blockquote>
</div>
</article>
@@ -705,7 +760,7 @@ footer.site .bottom a { color:rgba(245,241,232,0.6); }
<div class="body">
<div class="eyebrow-tag">Powerlifting coach</div>
<h3 class="name">Tomas Kovac</h3>
<p class="role">12 years in the gym. Built RPE-based programming software because off-the-shelf apps assume gym-membership-app generic.</p>
<p class="role">10 years as a fitness coach. Built RPE-based programming software because off-the-shelf apps were gym-membership specific and lacking in functionality.</p>
<div class="product-block">
<svg class="product-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="6" y1="6" x2="6" y2="18"/><line x1="18" y1="6" x2="18" y2="18"/><line x1="6" y1="12" x2="18" y2="12"/><circle cx="6" cy="9" r="1.5"/><circle cx="6" cy="15" r="1.5"/><circle cx="18" cy="9" r="1.5"/><circle cx="18" cy="15" r="1.5"/></svg>
<div>
@@ -713,7 +768,7 @@ footer.site .bottom a { color:rgba(245,241,232,0.6); }
<p class="product-tag">RPE-based programming and autoregulation for one-on-one coaches. Built around how strength athletes actually train.</p>
</div>
</div>
<blockquote>&ldquo;I knew exactly what coaches needed because I was the coach. AI handled the engineering &mdash; I handled the design. Now Keysat lets me sell it to the other coaches who recognize how it should actually work.&rdquo;</blockquote>
<blockquote>&ldquo;I knew exactly what coaches needed because I was the coach. AI handled the engineering. I handled the design. Now Keysat lets me sell it to the other coaches who recognize how it should actually work.&rdquo;</blockquote>
</div>
</article>
@@ -739,7 +794,7 @@ footer.site .bottom a { color:rgba(245,241,232,0.6); }
<p class="product-tag">Multi-grade week planner for homeschool families with kids on different tracks. Mixes curricula across ages.</p>
</div>
</div>
<blockquote>&ldquo;I sketched the workflow on a notepad in October. By January my kids&rsquo; school days were running on it. Now Keysat lets me sell it to the other homeschool families who were trying to bend single-student tools to fit their week.&rdquo;</blockquote>
<blockquote>&ldquo;I sketched the workflow on a notepad over a weekend. Two weeks later my kids&rsquo; school days were running on it. Now Keysat lets me sell it to the other homeschool families who were trying to bend single-student tools to fit their week.&rdquo;</blockquote>
</div>
</article>
@@ -752,7 +807,7 @@ footer.site .bottom a { color:rgba(245,241,232,0.6); }
<button class="case-dot" data-target="1" aria-label="Show case 2"></button>
<button class="case-dot" data-target="2" aria-label="Show case 3"></button>
</div>
<div class="footnote">Illustrative examples of the kinds of creators Keysat is built for. Real Keysat creators &mdash; come be one of them.</div>
<div class="footnote">Illustrative examples of the kinds of creators Keysat is built for. Real Keysat creators. Come be one of them.</div>
</div>
</section>
@@ -779,12 +834,12 @@ footer.site .bottom a { color:rgba(245,241,232,0.6); }
<div class="pitch">
<span class="eyebrow" style="color:var(--gold-700); font-size:11.5px; font-weight:700; letter-spacing:0.18em; text-transform:uppercase;">For developers and AI agents</span>
<h3>Five lines, in the language you or your AI agents already write.</h3>
<p>Keysat licenses are Ed25519-signed and Crockford base32-encoded. Verification is pure-function &mdash; no network, no daemon, no shared state. Hand the docs to your coding agent and tell it to wire licensing into your software; the integration is small enough to fit in one prompt.</p>
<p>Keysat licenses are Ed25519-signed and Crockford base32-encoded. Verification is pure-function: no network, no daemon, no shared state. Hand the docs to your coding agent and tell it to wire licensing into your software; the integration is small enough to fit in one prompt.</p>
<ul>
<li>Wire-compatible across SDKs (TypeScript, Rust, Python, Go)</li>
<li>Public key embedded at compile time</li>
<li>Returns product, policy, expiry, entitlements</li>
<li>Source-available &mdash; agents can read the verifier source directly</li>
<li>Source-available: agents can read the verifier source directly</li>
</ul>
</div>
<div class="code-card">
@@ -834,13 +889,13 @@ fmt.<span class="f">Printf</span>(<span class="s">"licensed for %s, expires %s\n
<div class="section-head">
<span class="eyebrow">Agent-friendly</span>
<h2>Built so you can hand operations to an AI agent.</h2>
<p>Keysat issues, monetizes, and manages licenses through a clean self-service admin UI. It also exposes every operator action through a documented HTTP API with bounded-scope credentials &mdash; so if you'd rather have an agent do the day-to-day work, you can give it the keys safely.</p>
<p>Keysat issues, monetizes, and manages licenses through a clean self-service admin UI. It also exposes every operator action through a documented HTTP API with bounded-scope credentials, so if you'd rather have an agent do the day-to-day work, you can give it the keys safely.</p>
</div>
<div class="agent-grid">
<div class="install-card">
<div class="cap">OpenAPI 3.1</div>
<h3>Discovery built in</h3>
<p><code>GET /v1/openapi.json</code> returns a curated, stable spec. Drop the URL into Claude (Code or Computer Use), an OpenAI Custom GPT, or Perplexity&rsquo;s Comet agent browser &mdash; the agent learns the endpoints automatically.</p>
<p><code>GET /v1/openapi.json</code> returns a curated, stable spec. Drop the URL into Claude (Code or Computer Use), an OpenAI Custom GPT, or Perplexity&rsquo;s Comet agent browser. The agent learns the endpoints automatically.</p>
</div>
<div class="install-card">
<div class="cap">Scoped API keys</div>
@@ -854,40 +909,7 @@ fmt.<span class="f">Printf</span>(<span class="s">"licensed for %s, expires %s\n
</div>
</div>
<div style="margin-top:32px; text-align:center">
<a class="btn ghost" href="https://github.com/keysat-xyz/keysat/blob/main/KEYSAT_AGENT_GUIDE.md">Agent integration guide &rarr;</a>
</div>
</div>
</section>
<section class="block" id="sovereign">
<div class="wrap">
<div class="section-head">
<span class="eyebrow">Sovereign by default</span>
<h2>Everything stays on your hardware.</h2>
<p>Migrate Start9 boxes &mdash; Keysat goes with you. If the Keysat project disappears tomorrow, your already-issued licenses keep verifying: the public key is embedded in your software, the private key is on your machine.</p>
</div>
<div class="sov">
<div class="panel">
<h3>What you keep</h3>
<div class="sub">On your Start9, in your normal backups.</div>
<ul>
<li>Signing keypair</li>
<li>Customer email &middot; npub list</li>
<li>Sale records</li>
<li>Audit log</li>
<li>BTCPay invoice history</li>
<li>Webhook subscribers</li>
<li>Bitcoin (your wallet)</li>
</ul>
<p class="footnote">Backed up automatically by StartOS as part of your normal backup routine.</p>
</div>
<div class="panel dark">
<h3>Or accept fiat, on your terms</h3>
<div class="sub">Coming soon: opt-in card payments via Zaprite.</div>
<p style="font-size:14px; line-height:1.55; color:rgba(245,241,232,0.85); margin:0 0 16px;">If your customers prefer paying with credit cards over Bitcoin, you&rsquo;ll be able to plug Zaprite into Keysat as an alternative payment provider. Same Keysat license-issuance flow, but the payment can come through Stripe-via-Zaprite for cards or any of Zaprite&rsquo;s Bitcoin rails (BTCPay, Strike, Unchained). Trades off some sovereignty &mdash; cards mean Stripe KYC and customer PII flowing through Zaprite &mdash; in exchange for a much wider addressable audience.</p>
<p style="font-size:14px; line-height:1.55; color:rgba(245,241,232,0.85); margin:0 0 16px;">Keysat stays sovereign-by-default. Card payments are something you opt into per Keysat install if your business needs them. Shipping in v0.3.</p>
<p class="footnote">Source-available license &middot; pay your operator-style trade-offs deliberately, never by default.</p>
</div>
<a class="btn ghost" href="https://docs.keysat.xyz/agent.html">Agent integration guide &rarr;</a>
</div>
</div>
</section>
@@ -897,9 +919,18 @@ fmt.<span class="f">Printf</span>(<span class="s">"licensed for %s, expires %s\n
<div class="section-head">
<span class="eyebrow">Pricing</span>
<h2>Three tiers. Free forever for solo creators.</h2>
<p>Keysat&rsquo;s gating happens at the operator&rsquo;s self-license, not at the buyer&rsquo;s. Every Keysat instance ships at Creator (free); pay only when you outgrow it.</p>
<p>Every Keysat instance ships at a highly functional Creator tier; pay only when you outgrow it.</p>
</div>
<div class="tier-grid">
<!--
Tier cards. Static markup is the FALLBACK shape (rendered on
every page load, kept conservative so it stays correct even when
offline). On load, `loadLiveTiers()` below fetches the master
Keysat's product + policies and re-renders this grid with the
live prices, marketing bullets, hidden-entitlement filtering, and
any active launch-special featured discount applied, matching
what the buy page renders.
-->
<div class="tier-grid" id="tier-grid-live">
<div class="tier-card">
<div class="tier-cap">Creator</div>
<div class="tier-price"><span class="price-num">Free</span><span class="price-sub">forever</span></div>
@@ -916,11 +947,11 @@ fmt.<span class="f">Printf</span>(<span class="s">"licensed for %s, expires %s\n
<div class="tier-card featured">
<div class="tier-cap gold">Pro</div>
<div class="tier-price"><span class="price-num">250k sats</span><span class="price-sub">/ year</span></div>
<p class="tier-pitch">For creators monetizing seriously &mdash; multiple products, subscriptions, both Bitcoin and card buyers.</p>
<p class="tier-pitch">For creators monetizing seriously: multiple products, subscriptions, both Bitcoin and card buyers.</p>
<ul>
<li>Unlimited products, tiers, and codes</li>
<li>Recurring subscriptions &middot; trials, grace, auto-renew</li>
<li>Zaprite payment gateway &mdash; cards, Apple Pay, bank transfers, plus Bitcoin</li>
<li>Zaprite payment gateway: cards, Apple Pay, bank transfers, plus Bitcoin</li>
<li>In-place tier upgrades (proration handled)</li>
<li>Everything in Creator</li>
</ul>
@@ -928,19 +959,17 @@ fmt.<span class="f">Printf</span>(<span class="s">"licensed for %s, expires %s\n
<div class="tier-card">
<div class="tier-cap">Patron</div>
<div class="tier-price"><span class="price-num">500k sats</span><span class="price-sub">/ year</span></div>
<p class="tier-pitch">Honest supporter tier. Same features as Pro; you&rsquo;re funding Keysat&rsquo;s development.</p>
<p class="tier-pitch">Perpetual license + direct one-on-one support, for creators who want Keysat to keep getting better.</p>
<ul>
<li>Everything in Pro</li>
<li>Perpetual license (one-time, never renews)</li>
<li>Direct one-on-one support</li>
<li>&ldquo;Patron&rdquo; badge in your admin dashboard</li>
<li>Listed on the Patrons page on keysat.xyz</li>
<li>Early access to release-candidate builds</li>
<li>Direct support line</li>
</ul>
</div>
</div>
<p style="margin-top:28px; text-align:center; font-size:13.5px; color:var(--ink-500);">
No fake feature gates: Patron is feature-identical to Pro. Pricing is a flat annual fee &mdash; we don&rsquo;t take a percentage of your sales.
</p>
</div>
</section>
@@ -969,7 +998,7 @@ fmt.<span class="f">Printf</span>(<span class="s">"licensed for %s, expires %s\n
<h3>Sideload</h3>
<p>If you'd rather not add the marketplace:</p>
<ol>
<li>Download <a href="https://files.keysat.xyz/keysat_x86_64.s9pk"><code>keysat_x86_64.s9pk</code></a>.</li>
<li>Download <code>keysat_x86_64.s9pk</code> from <a href="https://github.com/keysat-xyz/keysat/releases/latest">GitHub releases</a>.</li>
<li>StartOS dashboard &rarr; Sideload &rarr; drag the file in.</li>
<li>Click Install.</li>
</ol>
@@ -995,11 +1024,11 @@ fmt.<span class="f">Printf</span>(<span class="s">"licensed for %s, expires %s\n
</div>
<div>
<h3>What&rsquo;s the difference between the three tiers?</h3>
<p>Creator is free forever, capped at 5 products / 5 policies per product / 10 active discount codes &mdash; plenty for a solo creator selling one-time or perpetual licenses. Pro lifts every cap and unlocks recurring subscriptions plus the Zaprite payment gateway (cards, Apple Pay, bank transfers, in addition to Bitcoin). Patron is Pro with a public supporter badge; same features, you&rsquo;re funding development. See the tier comparison above for the full breakdown.</p>
<p>Creator is free forever, capped at 5 products / 5 policies per product / 10 active discount codes, plenty for a solo creator selling one-time or perpetual licenses. Pro lifts every cap and unlocks recurring subscriptions plus the Zaprite payment gateway (cards, Apple Pay, bank transfers, in addition to Bitcoin), billed annually. Patron is everything in Pro, sold as a one-time perpetual license instead of an annual subscription, plus direct one-on-one support and a public supporter badge. You&rsquo;re funding development. See the tier cards above for the full breakdown.</p>
</div>
<div>
<h3>Do I have to use Bitcoin?</h3>
<p>BTCPay (Bitcoin / Lightning) is the default and available on every tier. On Pro or Patron you can additionally connect Zaprite, which adds card / Apple Pay / bank transfer / more &mdash; with payments still landing in your wallet. Pick whichever your buyers prefer; you can switch the active provider at any time.</p>
<p>BTCPay (Bitcoin / Lightning) is the default and available on every tier. On Pro or Patron you can additionally connect Zaprite, which adds card / Apple Pay / bank transfer / more, with payments still landing in your wallet. Pick whichever your buyers prefer; you can switch the active provider at any time.</p>
</div>
</div>
</div>
@@ -1034,7 +1063,7 @@ fmt.<span class="f">Printf</span>(<span class="s">"licensed for %s, expires %s\n
</div>
</div>
<div class="bottom">
<span>&copy; Keysat. Source-available; not open-source.</span>
<span>&copy; Keysat. Daemon is <a href="https://docs.keysat.xyz/license.html">source-available</a>; SDKs are MIT.</span>
<span>Runs on Start9 &middot; Pays via BTCPay &middot; Verifies offline</span>
</div>
</div>
@@ -1074,7 +1103,7 @@ fmt.<span class="f">Printf</span>(<span class="s">"licensed for %s, expires %s\n
});
});
// Case-study slider auto-advance with pause on hover, dot indicators
// Case-study slider: auto-advance with pause on hover, dot indicators
(function() {
const track = document.getElementById('case-track');
const slider = document.getElementById('case-slider');
@@ -1083,7 +1112,7 @@ fmt.<span class="f">Printf</span>(<span class="s">"licensed for %s, expires %s\n
const slides = track.querySelectorAll('.case-slide');
const SLIDE_COUNT = slides.length;
const ADVANCE_MS = 9000; // ~9s per slide long enough to read
const ADVANCE_MS = 9000; // ~9s per slide (long enough to read)
let current = 0;
let timer = null;
@@ -1106,7 +1135,7 @@ fmt.<span class="f">Printf</span>(<span class="s">"licensed for %s, expires %s\n
// Pause on hover; resume on leave.
slider.addEventListener('mouseenter', stop);
slider.addEventListener('mouseleave', start);
// Also pause when the tab isn't visible saves CPU.
// Also pause when the tab isn't visible (saves CPU).
document.addEventListener('visibilitychange', () => {
if (document.hidden) stop(); else start();
});
@@ -1123,5 +1152,172 @@ fmt.<span class="f">Printf</span>(<span class="s">"licensed for %s, expires %s\n
start();
})();
</script>
<!--
Live tier-card render. Fetches the master Keysat's product + policies
on page load and re-renders the #tier-grid-live grid with whatever
the operator configured: prices, marketing bullets, hidden
entitlements, and any active featured (launch-special) discount.
Mirrors the buy page's tier-picker treatment so the landing page
and /buy/keysat tell exactly the same pricing story.
Failure mode: if the fetch errors (offline visitor, daemon down,
CORS hiccup), the static fallback grid renders as it does today.
This script only mutates the DOM on success.
-->
<script>
(function () {
const KEYSAT_API = 'https://licensing.keysat.xyz';
const PRODUCT_SLUG = 'keysat';
const fmtSats = (n) => {
if (n === 0) return 'Free';
if (n >= 1_000_000 && n % 100_000 === 0) return (n / 1_000_000) + 'M sats';
if (n >= 1_000 && n % 1_000 === 0) return (n / 1_000) + 'k sats';
return Number(n).toLocaleString('en-US') + ' sats';
};
const cadenceSuffix = (p) => {
if (!p.is_recurring) return '';
const d = p.renewal_period_days || 0;
if (d === 7) return '/ wk';
if (d === 30) return '/ mo';
if (d === 90) return '/ qtr';
if (d === 180) return '/ 6mo';
if (d === 365) return '/ year';
if (d > 0) return '/ ' + d + 'd';
return '';
};
const discountLabel = (fd) => {
if (!fd) return '';
if (fd.kind === 'percent') return Math.round(fd.amount / 100) + '% OFF';
if (fd.kind === 'free_license') return 'FREE';
if (fd.kind === 'set_price') return 'LIMITED PRICE';
return 'LAUNCH SPECIAL';
};
function renderCard(pol, catalog) {
const card = document.createElement('div');
card.className = 'tier-card' + (pol.highlighted ? ' featured' : '');
const fd = pol.featured_discount;
if (fd) card.classList.add('has-launch');
const cap = document.createElement('div');
cap.className = 'tier-cap' + (pol.highlighted ? ' gold' : '');
cap.textContent = pol.name;
card.appendChild(cap);
if (fd) {
const ribbon = document.createElement('div');
ribbon.className = 'tier-launch-ribbon';
ribbon.textContent = discountLabel(fd);
card.appendChild(ribbon);
const remaining = fd.remaining_uses;
if (typeof remaining === 'number' && remaining > 0) {
const meta = document.createElement('div');
meta.className = 'tier-launch-meta';
meta.textContent = 'Limited discount: ' + remaining + ' remaining';
card.appendChild(meta);
}
const orig = document.createElement('div');
orig.className = 'tier-price-original';
orig.textContent = fmtSats(pol.price_sats);
card.appendChild(orig);
}
// Headline price. Free policies just say "Free"; paid policies
// show the discounted price when a featured discount applies.
const priceWrap = document.createElement('div');
priceWrap.className = 'tier-price';
const priceNum = document.createElement('span');
priceNum.className = 'price-num';
const priceSub = document.createElement('span');
priceSub.className = 'price-sub';
if (pol.price_sats === 0) {
priceNum.textContent = 'Free';
priceSub.textContent = 'forever';
} else {
const effective = fd ? fd.discounted_price_sats : pol.price_sats;
priceNum.textContent = fmtSats(effective);
const suffix = cadenceSuffix(pol);
priceSub.textContent = pol.is_recurring && suffix ? suffix : '';
if (!pol.is_recurring) priceSub.textContent = '';
}
priceWrap.appendChild(priceNum);
if (priceSub.textContent) priceWrap.appendChild(priceSub);
card.appendChild(priceWrap);
if (pol.description) {
const pitch = document.createElement('p');
pitch.className = 'tier-pitch';
pitch.textContent = pol.description;
card.appendChild(pitch);
}
// Merge marketing bullets + (visible) entitlements into a single
// <ul> in the operator-controlled order. Identical pattern to the
// buy page's tier-features list.
const hidden = new Set(pol.hidden_entitlements || []);
const entItems = (pol.entitlements || [])
.filter((slug) => !hidden.has(slug))
.map((slug) => {
const entry = catalog[slug];
return entry && entry.name ? entry.name : slug;
});
const bullets = pol.marketing_bullets || [];
const order = (pol.marketing_bullets_position === 'below')
? entItems.concat(bullets)
: bullets.concat(entItems);
if (order.length > 0) {
const list = document.createElement('ul');
list.className = 'tier-features-list';
order.forEach((text) => {
const li = document.createElement('li');
li.textContent = text;
list.appendChild(li);
});
card.appendChild(list);
}
// Buy CTA. Navy pill that links to the master Keysat's buy page
// with the right policy slug pre-selected. Free tier links to the
// same page; it renders "Redeem license" automatically.
const buyBtn = document.createElement('a');
buyBtn.className = 'tier-buy-cta';
buyBtn.href = KEYSAT_API + '/buy/' + PRODUCT_SLUG + '?policy=' + encodeURIComponent(pol.slug);
buyBtn.textContent = 'Get ' + pol.name;
card.appendChild(buyBtn);
return card;
}
async function loadLiveTiers() {
const grid = document.getElementById('tier-grid-live');
if (!grid) return;
try {
const [productR, policiesR] = await Promise.all([
fetch(KEYSAT_API + '/v1/products/' + PRODUCT_SLUG, { cache: 'no-cache' }),
fetch(KEYSAT_API + '/v1/products/' + PRODUCT_SLUG + '/policies', { cache: 'no-cache' }),
]);
if (!productR.ok || !policiesR.ok) return; // leave static fallback
const productJ = await productR.json();
const policiesJ = await policiesR.json();
const product = productJ.product || productJ;
const catalog = {};
(product.entitlements_catalog || []).forEach((e) => { catalog[e.slug] = e; });
const policies = (policiesJ.policies || []).filter((p) => !p.is_trial);
if (policies.length === 0) return;
// Empty the grid + render the live cards.
while (grid.firstChild) grid.removeChild(grid.firstChild);
policies.forEach((p) => grid.appendChild(renderCard(p, catalog)));
} catch (_) {
// Silent fallback. The static cards stay rendered.
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', loadLiveTiers);
} else {
loadLiveTiers();
}
})();
</script>
</body>
</html>
+18 -3
View File
@@ -5,6 +5,21 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Support Keysat development</title>
<meta name="description" content="Support Keysat development. Lightning, on-chain, or buy a Patron license.">
<!-- Social sharing (Open Graph + Twitter Card). -->
<meta property="og:type" content="website">
<meta property="og:site_name" content="Keysat">
<meta property="og:title" content="Support Keysat development">
<meta property="og:description" content="Fund Keysat development directly: Lightning, on-chain Bitcoin, a Patron license, or via OpenSats. Pick whichever fits.">
<meta property="og:url" content="https://keysat.xyz/support.html">
<meta property="og:image" content="https://keysat.xyz/assets/keysat-social.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="1200">
<meta property="og:image:alt" content="Keysat — self-hosted licensing server">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Support Keysat development">
<meta name="twitter:description" content="Fund Keysat development directly: Lightning, on-chain Bitcoin, a Patron license, or via OpenSats.">
<meta name="twitter:image" content="https://keysat.xyz/assets/keysat-social.png">
<link rel="icon" type="image/svg+xml" href="assets/favicon.svg">
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;900&family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
@@ -139,7 +154,7 @@ footer{
<div class="card featured">
<div class="label">Recommended</div>
<h3>Patron tier on registry.keysat.xyz</h3>
<p>Same Keysat binary as the standard license, just priced higher. The admin UI shows a "Patron" badge in your dashboard. The cleanest way to support development &mdash; same purchase flow you&rsquo;re already familiar with from buying any other Keysat license.</p>
<p>Same Keysat binary as the standard license, just priced higher. The admin UI shows a "Patron" badge in your dashboard. The cleanest way to support development. Same purchase flow you&rsquo;re already familiar with from buying any other Keysat license.</p>
<p style="margin-top:14px"><a class="btn" href="https://registry.keysat.xyz">Visit the marketplace &rarr;</a></p>
</div>
@@ -147,7 +162,7 @@ footer{
<div class="card">
<div class="label">Fast, no-strings tip</div>
<h3>Lightning Address</h3>
<p>Tip any amount over Lightning. Hosted on Primal &mdash; works in any Lightning wallet that supports LN addresses.</p>
<p>Tip any amount over Lightning. Hosted on Primal. Works in any Lightning wallet that supports LN addresses.</p>
<div class="addr">
<span id="ln-addr">keysat@primal.net</span>
<button data-copy="keysat@primal.net">Copy</button>
@@ -158,7 +173,7 @@ footer{
<div class="card">
<div class="label">Fund Bitcoin FOSS broadly</div>
<h3>OpenSats</h3>
<p>If you&rsquo;d rather fund Bitcoin software development broadly rather than this project specifically, <a href="https://opensats.org" style="color:var(--navy-800); font-weight:500">OpenSats</a> is a 501(c)(3) that grants to dozens of FOSS Bitcoin projects &mdash; including BTCPay, which Keysat depends on.</p>
<p>If you&rsquo;d rather fund Bitcoin software development broadly rather than this project specifically, <a href="https://opensats.org" style="color:var(--navy-800); font-weight:500">OpenSats</a> is a 501(c)(3) that grants to dozens of FOSS Bitcoin projects, including BTCPay, which Keysat depends on.</p>
</div>
</div>