Skip to content

Payments ​

Collect event fees with Stripe or PayPal, manage pricing tiers and add-ons, and handle refunds.

Quick outcome ​

The payment system supports per-attendee and flat-fee pricing with optional add-ons. Attendees pay through hosted Stripe or PayPal checkout. Organizers monitor payments, process refunds, and export records from the admin dashboard.

Setup ​

Configure payment methods ​

In /admin/settings, set the enabled payment methods:

MethodRequirements
StripeSTRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET in environment or per-event settings
PayPalpaypalClientId, paypalClientSecret, paypalWebhookId in event settings

Per-event payment credentials can override the global environment variables, allowing different events to use different Stripe/PayPal accounts.

First-time setup?

See Stripe (Payments) and PayPal (Payments) for account creation, API key generation, and webhook configuration.

Set up pricing tiers ​

Navigate to /admin/pricing-tiers to define attendee types:

FieldExampleDescription
Name"Adult (18+)"Display name in RSVP and payment forms
Multiplier1.0Price multiplier (1.0 = full, 0.5 = half, 0 = free)

Common setup:

  • Adult: multiplier 1.0
  • Child (6-17): multiplier 0.5
  • Infant (0-5): multiplier 0

Create add-ons ​

Navigate to /admin/add-ons to define billable items:

FieldDescription
NameDisplay name (e.g., "Accommodation", "Activity Fee")
DescriptionWhat the add-on covers
Amount (cents)Base price in cents (e.g., 15000 for $150.00)
CurrencyCurrency code (default: usd)
OptionalIf true, attendees can choose whether to include it
Per attendeeIf true, charged per person; if false, flat fee per RSVP
Tier pricesOptional explicit price per tier (overrides multiplier calculation)

Per-attendee pricing example: A $100 "Activity Fee" add-on with per-attendee enabled. An RSVP with 2 adults (1.0x) and 1 child (0.5x) pays: $100 + $100 + $50 = $250.

Flat-fee example: A $200 "Cabin Rental" add-on with per-attendee disabled. Each RSVP pays $200 regardless of party size.

Tier prices override: If the Activity Fee has explicit tier prices ({ "adult": 10000, "child": 3000 }), those amounts are used instead of the multiplier calculation.

Day-to-day management ​

Payment dashboard ​

Open /admin/payments to see all payment records:

ColumnDescription
PayerEmail and name
AmountPayment amount
Statuspending, completed, failed, refunded, partial_refund
Methodstripe, paypal, or manual
DatePayment creation timestamp

Recording manual payments ​

For cash, check, or other offline payments, create manual payment records with:

  • Payer details
  • Amount
  • Optional note describing the payment method

Processing refunds ​

From a completed payment record:

  1. Click the refund action
  2. Enter the refund amount (full or partial)
  3. Provide a refund reason
  4. Confirm — the refund is processed through Stripe/PayPal

Refund status progresses: completed → refunding → refunded (or partial_refund).

Exporting payments ​

Export payment data for accounting or reconciliation. The export includes all payment fields, statuses, and amounts.

Attendee experience ​

Payment page ​

Attendees visit /pay to see available expense cards:

  • Each add-on is shown as a card with name, description, and price
  • Optional add-ons can be selected/deselected
  • Required add-ons are always included
  • The total updates based on selections and attendee count

Checkout flow ​

  1. Attendee selects items and clicks "Pay"
  2. Redirected to Stripe hosted checkout (or PayPal)
  3. Enters payment details on the secure checkout page
  4. On success → redirected to /pay/success
  5. On cancel → redirected to /pay/cancel

Webhook reconciliation ​

After checkout, Stripe sends a webhook to /api/stripe/webhook:

  1. Webhook verifies the signature using SubtleCryptoProvider
  2. Payment status updated from pending to completed
  3. Payment intent and session IDs recorded

TIP

If a payment shows as completed in Stripe but still pending in the admin, the webhook likely failed. Check the Stripe dashboard for webhook delivery history.

Troubleshooting ​

SymptomFix
Checkout doesn't openVerify Stripe credentials in settings or environment
Success page but admin shows pendingWebhook not delivered — check Stripe webhook dashboard
Wrong totalVerify tier multipliers, explicit tier prices, and add-on amounts
Refund blockedCheck payment intent state in Stripe dashboard
Manual payment not appearingConfirm the record was saved with correct event ID
Export incompleteCheck date range and status filters

Next steps ​

Released under the MIT License.