Setup & Configuration
Learn how to configure events in Plainform
Configure the Events system to secure your API and enable automatic event creation from Stripe coupons.
Environment Variables
The Events API requires one environment variable for authentication.
EVENT_API_SECRET
This secret key protects your Events API from unauthorized access. Required for all POST and DELETE requests.
Generate a Secret Key
Generate a secure random string:
# Using OpenSSL
openssl rand -base64 32
# Using Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"Add to Environment File
Add the secret to your .env file:
EVENT_API_SECRET=your_generated_secret_hereNever commit .env to version control. It's already in .gitignore.
Verify Configuration
The secret is validated in env.ts:
export const env = createEnv({
server: {
EVENT_API_SECRET: z.string().min(5),
// ... other variables
},
runtimeEnv: {
EVENT_API_SECRET: process.env.EVENT_API_SECRET,
},
});If missing or invalid, the app fails to start with a validation error.
Database Setup
Events are stored in PostgreSQL using Prisma ORM.
Schema
model Event {
id String @id @default(cuid())
type String // 'post', 'coupon', or 'product'
slug String // URL to link to
text String // Display text
icon String? // Optional icon name
timestamp BigInt // Creation timestamp
@@index([type])
}Migration
If setting up a fresh database, run migrations:
npx prisma migrate dev --name add_eventsIf the Event model already exists, no migration is needed.
Generate Prisma Client
After schema changes, regenerate the Prisma client:
npx prisma generateStripe Webhook Configuration
Enable automatic event creation from Stripe coupons. Events are created when you add a coupon with isFeatured: true metadata.
For complete Stripe webhook setup instructions, see Payments Setup & Configuration.
Webhook Handler
The webhook in app/api/webhooks/route.ts automatically creates events for featured coupons:
switch (event.type) {
case 'coupon.created':
case 'coupon.updated':
if (event?.data?.object?.metadata?.isFeatured === 'true') {
await recordEvent({
text: event?.data?.object?.name as string,
slug: '#coupon',
type: 'coupon',
});
revalidateTag('event', 'max');
}
break;
case 'coupon.deleted':
if (event?.data?.object?.metadata?.isFeatured === 'true') {
await deleteEventByType('coupon');
}
break;
}Key points:
- Only coupons with
isFeatured: truecreate events - Event text uses the coupon name
- Event slug is set to
#coupon(links to pricing section)
Testing the Integration
Test automatic event creation from Stripe:
-
Create a Featured Coupon in Stripe Dashboard:
- Go to Products → Coupons
- Click Create coupon
- Set name: "LAUNCH50"
- Set discount: 50% off
- Add metadata:
isFeatured=true - Click Create coupon
-
Verify Event Creation:
- Open Postman
- Send GET request to
https://yourdomain.com/api/events - You should see the event with text "LAUNCH50"
-
Check Homepage:
- Visit your homepage
- The event should appear at the top with animated effects
If the event doesn't appear, check webhook logs in Stripe Dashboard under Developers → Webhooks.
Rate Limiting
The Events API uses rate limiting to prevent abuse:
// 10 requests per 10 seconds per IP
const identifier = getClientIdentifier(req);
const rateLimitResult = rateLimiters.standard(identifier);
if (!rateLimitResult.success) {
return createRateLimitResponse(rateLimitResult);
}Default limits:
- 10 requests per 10 seconds per IP
- Applies to POST and DELETE only
- GET requests are not rate limited
Security Best Practices
Protect Your API Secret
- Never commit
.envto version control - Use different secrets for development and production
- Rotate secrets periodically
- Store production secrets in your hosting platform's environment variables
Validate Input
All event data is validated with Zod:
export const eventSchema = z.object({
text: z.string().min(3).max(500).trim(),
type: z.enum(['post', 'coupon', 'product']),
slug: z.string().min(1).max(500).trim(),
icon: z.string().optional(),
});Troubleshooting
"Unauthorized. Invalid API secret"
Cause: Missing or incorrect EVENT_API_SECRET
Solution:
- Verify
.envcontainsEVENT_API_SECRET - Restart dev server after adding the variable
- Check Authorization header format:
Bearer your_secret
Events Not Appearing
Cause: Cache not revalidated or event not created
Solution:
- Check if event exists: GET
https://yourdomain.com/api/events - Verify
revalidateTag('event', 'max')is called - Clear browser cache and refresh
Stripe Webhook Not Creating Events
Cause: Webhook not configured or missing isFeatured metadata
Solution:
- Verify webhook endpoint is active in Stripe Dashboard
- Check webhook logs for errors
- Ensure coupon has
isFeatured: truemetadata - Verify
STRIPE_WEBHOOK_SECRETis correct
Next Steps
- Usage & Integration - Create and manage events
- Payments Setup - Configure Stripe webhooks
How is this guide ?
Last updated on