tractatus/docs/KOHA_STRIPE_SETUP.md
TheFlow b3bd3b2348 feat: add multi-currency support and privacy policy to Koha system
Multi-Currency Implementation:
- Add currency configuration with 10 supported currencies (NZD, USD, EUR, GBP, AUD, CAD, JPY, CHF, SGD, HKD)
- Create client-side and server-side currency utilities for conversion and formatting
- Implement currency selector UI component with auto-detection and localStorage persistence
- Update Donation model to store multi-currency transactions with NZD equivalents
- Update Koha service to handle currency conversion and exchange rate tracking
- Update donation form UI to display prices in selected currency
- Update transparency dashboard to show donations with currency indicators
- Update Stripe setup documentation with currency_options configuration guide

Privacy Policy:
- Create comprehensive privacy policy page (GDPR compliant)
- Add shared footer component with privacy policy link
- Update all Koha pages with footer component

Technical Details:
- Exchange rates stored at donation time for historical accuracy
- All donations tracked in both original currency and NZD for transparency
- Base currency: NZD (New Zealand Dollar)
- Uses Stripe currency_options for monthly subscriptions
- Dynamic currency for one-time donations

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-08 15:17:23 +13:00

12 KiB

Koha Donation System - Stripe Setup Guide

Project: Tractatus Framework Feature: Phase 3 - Koha (Donation) System Date: 2025-10-08 Status: Development


Overview

The Koha donation system uses the existing Stripe account from passport-consolidated to process donations in multiple currencies. This document guides you through setting up the required Stripe products and webhooks.

Account: Same Stripe test account as passport-consolidated Currencies: 10 supported (NZD base + USD, EUR, GBP, AUD, CAD, JPY, CHF, SGD, HKD) Payment Types: Recurring monthly subscriptions + one-time donations Multi-Currency: Uses Stripe's currency_options feature for automatic conversion


1. Stripe Products to Create

Product: "Tractatus Framework Support"

Description: "Support the development and maintenance of the Tractatus AI Safety Framework. Your donation helps fund hosting, development, research, and community building."

Statement Descriptor: "TRACTATUS FRAMEWORK" Category: Charity/Non-profit


2. Price IDs to Create

2.1 Monthly Tier: $5 NZD/month

Product: Tractatus Framework Support
Price:   $5.00 NZD
Billing: Recurring - Monthly
ID:      price_<generated_by_stripe>

After creation, copy the Price ID and update .env:

STRIPE_KOHA_5_PRICE_ID=price_<your_actual_price_id>

2.2 Monthly Tier: $15 NZD/month

Product: Tractatus Framework Support
Price:   $15.00 NZD
Billing: Recurring - Monthly
ID:      price_<generated_by_stripe>

After creation, copy the Price ID and update .env:

STRIPE_KOHA_15_PRICE_ID=price_<your_actual_price_id>

2.3 Monthly Tier: $50 NZD/month

Product: Tractatus Framework Support
Price:   $50.00 NZD
Billing: Recurring - Monthly
ID:      price_<generated_by_stripe>

After creation, copy the Price ID and update .env:

STRIPE_KOHA_50_PRICE_ID=price_<your_actual_price_id>

2.4 One-Time Donation (Custom Amount)

Note: For one-time donations, we don't create a fixed price. Instead, the donation form sends a custom amount to Stripe Checkout. No Price ID needed for this - the code handles it dynamically.


2.5 Multi-Currency Setup with currency_options

IMPORTANT: To support multiple currencies with a single price ID, configure currency_options for each monthly tier price.

  1. Go to your product → Select a price (e.g., $5 NZD/month)
  2. Click Add currency in the pricing section
  3. Add each supported currency with converted amounts:
Base (NZD) USD EUR GBP AUD CAD JPY CHF SGD HKD
$5.00 $3.00 €2.75 £2.35 $4.65 $4.10 ¥470 2.65 $4.05 $23.40
$15.00 $9.00 €8.25 £7.05 $13.95 $12.30 ¥1410 7.95 $12.15 $70.20
$50.00 $30.00 €27.50 £23.50 $46.50 $41.00 ¥4700 26.50 $40.50 $234.00
  1. Repeat for all three monthly tier prices

Method 2: Stripe API

Update existing prices via Stripe API:

