Files

9.3 KiB

Billing Setup Guide

This guide covers how to configure Stripe billing and local user sign-up in DocuElevate.

Table of Contents


Local User Sign-up

By default, user accounts are created by an administrator. To allow users to self-register with an email address and password, set ALLOW_LOCAL_SIGNUP=true.

Note: SMTP is optional for local sign-up. When SMTP is configured, new accounts require email verification before they can log in. Without SMTP, accounts are activated immediately upon registration — useful for self-hosted deployments without email infrastructure.

Configuration

ALLOW_LOCAL_SIGNUP=true

# SMTP (optional — enables email verification and password reset)
EMAIL_HOST=smtp.example.com
EMAIL_PORT=587
EMAIL_USERNAME=noreply@example.com
EMAIL_PASSWORD=yourpassword
EMAIL_USE_TLS=true
EMAIL_SENDER=DocuElevate <noreply@example.com>

Sign-up Flow

With SMTP configured (recommended):

  1. User visits /signup and fills out the registration form.
  2. DocuElevate sends a verification email with a 24-hour token link.
  3. User clicks the link — their account is activated and they are signed in.
  4. First-time users are redirected to the onboarding wizard.

Without SMTP:

  1. User visits /signup and fills out the registration form.
  2. Account is activated immediately — no email verification required.
  3. User is redirected to the login page to sign in straight away.

Admin-Created Accounts

Administrators can create local user accounts directly from the Admin → User Management page without requiring self-registration. Admin-created accounts are immediately active regardless of SMTP configuration.

Password Reset Flow

  1. User clicks "Forgot password?" on the login page.
  2. User enters their email address.
  3. DocuElevate sends a password reset email with a 24-hour token link.
  4. User clicks the link, enters a new password, and is redirected to sign in.

Security

  • Passwords are hashed with bcrypt (12 rounds).
  • Verification and reset tokens are 256-bit URL-safe random strings.
  • All tokens expire after 24 hours.
  • Sign-up and login endpoints return generic error messages to prevent user enumeration.

Stripe Billing Integration

DocuElevate integrates with Stripe to handle subscription payments. Stripe acts as a data processor under a Data Processing Agreement (DPA) and is SOC 2 Type II certified.

Prerequisites

  • A Stripe account (sign up at stripe.com)
  • A publicly reachable webhook endpoint (or use Stripe CLI for local testing)

Configuration

STRIPE_SECRET_KEY=sk_live_...         # Your Stripe secret key
STRIPE_PUBLISHABLE_KEY=pk_live_...    # Your Stripe publishable key (for frontend)
STRIPE_WEBHOOK_SECRET=whsec_...       # Webhook signing secret
STRIPE_SUCCESS_URL=https://app.example.com/api/billing/success  # Optional override
STRIPE_CANCEL_URL=https://app.example.com/pricing               # Optional override

Security: Never commit your Stripe secret key. Store it in your environment or secrets manager.

DocuElevate includes a built-in Stripe Setup Wizard at /admin/stripe-wizard that guides you through the complete setup in three steps:

  1. Verify API Keys — checks that your Stripe secret key is configured and the connection to Stripe is working.
  2. Sync Plans to Stripe — automatically creates Stripe Products and Prices for every paid plan defined in DocuElevate, then stores the resulting price_id values back in the database. Free plans are skipped; plans that already have a price ID are left unchanged.
  3. Configure Webhook — shows the exact webhook endpoint URL to register in the Stripe Dashboard and which events to subscribe to.

You can also reach the wizard from the Admin → Plans page via the Stripe Setup button.

Auto-sync API

The sync step is also available as an API endpoint for automation:

curl -X POST https://your-app.example.com/api/billing/stripe/sync-plans \
  -H "Cookie: <admin-session-cookie>"

Response:

{
  "results": [
    {
      "plan_id": "starter",
      "name": "Starter",
      "status": "created",
      "stripe_price_id_monthly": "price_1OtAbc...",
      "stripe_price_id_yearly": "price_1OtDef..."
    },
    {
      "plan_id": "free",
      "name": "Free",
      "status": "skipped_free"
    }
  ]
}

