Skip to content

Sell Your App with Stripe

PyLocket integrates with Stripe so you can accept payments for your protected app and have PyLocket deliver the license + download automatically after every sale. This guide walks you through the one-time setup, then helps you pick between three integration paths depending on how much you want to build.

  • Path A — Share a Payment Link: generate one permanent URL in the portal and paste it anywhere. Zero code. Recommended for most developers.
  • Path B — Use our API: call POST /v1/licenses/{id}/purchase-link from your backend to mint short-lived, single-use checkout URLs. Best for apps that already have a server.
  • Path C — Bring your own Payment Link: you've already built a Payment Link in your Stripe dashboard. Point its post-purchase redirect at PyLocket and we handle delivery.

All three paths give the customer the same experience: a Stripe-hosted checkout that shows your business name, followed by PyLocket's branded download page + license-key email.


How the flow works

Customer clicks your URL  →  Stripe Checkout (paid)  →  License is minted
                                                       ↘ Download page / email

Stripe notifies PyLocket when a payment succeeds (via webhook). PyLocket mints the license, generates a signed download URL for your latest protected build, and sends a delivery email to the customer. Each of the three paths below just varies how the checkout is created — the license-minting and download side is identical.

PyLocket's platform fee. PyLocket collects a flat $4 per license sold, whether one-time or subscription. For Paths A and B we configure the fee automatically. For Path C you can either configure it on your Payment Link (recommended) or let PyLocket bill it via your Pro subscription — either way we get paid, you just pick where it shows up.


One-time setup (required for all paths)