stripe prices update price_YOUR_5_NZD_PRICE_ID \
  --currency-options[usd][unit_amount]=300 \
  --currency-options[eur][unit_amount]=275 \
  --currency-options[gbp][unit_amount]=235 \
  --currency-options[aud][unit_amount]=465 \
  --currency-options[cad][unit_amount]=410 \
  --currency-options[jpy][unit_amount]=470 \
  --currency-options[chf][unit_amount]=265 \
  --currency-options[sgd][unit_amount]=405 \
  --currency-options[hkd][unit_amount]=2340

Repeat for $15 and $50 tier prices with their corresponding amounts.

Exchange Rate Calculation

Our base currency is NZD. Exchange rates (as of 2025-10-08):

1 NZD = 0.60 USD = 0.55 EUR = 0.47 GBP = 0.93 AUD = 0.82 CAD
      = 94.0 JPY = 0.53 CHF = 0.81 SGD = 4.68 HKD

Note: Rates are configurable in src/config/currencies.config.js. Update periodically or integrate live exchange rate API.

One-Time Donations (Dynamic Currency)

For one-time donations, the code dynamically creates Stripe checkout sessions with the selected currency:

sessionParams.line_items = [{
  price_data: {
    currency: currentCurrency.toLowerCase(), // e.g., 'usd', 'eur'
    unit_amount: amount // Amount in cents/smallest currency unit
  }
}];

No additional configuration needed - Stripe handles any supported currency.


3. Webhook Configuration

Create Webhook Endpoint

URL (Development):

http://localhost:9000/api/koha/webhook

URL (Production):

https://agenticgovernance.digital/api/koha/webhook

Events to Subscribe To

Select these events in Stripe Dashboard:

  • checkout.session.completed
  • payment_intent.succeeded
  • payment_intent.payment_failed
  • invoice.paid (recurring payments)
  • invoice.payment_failed
  • customer.subscription.created
  • customer.subscription.updated
  • customer.subscription.deleted

After Creating Webhook

Copy the Webhook Signing Secret and update .env:

STRIPE_KOHA_WEBHOOK_SECRET=whsec_<your_webhook_secret>

4. Testing Configuration

Stripe Test Cards

Use these test cards for development:

Card Number Scenario
4242 4242 4242 4242 Successful payment
4000 0027 6000 3184 3D Secure required
4000 0000 0000 9995 Payment declined
4000 0000 0000 0341 Attaching card fails

Expiry: Any future date CVC: Any 3 digits ZIP: Any valid postal code


5. Step-by-Step Setup Instructions

Step 1: Access Stripe Dashboard

  1. Go to dashboard.stripe.com
  2. Ensure you're in Test Mode (toggle in top-right)
  3. Log in with passport-consolidated credentials

Step 2: Create Product

  1. Navigate to ProductsAdd Product
  2. Product name: Tractatus Framework Support
  3. Description: Support the development and maintenance of the Tractatus AI Safety Framework
  4. Image: Upload /home/theflow/projects/tractatus/public/images/tractatus-icon.svg
  5. Click Save Product

Step 3: Create Price IDs

For each monthly tier ($5, $15, $50):

  1. In the product page, click Add another price
  2. Select Recurring
  3. Billing period: Monthly
  4. Price: Enter amount (e.g., 5.00)
  5. Currency: NZD
  6. Click Save
  7. Copy the Price ID (starts with price_)
  8. Paste into .env file

Step 4: Set Up Webhook

  1. Navigate to DevelopersWebhooks
  2. Click Add endpoint
  3. Endpoint URL: http://localhost:9000/api/koha/webhook (for development)
  4. Description: Tractatus Koha - Development
  5. Events to send: Select all 8 events listed in Section 3
  6. Click Add endpoint
  7. Copy the Signing Secret (click "Reveal")
  8. Update .env with the webhook secret

Step 5: Verify Configuration

Run this command to test:

npm run dev

Check logs for:

✅ Stripe webhook ready: /api/koha/webhook
✅ Koha service initialized

6. Environment Variables Checklist

After setup, your .env should have:

# Stripe Keys (from passport-consolidated)
STRIPE_SECRET_KEY=sk_test_51RX67k...
STRIPE_PUBLISHABLE_KEY=pk_test_51RX67k...

# Webhook Secret (from Step 4)
STRIPE_KOHA_WEBHOOK_SECRET=whsec_...

