patx/projectpay

Get paid for freelance projects with Stripe and no-nonsense!

$ git clone https://gitman.io/git/patx/projectpay

ProjectPay

ProjectPay is a small web app for creating project payment pages and collecting payments through Stripe Checkout. It gives an admin user a private project dashboard, creates shareable payment links for customers, and records successful Stripe payments against each project.

Features

  • Password-protected admin area
  • Create, edit, search, and delete projects
  • Line-item project pricing with scope and terms text
  • Public, tokenized project payment pages
  • Stripe Checkout payment flow
  • Stripe webhook handling for successful payments
  • Payment history and automatic paid/open project status updates
  • MongoDB-backed storage

Tech Stack

  • Python ASGI app built with micropie
  • MongoDB via pymongo
  • Stripe Checkout and webhooks via stripe
  • Uvicorn for local and production serving

Requirements

  • Python 3.10 or newer recommended
  • MongoDB
  • Stripe account, if you want live payment collection

Local Setup

  1. Create and activate a virtual environment:

bash python3 -m venv .venv source .venv/bin/activate

  1. Install dependencies:

bash pip install -r requirements.txt

  1. Start MongoDB locally, or point the app at a hosted MongoDB database.

  2. Create a .env file:

```bash ADMIN_PASSWORD=change-me ADMIN_COOKIE_SECRET=replace-with-a-long-random-secret MONGODB_URI=mongodb://localhost:27017 MONGODB_DB=projectpay APP_BASE_URL=http://127.0.0.1:8000 PUBLIC_LOGO_URL= PUBLIC_LOGO_ALT=ProjectPay Logo

STRIPE_SECRET_KEY= STRIPE_WEBHOOK_SECRET= STRIPE_PRODUCT_ID= STRIPE_CURRENCY=usd STRIPE_MINIMUM_AMOUNT_CENTS=100 ```

  1. Run the app:

bash python3 app.py

  1. Open http://127.0.0.1:8000/login and sign in with ADMIN_PASSWORD.

Environment Variables

Variable Required Default Description
ADMIN_PASSWORD Recommended admin Password for the admin dashboard. Change this before deploying.
ADMIN_COOKIE_SECRET Recommended Falls back to APP_SECRET, then ADMIN_PASSWORD Secret used to sign the admin cookie. Use a long random value in production.
APP_SECRET Optional unset Fallback cookie secret if ADMIN_COOKIE_SECRET is not set.
APP_BASE_URL Recommended in production Derived from request headers Public base URL used to generate customer payment links and Stripe return URLs.
PUBLIC_LOGO_URL Optional unset Logo image URL shown on public project payment pages. No logo is shown when this is empty.
PUBLIC_LOGO_ALT Optional ProjectPay Logo Alt text for the public payment page logo.
MONGODB_URI Optional mongodb://localhost:27017 MongoDB connection string.
MONGODB_DB Optional invoice_maker MongoDB database name. Use projectpay or another explicit name for new installs.
MONGODB_SERVER_SELECTION_TIMEOUT_MS Optional 5000 MongoDB connection timeout in milliseconds.
STRIPE_SECRET_KEY Required for payments unset Stripe secret API key.
STRIPE_WEBHOOK_SECRET Required for webhook processing unset Signing secret for the Stripe webhook endpoint.
STRIPE_PRODUCT_ID Required for payments unset Stripe Product ID used when creating custom-amount prices.
STRIPE_CURRENCY Optional usd Currency for Stripe Checkout and display formatting.
STRIPE_MINIMUM_AMOUNT_CENTS Optional 100 Minimum customer payment amount in cents.
HOST Optional 127.0.0.1 Host used by python3 app.py.
PORT Optional 8000 Port used by python3 app.py and the included Procfile.

Stripe Setup

  1. Create a Product in Stripe and copy its product ID into STRIPE_PRODUCT_ID.
  2. Add a webhook endpoint that points to:

text https://your-domain.example/webhook/stripe

  1. Subscribe the webhook endpoint to the checkout.session.completed event. If you enable delayed payment methods, also subscribe to checkout.session.async_payment_succeeded.
  2. Copy the webhook signing secret into STRIPE_WEBHOOK_SECRET.
  3. Set STRIPE_SECRET_KEY to your Stripe secret key.

ProjectPay records payments from signed Stripe webhooks. The customer return page may show a thank-you message immediately after Checkout redirects back, but the project balance is updated only after a successful payment webhook is received and processed.

For local webhook testing, use the Stripe CLI:

stripe listen --forward-to localhost:8000/webhook/stripe

Then copy the whsec_... value from the Stripe CLI output into STRIPE_WEBHOOK_SECRET.

Usage

  1. Sign in at /login.
  2. Create a project with a customer name, optional email, line items, and scope or terms.
  3. Open the project detail page and copy the generated payment link.
  4. Send the payment link to the customer.
  5. The customer opens the public project page and clicks Make a Payment.
  6. Stripe Checkout collects the payment.
  7. Stripe sends a webhook back to ProjectPay, and the payment is recorded.

Deployment

The included Procfile runs the app with Uvicorn:

web: uvicorn app:app --host 0.0.0.0 --port $PORT

For production, set at least:

  • ADMIN_PASSWORD
  • ADMIN_COOKIE_SECRET
  • APP_BASE_URL
  • MONGODB_URI
  • MONGODB_DB
  • STRIPE_SECRET_KEY
  • STRIPE_WEBHOOK_SECRET
  • STRIPE_PRODUCT_ID

Use HTTPS in production so Stripe webhooks and customer payment redirects work reliably.

Customization

  • Set PUBLIC_LOGO_URL and PUBLIC_LOGO_ALT to brand the public payment page.
  • Update styles in templates/base.html.
  • The current default database name is invoice_maker; set MONGODB_DB=projectpay for a fresh ProjectPay deployment.
  • Currency formatting is optimized for USD. Non-USD currencies display as CURRENCY amount.

Data Model

ProjectPay creates and manages these MongoDB collections:

  • projects
  • payments
  • checkout_sessions
  • webhook_events
  • counters

Indexes are created automatically when the app first touches the database.

Security Notes

  • Do not deploy with the default ADMIN_PASSWORD=admin.
  • Use a long random ADMIN_COOKIE_SECRET.
  • Keep Stripe and MongoDB credentials out of source control.
  • The public project URL uses a random share token, but anyone with the link can view the project payment page.

License

ProjectPay is released under the MIT License.