PriceLogicPriceLogic

The AI Platform for Marketplace Sellers

© Copyright 2025 PriceLogic, Inc. All Rights Reserved.

About
  • Blog
  • Contact
Product
  • Pricing
Legal
  • Terms of Service
  • Privacy Policy
  • Cookie Policy
  • Getting started with PriceLogic
    • Quick Start
    • Project Structure
    • Configuration
  • Diana API
  • Email & Password
  • Database
    • Database Overview
    • Migrations
    • Row Level Security
    • Querying Data
    • Functions & Triggers
  • OAuth
  • Features
    • Features Overview
    • Team Collaboration
    • File Uploads
  • Magic Links
  • Billing & Payments
    • Billing Overview
    • Pricing Plans
    • Webhook Integration

Webhook Integration

Setting up and handling payment provider webhooks for subscription events.

Note: This is mock/placeholder content for demonstration purposes.

Webhooks notify your application when billing events occur, ensuring your app stays synchronized with your payment provider.

Why Webhooks?

Webhooks are essential for:

  • Real-time updates - Instant notification of payment events
  • Reliability - Handles events even if users close their browser
  • Security - Server-to-server communication
  • Automation - Automatic subscription status updates

Webhook Endpoint

Your webhook endpoint receives events from the payment provider:

// app/api/billing/webhook/route.ts
export async function POST(request: Request) {
  const body = await request.text();
  const signature = request.headers.get('stripe-signature');

  // Verify webhook signature
  const event = stripe.webhooks.constructEvent(
    body,
    signature,
    process.env.STRIPE_WEBHOOK_SECRET
  );

  // Handle the event
  await handleBillingEvent(event);

  return new Response('OK', { status: 200 });
}

Common Events

Subscription Created

case 'customer.subscription.created':
  await prisma.subscription.create({
    data: {
      id: event.data.object.id,
      accountId: event.data.object.metadata.accountId,
      status: 'active',
      planId: event.data.object.items.data[0].price.id,
      currentPeriodEnd: new Date(event.data.object.current_period_end * 1000),
    },
  });
  break;

Subscription Updated

case 'customer.subscription.updated':
  await prisma.subscription.update({
    where: { id: event.data.object.id },
    data: {
      status: event.data.object.status,
      planId: event.data.object.items.data[0].price.id,
      currentPeriodEnd: new Date(event.data.object.current_period_end * 1000),
    },
  });
  break;

Subscription Deleted

case 'customer.subscription.deleted':
  await prisma.subscription.update({
    where: { id: event.data.object.id },
    data: {
      status: 'canceled',
      canceledAt: new Date(),
    },
  });
  break;

Payment Failed

case 'invoice.payment_failed':
  const subscription = await prisma.subscription.findUnique({
    where: { id: event.data.object.subscription },
  });

  // Send payment failure notification
  await sendPaymentFailureEmail(subscription.accountId);
  break;

Setting Up Webhooks

Stripe

  1. Local Development (using Stripe CLI):
stripe listen --forward-to localhost:3000/api/billing/webhook
  1. Production:
  • Go to Stripe Dashboard → Developers → Webhooks
  • Add endpoint: https://yourdomain.com/api/billing/webhook
  • Select events to listen to
  • Copy webhook signing secret to your .env

Paddle

  1. Configure webhook URL in Paddle dashboard
  2. Add webhook secret to environment variables
  3. Verify webhook signature:
const signature = request.headers.get('paddle-signature');
const verified = paddle.webhooks.verify(body, signature);

if (!verified) {
  return new Response('Invalid signature', { status: 401 });
}

Security Best Practices

  1. Always verify signatures - Prevents unauthorized requests
  2. Use HTTPS - Encrypts webhook data in transit
  3. Validate event data - Check for required fields
  4. Handle idempotently - Process duplicate events safely
  5. Return 200 quickly - Acknowledge receipt, process async

Error Handling

async function handleBillingEvent(event: Event) {
  try {
    await processEvent(event);
  } catch (error) {
    // Log error for debugging
    console.error('Webhook error:', error);

    // Store failed event for retry
    await prisma.failedWebhook.create({
      data: {
        eventId: event.id,
        type: event.type,
        payload: event,
        error: error.message,
      },
    });

    // Throw to trigger provider retry
    throw error;
  }
}

Testing Webhooks

Using Provider's CLI Tools

# Stripe
stripe trigger customer.subscription.created

# Test specific scenarios
stripe trigger payment_intent.payment_failed

Manual Testing

curl -X POST https://your-app.com/api/billing/webhook \
  -H "Content-Type: application/json" \
  -H "stripe-signature: test_signature" \
  -d @test-event.json

Monitoring

Track webhook delivery:

  • Response times
  • Success/failure rates
  • Event processing duration
  • Failed events requiring manual intervention

Most providers offer webhook monitoring dashboards showing delivery attempts and failures.

  1. Why Webhooks?
    1. Webhook Endpoint
    2. Common Events
    3. Setting Up Webhooks
    4. Security Best Practices
    5. Error Handling
    6. Testing Webhooks
    7. Monitoring