Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.shipfastai.dev/llms.txt

Use this file to discover all available pages before exploring further.

The storefront API handles one-time product purchases through Stripe Checkout and delivers the purchased product as a password-protected ZIP file. These endpoints power the main Shipfastai storefront and are separate from the subscription billing endpoints used inside each product tier.
Checkout and download endpoints use Supabase authentication (cookie-based). Make sure you are logged in through the Shipfastai frontend before calling these endpoints.

GET /api/checkout

Start a one-time purchase flow for a product tier. This endpoint redirects the browser to a Stripe-hosted checkout page. If the user is not authenticated, they are redirected to the login page first. If the user already owns the requested tier, they are redirected to the dashboard. Query parameters:
tier
string
required
The product tier to purchase. Must be one of basic, pro, or enterprise.
curl --request GET \
  --url "https://your-app.com/api/checkout?tier=pro" \
  --cookie "session=..."
Behavior:
ConditionResult
Valid tier, authenticatedRedirects to Stripe Checkout page
Valid tier, not authenticatedRedirects to /login?redirect=/api/checkout?tier={tier}
User already owns the tierRedirects to /dashboard
Invalid or missing tierReturns 400 with {"error": "Invalid tier specified"}
After successful payment, Stripe redirects to /dashboard?success=true&session_id={id}. If the user cancels, Stripe redirects to /pricing?canceled=true.

Available tiers

TierPriceIncludes
basic$199FastAPI + Next.js boilerplate, JWT auth, OAuth, Stripe subscriptions, Docker, CI/CD
pro$299Everything in Basic plus RAG pipeline, streaming LLM chat, admin dashboard, API keys
enterprise$499Everything in Pro plus fine-tuning scripts, multi-tenancy, usage-based billing
Promotion codes are supported. Stripe Checkout displays a promotion code field automatically.

GET /api/download

Download the purchased product as an AES-256 encrypted ZIP file. The ZIP password is the license key issued at purchase time. The license key is also returned in the X-License-Key response header. Query parameters:
purchase_id
string
The UUID of a specific purchase to download. If omitted, the most recent completed purchase is used.
curl --request GET \
  --url "https://your-app.com/api/download?purchase_id=abc123" \
  --cookie "session=..." \
  --output product.zip
Response headers:
HeaderDescription
Content-Typeapplication/zip
Content-Dispositionattachment; filename="Shipfastai-{tier}-{license_prefix}.zip"
X-License-KeyThe full license key used as the ZIP password

Rate limiting

Each user is limited to one download per purchase every 60 seconds. Requests within the cooldown window return 429:
{
  "error": "Please wait 45 seconds before downloading again."
}

Download limits

Each purchase has a maximum number of downloads (default: 5 for new purchases). Once the limit is reached, the purchase status changes to expired and further downloads are blocked.
{
  "error": "Download limit reached. Your license has expired. Please purchase a new license to continue downloading.",
  "expired": true
}

Error responses

StatusCondition
401Not authenticated
403No active purchase found, or download limit reached
404Product files not found for the given tier
429Rate limit — download requested too soon
500ZIP creation failed or unexpected error

GET /api/download/history

Retrieve the download history for the authenticated user. Returns the most recent 50 download log entries, ordered by download time (newest first). Query parameters:
purchase_id
string
Filter results to a specific purchase. If omitted, returns download logs across all purchases.
curl --request GET \
  --url "https://your-app.com/api/download/history?purchase_id=abc123" \
  --cookie "session=..."
Response — array of download log entries:
id
string
required
UUID of the download log entry.
purchase_id
string
required
UUID of the associated purchase.
user_id
string
required
UUID of the user who performed the download.
version
string
The product version that was downloaded (e.g., "1.0.0").
ip_address
string
IP address of the client at the time of download.
user_agent
string
User-Agent header of the client at the time of download.
country
string
Country code derived from the client IP address, if available.
downloaded_at
string
required
ISO 8601 timestamp of when the download occurred.
[
  {
    "id": "d4e5f6a1-b2c3-4d5e-f6a1-b2c3d4e5f6a1",
    "purchase_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "user_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "version": "1.0.0",
    "ip_address": "203.0.113.42",
    "user_agent": "Mozilla/5.0 ...",
    "country": "US",
    "downloaded_at": "2026-04-09T14:30:00Z"
  }
]

POST /api/stripe/webhook

Stripe webhook endpoint for the storefront. Handles purchase completion, payment confirmation, and refund events. This endpoint is called directly by Stripe, not by your application.
Do not call this endpoint from your application. Register it in the Stripe Dashboard as your webhook URL: https://your-app.com/api/stripe/webhook.
Headers required by Stripe:
stripe-signature
string
required
The Stripe-Signature header added automatically by Stripe. The backend verifies this against STRIPE_WEBHOOK_SECRET.

Handled events

Event typeEffect
checkout.session.completedCreates a purchase record with a generated license key, 5 max downloads, and 12-month update entitlement (entitled_until). Sends a purchase confirmation email.
payment_intent.succeededSame as checkout.session.completed. Falls back to looking up the checkout session if metadata is not on the payment intent directly.
charge.refundedSets the purchase status to refunded for the matching payment.
Response:
{
  "received": true
}
Returns 400 for an invalid payload or failed signature verification.

Local testing with the Stripe CLI

Forward events from Stripe to your local development server:
stripe listen --forward-to http://localhost:3000/api/stripe/webhook
Set the webhook signing secret printed by the CLI as STRIPE_WEBHOOK_SECRET in your .env.local.