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:

.env
EVENT_API_SECRET=your_generated_secret_here

Never commit .env to version control. It's already in .gitignore.

Verify Configuration

The secret is validated in env.ts:

env.ts (excerpt)
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

prisma/schema.prisma
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_events

If the Event model already exists, no migration is needed.

Generate Prisma Client

After schema changes, regenerate the Prisma client:

npx prisma generate

Stripe 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:

Webhook handler (excerpt)
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: true create 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:

  1. Create a Featured Coupon in Stripe Dashboard:

    • Go to ProductsCoupons
    • Click Create coupon
    • Set name: "LAUNCH50"
    • Set discount: 50% off
    • Add metadata: isFeatured = true
    • Click Create coupon
  2. Verify Event Creation:

    • Open Postman
    • Send GET request to https://yourdomain.com/api/events
    • You should see the event with text "LAUNCH50"
  3. 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 DevelopersWebhooks.

Rate Limiting

The Events API uses rate limiting to prevent abuse:

Rate limiting
// 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 .env to 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:

validationSchemas/eventSchema.ts
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:

  1. Verify .env contains EVENT_API_SECRET
  2. Restart dev server after adding the variable
  3. Check Authorization header format: Bearer your_secret

Events Not Appearing

Cause: Cache not revalidated or event not created

Solution:

  1. Check if event exists: GET https://yourdomain.com/api/events
  2. Verify revalidateTag('event', 'max') is called
  3. Clear browser cache and refresh

Stripe Webhook Not Creating Events

Cause: Webhook not configured or missing isFeatured metadata

Solution:

  1. Verify webhook endpoint is active in Stripe Dashboard
  2. Check webhook logs for errors
  3. Ensure coupon has isFeatured: true metadata
  4. Verify STRIPE_WEBHOOK_SECRET is correct

Next Steps

How is this guide ?

Last updated on

On this page