Possible status values:

Status Meaning
created Stripe product and price(s) were created and saved
already_synced Plan already had a price ID — no changes made
skipped_free Free plan (price is $0) — no Stripe price needed
error Stripe API call failed — detail contains the error message

Stripe connection status API

curl https://your-app.example.com/api/billing/stripe/status

Returns connection health, API mode (test/live), webhook secret status, and per-plan sync status.

Setting Up Plans Manually

If you prefer to enter price IDs yourself rather than using the wizard:

  1. Create Products and Prices in the Stripe Dashboard.
  2. Go to Admin → Plans in DocuElevate and click the Edit (pencil) button for a paid plan.
  3. Scroll to the Stripe Integration section in the plan editor.
  4. Enter the Stripe Price ID (monthly) (e.g. price_1OtAbc...).
  5. Optionally enter the Stripe Price ID (yearly) for annual billing.
  6. Save the plan.

Stable link: DocuElevate stores the Stripe customer_id in the UserProfile.stripe_customer_id column and matches it on every webhook event. This is the stable link between Stripe billing profiles and DocuElevate accounts. It is set automatically when a user completes their first checkout.

Webhook Configuration

Stripe webhooks allow DocuElevate to sync subscription status in real time.

Stripe Dashboard setup

  1. Go to Developers → Webhooks in the Stripe Dashboard.
  2. Click Add endpoint.
  3. Set the endpoint URL to: https://your-app-domain.com/api/billing/webhook (The Stripe Setup Wizard shows the exact URL for your deployment.)
  4. Select the following events:
    • checkout.session.completed
    • customer.subscription.updated
    • customer.subscription.deleted
    • invoice.payment_failed
  5. Copy the Signing secret and set STRIPE_WEBHOOK_SECRET in your environment.

Local testing with Stripe CLI

# Install Stripe CLI and log in
stripe login

# Forward webhooks to your local server
stripe listen --forward-to http://localhost:8000/api/billing/webhook

# Trigger test events
stripe trigger checkout.session.completed
stripe trigger customer.subscription.updated
stripe trigger customer.subscription.deleted

Billing Flows

Subscribe to a plan

  1. User visits /pricing.
  2. User clicks the CTA button on a paid plan.
  3. DocuElevate calls POST /api/billing/create-checkout-session.
  4. User is redirected to Stripe Checkout.
  5. After payment, Stripe fires checkout.session.completed.
  6. DocuElevate webhook handler activates the subscription tier and stores the Stripe customer_id.
  7. User is redirected to /api/billing/success.

Manage or cancel subscription

  1. User visits their account settings.
  2. DocuElevate calls POST /api/billing/create-portal-session.
  3. User is redirected to the Stripe Customer Portal.
  4. User can update payment method, upgrade, downgrade, or cancel.
  5. Stripe fires customer.subscription.updated or customer.subscription.deleted.
  6. DocuElevate webhook handler syncs the change.

Cancellation

When a subscription is cancelled, Stripe fires customer.subscription.deleted and DocuElevate automatically downgrades the user to the free tier.


Compliance Notes

Topic Details
GDPR Stripe acts as a data processor. A Data Processing Agreement (DPA) is available in the Stripe Dashboard. Stripe supports EU data residency.
SOC 2 Stripe is SOC 2 Type II certified.
EU VAT Configure Stripe Tax in the Stripe Dashboard for automatic VAT collection.
PCI DSS Card data is handled entirely by Stripe. DocuElevate never sees or stores card details.

Environment Variable Reference

Variable Type Default Description
ALLOW_LOCAL_SIGNUP bool false Allow users to self-register with email/password
STRIPE_SECRET_KEY string Stripe API secret key
STRIPE_PUBLISHABLE_KEY string Stripe API publishable key
STRIPE_WEBHOOK_SECRET string Webhook signing secret from Stripe Dashboard
STRIPE_SUCCESS_URL string Override redirect URL after successful checkout
STRIPE_CANCEL_URL string Override redirect URL when checkout is cancelled

See ConfigurationGuide.md for the full environment variable reference.