Fix change-tier API example and move install steps to the admin UI

This commit is contained in:
Keysat
2026-06-17 15:24:55 -05:00
parent 1d87d6d889
commit 2a0e179c43
2 changed files with 14 additions and 13 deletions
+7 -6
View File
@@ -64,8 +64,8 @@ curl -X POST https://your-keysat-host/v1/admin/api-keys \
-d '{"label":"Support bot","role":"support"}' -d '{"label":"Support bot","role":"support"}'
# Response includes `token: ks_...`. Save it. It's only shown once. # Response includes `token: ks_...`. Save it. It's only shown once.
# 3. Use the scoped key # 3. Use the scoped key (admin/licenses requires a product_id)
curl https://your-keysat-host/v1/admin/licenses?status=active \ curl "https://your-keysat-host/v1/admin/licenses?product_id=<uuid>" \
-H "Authorization: Bearer ks_..."</pre> -H "Authorization: Bearer ks_..."</pre>
<h2 id="auth">Authentication</h2> <h2 id="auth">Authentication</h2>
@@ -245,11 +245,12 @@ curl -X POST $KS/v1/admin/subscriptions/$SUB_ID/cancel \
<pre class="code">curl -X POST $KS/v1/admin/licenses/$LICENSE_ID/change-tier \ <pre class="code">curl -X POST $KS/v1/admin/licenses/$LICENSE_ID/change-tier \
-H "Authorization: Bearer ks_..." \ -H "Authorization: Bearer ks_..." \
-d '{ -d '{
"target_policy_slug": "pro", "to_policy_slug": "pro",
"skip_payment": true,
"reason": "support resolution" "reason": "support resolution"
}'</pre> }'</pre>
<p>Always applies as comp (no invoice) from the admin path. Buyer-initiated paid upgrades go through <code>/v1/upgrade</code> (different endpoint, signed-license auth).</p> <p>With <code>skip_payment: true</code> this applies as a comp (no invoice). Omit it (defaults to false) and the admin path behaves like the buyer path: it creates an invoice for the prorated charge and returns the checkout URL. Buyer-initiated paid upgrades go through <code>/v1/upgrade</code> (different endpoint, signed-license auth).</p>
<p><em>Scope required: <code>licenses:write</code>.</em></p> <p><em>Master admin key required.</em></p>
<h3 id="connect-btcpay">Connect BTCPay programmatically (sandbox)</h3> <h3 id="connect-btcpay">Connect BTCPay programmatically (sandbox)</h3>
<p>On a <strong>sandbox</strong> daemon (<code>KEYSAT_SANDBOX_MODE=1</code>), a scoped key carrying <code>payment_providers:write</code> can connect a BTCPay store over the API with no browser step, as long as the store settles on a <strong>non-mainnet</strong> network (regtest / testnet / signet). On a production daemon, or for a mainnet store, connect stays master-only. This is the path a delegated setup agent uses to stand up a disposable test instance end to end. You need a BTCPay API key for the target store (the operator's BTCPay access, delegated to you) carrying the same store and invoice permissions the browser flow grants (see <a href="install.html#connect-btcpay">Install &amp; setup</a>): the store-settings permissions complete the connect, and the invoice permissions let settled purchases issue licenses.</p> <p>On a <strong>sandbox</strong> daemon (<code>KEYSAT_SANDBOX_MODE=1</code>), a scoped key carrying <code>payment_providers:write</code> can connect a BTCPay store over the API with no browser step, as long as the store settles on a <strong>non-mainnet</strong> network (regtest / testnet / signet). On a production daemon, or for a mainnet store, connect stays master-only. This is the path a delegated setup agent uses to stand up a disposable test instance end to end. You need a BTCPay API key for the target store (the operator's BTCPay access, delegated to you) carrying the same store and invoice permissions the browser flow grants (see <a href="install.html#connect-btcpay">Install &amp; setup</a>): the store-settings permissions complete the connect, and the invoice permissions let settled purchases issue licenses.</p>
@@ -375,7 +376,7 @@ def verify(body_bytes: bytes, signature_header: str, secret: str) -> bool:
<p>List endpoints return up to ~100 rows by default. Use <code>?limit=N</code> and <code>?offset=N</code> for larger result sets. The OpenAPI spec documents the limits per endpoint.</p> <p>List endpoints return up to ~100 rows by default. Use <code>?limit=N</code> and <code>?offset=N</code> for larger result sets. The OpenAPI spec documents the limits per endpoint.</p>
<h3>Rate limits</h3> <h3>Rate limits</h3>
<p>The admin endpoints have no per-IP rate limit today. Operators are trusted. The public endpoints (<code>/v1/validate</code>, <code>/v1/recover</code>) are rate-limited per client IP (10/min for <code>/recover</code>; <code>/validate</code> is unlimited but a reasonable agent calls it once per app boot + once per hour).</p> <p>The admin endpoints have no per-IP rate limit today. Operators are trusted. The public endpoints (<code>/v1/validate</code>, <code>/v1/recover</code>) are rate-limited per client IP (10/min for <code>/recover</code>; <code>/validate</code> allows a 60/min burst per client IP, which a reasonable agent stays well under by calling it once per app boot + once per hour).</p>
<h3>Master key handling</h3> <h3>Master key handling</h3>
<p>If your automation needs <code>full-admin</code> because it touches operator-only operations (creating other API keys, changing payment providers), use the master key from a secret manager. If it can stay within license / product / policy operations, <strong>always use a scoped key</strong>. Operators can revoke a compromised scoped key without rotating the master credential.</p> <p>If your automation needs <code>full-admin</code> because it touches operator-only operations (creating other API keys, changing payment providers), use the master key from a secret manager. If it can stay within license / product / policy operations, <strong>always use a scoped key</strong>. Operators can revoke a compromised scoped key without rotating the master credential.</p>
+7 -7
View File
@@ -71,7 +71,7 @@
<h3>Option B: sideload</h3> <h3>Option B: sideload</h3>
<ol> <ol>
<li>Download <code>keysat_x86_64.s9pk</code> from the <a href="https://github.com/keysat-xyz/keysat/releases">GitHub releases page</a>.</li> <li>Download <code>keysat.s9pk</code> from the <a href="https://github.com/keysat-xyz/keysat/releases">GitHub releases page</a>.</li>
<li>In your StartOS dashboard, go to <strong>Sideload</strong> and drag the file in.</li> <li>In your StartOS dashboard, go to <strong>Sideload</strong> and drag the file in.</li>
<li>Click <strong>Install</strong>.</li> <li>Click <strong>Install</strong>.</li>
</ol> </ol>
@@ -79,13 +79,13 @@
<p>BTCPay Server is declared as a required dependency. If you don&rsquo;t have it installed yet, StartOS will prompt you to install it as part of the same flow.</p> <p>BTCPay Server is declared as a required dependency. If you don&rsquo;t have it installed yet, StartOS will prompt you to install it as part of the same flow.</p>
<h2 id="operator-name">Step 2: Set your operator name</h2> <h2 id="operator-name">Step 2: Set your operator name</h2>
<p>Open the Keysat service page in StartOS. Go to <strong>Actions &rarr; Set operator name</strong>. Pick a short label that identifies <em>you</em> as the seller, e.g. "aurora-software", "northpath", "my-name". This shows up on the public purchase pages and in the audit log.</p> <p>Open the admin web UI (Step 5) and go to <strong>Settings</strong>. Set your operator name there: a short label that identifies <em>you</em> as the seller, e.g. "aurora-software", "northpath", "my-name". This shows up on the public purchase pages and in the audit log.</p>
<p>This change is live-reloaded; you don&rsquo;t need to restart the service.</p> <p>This change is live-reloaded; you don&rsquo;t need to restart the service.</p>
<h2 id="connect-btcpay">Step 3: Connect BTCPay</h2> <h2 id="connect-btcpay">Step 3: Connect BTCPay</h2>
<p>Make sure BTCPay Server is running and has at least one <strong>store</strong> with a configured <strong>payment method</strong> (on-chain wallet or Lightning node). Without a payment method, BTCPay will reject Keysat&rsquo;s invoice creation.</p> <p>Make sure BTCPay Server is running and has at least one <strong>store</strong> with a configured <strong>payment method</strong> (on-chain wallet or Lightning node). Without a payment method, BTCPay will reject Keysat&rsquo;s invoice creation.</p>
<p>In Keysat&rsquo;s service page, click <strong>Actions &rarr; Connect BTCPay</strong>. You&rsquo;ll be redirected to BTCPay&rsquo;s authorize page, where you grant Keysat the permissions it needs:</p> <p>In the admin web UI, go to <strong>Settings &rarr; Payment providers</strong> and click <strong>Connect BTCPay</strong> (agents can drive the same connect over the API with <code>POST /v1/admin/btcpay/connect</code>). You&rsquo;ll be redirected to BTCPay&rsquo;s authorize page, where you grant Keysat the permissions it needs:</p>
<ul> <ul>
<li><code>btcpay.store.canviewstoresettings</code></li> <li><code>btcpay.store.canviewstoresettings</code></li>
@@ -104,12 +104,12 @@
<div class="callout"> <div class="callout">
<i data-lucide="info"></i> <i data-lucide="info"></i>
<p><strong>Connect is idempotent.</strong> If you click it again later, Keysat detects the existing connection and returns success without re-authorizing. To force a re-authorize, run the <strong>Disconnect BTCPay</strong> action first.</p> <p><strong>Connect is idempotent.</strong> If you click it again later, Keysat detects the existing connection and returns success without re-authorizing. To force a re-authorize, disconnect first from <strong>Settings &rarr; Payment providers</strong> (or <code>POST /v1/admin/btcpay/disconnect</code>).</p>
</div> </div>
<p>Automating setup? On a <strong>sandbox</strong> daemon you can connect a non-mainnet BTCPay over the API instead of clicking, using a scoped key carrying the <code>payment_providers:write</code> scope. See <a href="agent.html#connect-btcpay">Agent integration: Connect BTCPay programmatically</a>.</p> <p>Automating setup? On a <strong>sandbox</strong> daemon you can connect a non-mainnet BTCPay over the API instead of clicking, using a scoped key carrying the <code>payment_providers:write</code> scope. See <a href="agent.html#connect-btcpay">Agent integration: Connect BTCPay programmatically</a>.</p>
<p>Click <strong>Actions &rarr; Check BTCPay connection</strong> to verify the wiring. It should report:</p> <p>Back in <strong>Settings &rarr; Payment providers</strong> (or via <code>GET /v1/admin/btcpay/status</code>), verify the wiring. It should report:</p>
<pre class="code"><span class="c"># Expected output:</span> <pre class="code"><span class="c"># Expected output:</span>
status: <span class="s">connected</span> status: <span class="s">connected</span>
@@ -120,7 +120,7 @@ payment_methods: <span class="s">[BTC-OnChain, BTC-LightningNetwork]</span></pre
<p>If <code>payment_methods</code> is empty, head back to BTCPay and configure at least one before continuing.</p> <p>If <code>payment_methods</code> is empty, head back to BTCPay and configure at least one before continuing.</p>
<h2 id="admin-key">Step 4: Get your admin API key</h2> <h2 id="admin-key">Step 4: Get your admin API key</h2>
<p>Go to <strong>Actions &rarr; Show admin API key</strong>. This reveals the 64-hex-character key that gates all <code>/v1/admin/*</code> endpoints, including the admin UI.</p> <p>Go to <strong>Actions &rarr; Show credentials</strong>. This reveals the 64-hex-character admin API key that gates all <code>/v1/admin/*</code> endpoints, including the admin UI.</p>
<div class="callout warn"> <div class="callout warn">
<i data-lucide="alert-triangle"></i> <i data-lucide="alert-triangle"></i>
@@ -130,7 +130,7 @@ payment_methods: <span class="s">[BTC-OnChain, BTC-LightningNetwork]</span></pre
<h2 id="admin-ui">Step 5: Open the admin UI</h2> <h2 id="admin-ui">Step 5: Open the admin UI</h2>
<p>Click the <strong>Launch UI</strong> button on Keysat&rsquo;s service page. (StartOS surfaces this for any service that defines a <code>type: 'ui'</code> interface.) Paste the admin key from the previous step into the sign-in form.</p> <p>Click the <strong>Launch UI</strong> button on Keysat&rsquo;s service page. (StartOS surfaces this for any service that defines a <code>type: 'ui'</code> interface.) Paste the admin key from the previous step into the sign-in form.</p>
<p>From here on, you mostly work in the admin UI. The StartOS Actions tab is reserved for setup-only operations (operator name, BTCPay connect/disconnect/check, show admin key).</p> <p>From here on, you work in the admin UI. The StartOS Actions tab is reserved for the few operations that must happen outside the web UI: showing credentials, setting the web UI password, and activating or checking the Keysat self-license.</p>
<h2 id="first-product">Step 6: Define your first product</h2> <h2 id="first-product">Step 6: Define your first product</h2>
<p>In the admin UI, go to <strong>Products &rarr; Create a new product</strong> and fill in:</p> <p>In the admin UI, go to <strong>Products &rarr; Create a new product</strong> and fill in:</p>