Simplified Offering System Guide
Overview
The offering system supports external payment links from any payment provider (Stripe, PayPal, etc.) with generic webhook verification.
How It Works
1. Admin Creates an Offering
- Go to Admin Panel → Offerings → "Create New Offering"
- Fill in basic information:
- Name, description, image
- Select communities to grant access
- Set a single price (in cents)
- Choose pricing type (one-time, monthly, yearly)
- Important: Add your external payment link
- This can be from Stripe, PayPal, or any payment service
- Example:
https://buy.stripe.com/test_...orhttps://paypal.me/...
- Save the offering
2. System Generates Webhook URL
When you create an offering, the system automatically generates:
- Webhook URL:
/webhooks/offerings/{offering-id} - Webhook Secret: A secure random string for verification
You can find these in the database or by querying the offering.
3. Configure Your Payment Provider
After creating the offering, configure your payment provider's webhook:
For Stripe
- Go to Stripe Dashboard → Developers → Webhooks
- Add endpoint:
https://your-domain.com/webhooks/offerings/{offering-id} - Select events:
checkout.session.completed - Add custom header:
x-offering-secret: {your-webhook-secret}
For PayPal
- Go to PayPal Developer Dashboard → Webhooks
- Add webhook URL:
https://your-domain.com/webhooks/offerings/{offering-id} - Select events:
PAYMENT.SALE.COMPLETED - Add custom header:
x-offering-secret: {your-webhook-secret}
For Other Providers
Configure the webhook to POST to the offering webhook URL with the payment details.
4. User Purchase Flow
- User browses offerings at
/offerings - User clicks "Get Started" on an offering
- User clicks "Proceed to Payment"
- System creates a pending purchase record
- User is redirected to your external payment link
- User completes payment on external site
- Payment provider sends webhook to our system
- System verifies webhook and grants access automatically
Webhook Payload Format
The webhook handler accepts flexible payload formats. Send a POST request with:
Required Fields
{
"status": "succeeded",
"user_id": "uuid",
"user_email": "email",
"purchase_id": "uuid"
}
Optional Fields
{
"payment_id": "external_payment_id",
"external_payment_id": "stripe_payment_intent_id",
"amount": 2500,
"currency": "USD"
}
Webhook Security
The webhook handler verifies requests using the webhook secret. Include it in one of these ways:
-
Custom Header (Recommended):
x-offering-secret: your-webhook-secret-here -
Authorization Header:
Authorization: Bearer your-webhook-secret-here
Access Provisioning
When a webhook is verified:
- Purchase status is updated to "succeeded"
- User is automatically added to all communities in the offering
- Access is marked as granted with timestamp
- User receives immediate access to all content
Testing
Manual Webhook Testing
curl -X POST https://your-domain.com/webhooks/offerings/{offering-id} \
-H "Content-Type: application/json" \
-H "x-offering-secret: your-webhook-secret" \
-d '{
"status": "succeeded",
"user_id": "user-uuid",
"external_payment_id": "test_payment_123"
}'
Testing Purchase Flow
- Create a test offering with a test payment link
- As a non-admin user, go to
/offerings - Click "Get Started" on the offering
- Click "Proceed to Payment"
- System creates pending purchase
- Manually trigger webhook (as shown above)
- Verify access is granted
Troubleshooting
Payment Not Processing
- Check webhook logs in your dashboard
- Verify webhook secret is correct
- Ensure
status: "succeeded"is in payload - Check that user_id, user_email, or purchase_id is provided
Access Not Granted
- Verify purchase status changed to "succeeded"
- Check
access_granted_attimestamp - Verify user was added to community
- Check function logs for errors
Webhook 404 Error
- Verify offering ID in webhook URL matches actual offering ID
- Check that offering exists in database
Webhook 401 Error
- Verify webhook secret matches
- Check header format (x-offering-secret or Authorization)
Best Practices
- Always test webhooks before going live
- Store webhook secrets securely - don't expose them in frontend code
- Monitor webhook logs for failed payments
- Set up payment provider alerts for webhook failures
- Use HTTPS for all webhook endpoints
- Keep webhook URLs consistent - don't change offering IDs after setup
- Provide clear payment success page on your payment provider
- Handle edge cases - duplicate webhooks, delayed webhooks, etc.