# Price IDs (from Step 3)
STRIPE_KOHA_5_PRICE_ID=price_...
STRIPE_KOHA_15_PRICE_ID=price_...
STRIPE_KOHA_50_PRICE_ID=price_...

# Frontend URL
FRONTEND_URL=http://localhost:9000

7. Testing the Integration

Test API Endpoint

Test 1: Monthly donation in NZD

curl -X POST http://localhost:9000/api/koha/checkout \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 1500,
    "currency": "NZD",
    "frequency": "monthly",
    "tier": "15",
    "donor": {
      "name": "Test Donor",
      "email": "test@example.com"
    },
    "public_acknowledgement": false
  }'

Test 2: One-time donation in USD

curl -X POST http://localhost:9000/api/koha/checkout \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 2500,
    "currency": "USD",
    "frequency": "one_time",
    "tier": "custom",
    "donor": {
      "name": "US Donor",
      "email": "us@example.com"
    },
    "public_acknowledgement": true,
    "public_name": "Anonymous US Supporter"
  }'

Expected Response:

{
  "success": true,
  "data": {
    "sessionId": "cs_test_...",
    "checkoutUrl": "https://checkout.stripe.com/c/pay/cs_test_...",
    "frequency": "monthly",
    "amount": 15
  }
}

Test Webhook Locally

Use Stripe CLI for local webhook testing:

# Install Stripe CLI
brew install stripe/stripe-cli/stripe

# Forward webhooks to local server
stripe listen --forward-to localhost:9000/api/koha/webhook

# Trigger test event
stripe trigger checkout.session.completed

8. Production Setup

Before Going Live

  1. Switch to Live Mode in Stripe Dashboard
  2. Create live webhook endpoint:
    • URL: https://agenticgovernance.digital/api/koha/webhook
    • Same 8 events as development
  3. Obtain live API keys (starts with sk_live_ and pk_live_)
  4. Update production .env with live keys
  5. Test with real card (small amount)
  6. Verify webhook delivery in Stripe Dashboard

Production Environment Variables

NODE_ENV=production
STRIPE_SECRET_KEY=sk_live_...
STRIPE_PUBLISHABLE_KEY=pk_live_...
STRIPE_KOHA_WEBHOOK_SECRET=whsec_live_...
FRONTEND_URL=https://agenticgovernance.digital

9. Monitoring & Troubleshooting

Check Webhook Deliveries

  1. Stripe Dashboard → DevelopersWebhooks
  2. Click on your endpoint
  3. View Recent deliveries
  4. Check for failed deliveries (red icons)

Common Issues

Issue Solution
Webhook signature verification fails Ensure STRIPE_KOHA_WEBHOOK_SECRET matches Dashboard
Price ID not found Verify Price IDs in .env match Stripe Dashboard
Redirects fail after payment Check FRONTEND_URL is correct
Donations not recording Check MongoDB connection and logs

Debug Logging

Enable detailed Stripe logs:

# In koha.service.js, logger.info statements will show:
[KOHA] Creating checkout session: monthly donation of USD $9.00 (NZD $15.00)
[KOHA] Checkout session created: cs_test_...
[KOHA] Processing webhook event: checkout.session.completed
[KOHA] Checkout completed: monthly donation, tier: 15, currency: USD
[KOHA] Donation recorded: USD $9.00 (NZD $15.00)
[KOHA] Recurring donation recorded: EUR $8.25 (NZD $15.00)

10. Security Considerations

Webhook Security

  • Signature verification enabled (via verifyWebhookSignature)
  • Raw body parsing for Stripe webhooks
  • HTTPS required in production
  • Rate limiting on API endpoints

Data Privacy

  • Donor emails stored securely (for receipts only)
  • Anonymous donations by default
  • Opt-in public acknowledgement
  • No credit card data stored (handled by Stripe)

PCI Compliance

  • Using Stripe Checkout (PCI compliant)
  • No card data touches our servers
  • Stripe handles all payment processing

11. Next Steps

After completing this setup:

  1. Test donation flow end-to-end
  2. Create frontend donation form UI
  3. Build transparency dashboard
  4. Implement receipt email generation
  5. Add donor acknowledgement system
  6. Deploy to production

Support

Issues: Report in GitHub Issues Questions: Contact john.stroh.nz@pm.me Stripe Docs: https://stripe.com/docs/api


Last Updated: 2025-10-08 Version: 1.0 Status: Ready for setup