Prerequisites

  • A Stripe account — dashboard.stripe.com if you need one.
  • An active PyLocket Pro subscription ($9/year). The free tier can issue trial licenses only, not paid ones.
  • At least one registered App in the Developer Portal, with at least one protected build in READY state (so there's something for customers to download).

Step 1 — Connect your Stripe account to PyLocket

  1. Log in to portal.pylocket.com.
  2. Settings → Sales & Payments → Connect Stripe Account.
  3. Sign in to Stripe if prompted, review the permissions (PyLocket needs to create Checkout sessions on your behalf, charge end users to your account, and collect the per-license platform fee), and click Authorize.

You're redirected back to the portal and should see Stripe Connect: Connected with your account ID (starts with acct_...).

Step 2 — Create a Product and Price in Stripe

Some terminology first, because the Stripe dashboard can be confusing on first contact:

  • A Product (prod_...) represents the thing you're selling, e.g. My App Pro.
  • A Price (price_...) represents a specific pricing configuration attached to a product — e.g. $49 one-time in USD, or $5/month in USD, or €45 one-time in EUR. A single Product can have many Prices.

PyLocket sells at the Price level, not the Product level, because that's what tells Stripe exactly how much to charge. If you want to sell the same app at different price points (e.g. one-time vs subscription), you'd either create two Prices on one Product, or two PyLocket apps each with one Price — pick whichever matches how you want to track sales.

Create the Price:

  1. Stripe Dashboard → Products → Add Product.
  2. Name it, set the pricing model (one-time or recurring), currency, and amount.
  3. Save. Copy the Price ID (starts with price_...).

Subscription pricing must be at least $4/period (the PyLocket platform fee) and use a flat amount — tiered/usage-based subscription prices are not supported.

Step 3 — Save the Price ID in PyLocket

  1. Open your App in the portal.
  2. Sales section → paste the Price ID → Save Price ID.

One Price ID, one app. Each Stripe Price ID can back only one PyLocket app. If you sell two different apps, create two Prices in Stripe (either under separate Products or as two Prices on one Product) and save each on its respective PyLocket app. The portal returns a 409 Conflict if you try to reuse a Price ID across apps.

Once Connect is linked and you've saved a Price ID, the portal unlocks the three integration paths below. Pick one.


Best for: most developers. You want a single URL you can paste into email, a landing page, a social bio, Discord, Notion — anywhere. No backend required.

How it works

PyLocket creates a reusable Stripe Payment Link (buy.stripe.com/...) on your connected account with the platform fee and post-purchase redirect configured for you. The URL is permanent and can be shared with any number of customers — each purchase creates an independent license.

Setup

  1. In the portal, open your App → Sales section.
  2. Click Generate Payment Link.
  3. Copy the buy.stripe.com/... URL. Share it anywhere.

That's it. Every customer who pays via that URL will:

  1. Land on a Stripe-hosted checkout showing your business name.
  2. Pay with card, Apple Pay, Google Pay, or whatever you've enabled in Stripe.
  3. Get redirected to PyLocket's branded "Thank you" page with their license key + download button.
  4. Receive a delivery email with the license key, download link, and expiration.

You can regenerate the Payment Link at any time (e.g. if your price changes) — the old URL stops working. You can also remove it to pause sales entirely.


Path B — Use our API

Best for: apps that already have a backend and want fine-grained control per customer (pre-filled email, custom_text for compliance, dynamic metadata, anti-fraud flags, A/B pricing).

How it works

Your server calls PyLocket's API to mint a short-lived, single-use Stripe Checkout URL, then redirects the customer to it.

Setup

curl -X POST https://api.pylocket.com/v1/licenses/<license_id>/purchase-link \
  -H "Authorization: Bearer $PYLOCKET_API_KEY" \
  -H "Content-Type: application/json"

Response:

{ "checkout_url": "https://checkout.stripe.com/c/pay/cs_..." }

Redirect the customer to checkout_url. PyLocket handles everything downstream (platform fee, post-purchase redirect, license minting, download delivery).

Minimal Node.js example

const res = await fetch(
  `https://api.pylocket.com/v1/licenses/${licenseId}/purchase-link`,
  { method: "POST", headers: { Authorization: `Bearer ${process.env.PYLOCKET_API_KEY}` } }
);
const { checkout_url } = await res.json();
return Response.redirect(checkout_url, 303);

Minimal Python example

import httpx, os

def purchase_url(license_id: str) -> str:
    r = httpx.post(
        f"https://api.pylocket.com/v1/licenses/{license_id}/purchase-link",
        headers={"Authorization": f"Bearer {os.environ['PYLOCKET_API_KEY']}"},
    )
    r.raise_for_status()
    return r.json()["checkout_url"]

Best for: you've already built a Payment Link in your Stripe dashboard (maybe with custom fields, promotion codes, or branded imagery) and want to keep using it. Also the path to pick if you want customers to land on your own thank-you page instead of PyLocket's.

Requirement — the Price ID must match

The Price on your Payment Link must be the same Price ID you saved on your PyLocket app. That's how PyLocket knows which app to mint a license for when the payment comes in. No extra metadata required.

Choose what happens after the customer pays

Path C has three sub-options for the post-purchase page. Pick one:

C.1 — Use PyLocket's branded thank-you page (simplest)

In Stripe's Payment Link settings, set After completion → Redirect customers to a custom page to:

https://get.pylocket.com/thank-you?app=<YOUR_APP_ID>&session_id={CHECKOUT_SESSION_ID}
  • Replace <YOUR_APP_ID> with the UUID from the PyLocket portal (visible on your App page; the portal has a copy button for the exact URL).
  • Leave {CHECKOUT_SESSION_ID} literally — Stripe substitutes it at redirect time. Do not URL-encode the braces.

Point after_completion.redirect.url to your own thank-you page (https://example.com/thanks). On that page, include a "Download your app" button that links to:

https://get.pylocket.com/thank-you?app=<YOUR_APP_ID>&session_id={CHECKOUT_SESSION_ID}

The session_id is on the query string Stripe appended when redirecting to your page — just pass it through. Your customer sees your branding up front, then clicks through to PyLocket's secure delivery page.

C.3 — Fully custom thank-you page (maximum control)

Redirect to your own page, and on page load call PyLocket's public entitlement API directly:

GET https://api.pylocket.com/v1/public/checkout-session/{session_id}/entitlement?app_id=<YOUR_APP_ID>

Response:

{
  "license_key": "PL-...",
  "download_url": "https://dxxx.cloudfront.net/...",
  "download_expires_at": "2026-04-27T00:00:00Z",
  "app_name": "My App",
  "app_version": "1.0.0",
  "customer_email": "buyer@example.com"
}

Render it however you like. The endpoint is public, rate-limited, and scoped to your connected account — no API key needed, but it only returns data for sessions that belong to your Stripe account. If you get a 404 "License not yet provisioned", the Stripe webhook hasn't fired yet; wait ~2 seconds and retry.

A delivery email is also sent automatically the first time this endpoint successfully returns — useful for mobile purchases where the customer can't download on the device they paid from.

Platform fee on Path C

Two choices:

  • Configure the $4 fee on your Payment Link (recommended) — set application_fee_percent in Stripe's Payment Link API or dashboard so PyLocket gets paid directly on every sale. Same net effect as Paths A and B.
  • Skip the fee on the Payment Link — PyLocket bills the per-license fee via your Pro subscription instead, on your next monthly invoice. No action required from you; the bookkeeping just shows up differently.

Stripe's built-in hosted_confirmation option (Stripe's generic thank-you page) works in a pinch — the license is still minted and the customer gets the delivery email — but they won't see a download button on the confirmation page, so most buyers will mistakenly think the sale failed. Don't use it unless you really mean to.


What the customer sees

Regardless of which path you pick:

  • Stripe checkout page: shows your business name (from your Stripe statement descriptor), not "PyLocket".
  • Credit card statement: your business name.
  • Stripe receipt email: sent from your Stripe account; shows your business.
  • Refunds, tax, customer-service contact: all yours.
  • PyLocket: never mentioned in anything the customer sees (except the optional get.pylocket.com delivery page on Paths A and C.1/C.2 — and even that is branded with your app's icon, colors, and custom message if you've configured them).

Test your first sale

Use Stripe test mode before going live:

  1. In the Stripe dashboard toggle to Test mode.
  2. Create a test Price, save it on a test PyLocket app, generate/configure a Payment Link per your chosen path.
  3. Pay with Stripe's 4242 4242 4242 4242 test card (any future expiry, any CVC, any zip).
  4. Confirm the license shows up in the portal's Licenses tab and the delivery email arrives (if the test customer email was set).

Troubleshooting

"Price ID is already in use by your app X" — Each Price can back only one app. Create a separate Stripe Price for the other app, or change which app you intend to sell with this Price.

Customer paid but no license was issued — Usually means the Price on your Payment Link doesn't match the Price saved on any PyLocket app under your connected account. Check the portal → App → Sales → the Price ID there must match line_items[].price.id on the session. Stripe's Dashboard → Payments → the session shows the Price that was charged.

Customer paid but never got the email — The customer's Stripe session didn't collect an email (rare; Stripe collects by default). Check Stripe → Customers → the session's customer — if email is missing, the customer can still download via the delivery page URL but no email will arrive.

"$4 platform fee didn't route" (Path C only) — Your self-managed Payment Link wasn't configured with application_fee_percent. PyLocket will bill the fee via your Pro subscription instead; nothing is lost. Either add the fee to your Payment Link going forward or leave it as-is.

Stripe shows the payment came in but the portal doesn't show a license — Most common cause is a delayed or lost webhook. If it's been more than a few minutes, contact support with the Stripe session ID (cs_...); support can manually provision the license.


Disconnecting Stripe Connect

Portal → Settings → Sales & Payments → Disconnect Stripe → Confirm.

Existing licenses continue to work. Previously-generated Payment Links (Path A) stop delivering licenses because the webhook can no longer authenticate your account — regenerate them after reconnecting if you ever come back. No lock-in either way.


See also