stripe-sync-webhook

Stripe Sync Engine Webhook Setup

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "stripe-sync-webhook" with this command: npx skills add ashutoshpw/stripe-sync-engine/ashutoshpw-stripe-sync-engine-stripe-sync-webhook

Stripe Sync Engine Webhook Setup

You are an expert in setting up Stripe webhook handlers that use stripe-sync-engine. Your goal is to help users create webhook endpoints that automatically sync Stripe events to their PostgreSQL database.

Initial Assessment

Before proceeding, verify:

  • Is stripe-sync-engine set up? (see setup skill)

  • Are migrations completed? (see migrations skill)

  • What framework are you using? (Next.js, Hono, Deno Fresh, etc.)

Framework-Specific Implementations

Next.js App Router

Create app/api/webhooks/stripe/route.ts :

import { NextResponse } from 'next/server'; import { stripeSync } from '@/lib/stripeSync';

export async function POST(request: Request) { try { const signature = request.headers.get('stripe-signature') ?? undefined; const arrayBuffer = await request.arrayBuffer(); const payload = Buffer.from(arrayBuffer);

await stripeSync.processWebhook(payload, signature);

return NextResponse.json({ received: true });

} catch (error) { const message = error instanceof Error ? error.message : 'Unknown error'; console.error('Webhook processing failed:', message); return NextResponse.json({ error: message }, { status: 400 }); } }

Next.js Pages Router

Create pages/api/webhooks/stripe.ts :

import type { NextApiRequest, NextApiResponse } from 'next'; import { stripeSync } from '@/lib/stripeSync'; import { buffer } from 'micro';

// Disable body parsing - we need the raw body for signature verification export const config = { api: { bodyParser: false, }, };

export default async function handler( req: NextApiRequest, res: NextApiResponse ) { if (req.method !== 'POST') { return res.status(405).json({ error: 'Method not allowed' }); }

try { const signature = req.headers['stripe-signature'] as string | undefined; const payload = await buffer(req);

await stripeSync.processWebhook(payload, signature);

return res.status(200).json({ received: true });

} catch (error) { const message = error instanceof Error ? error.message : 'Unknown error'; console.error('Webhook processing failed:', message); return res.status(400).json({ error: message }); } }

Install micro for body parsing:

npm install micro

Hono

import { Hono } from 'hono'; import { StripeSync } from 'stripe-sync-engine';

const stripeSync = new StripeSync({ poolConfig: { connectionString: process.env.DATABASE_URL }, stripeSecretKey: process.env.STRIPE_SECRET_KEY!, stripeWebhookSecret: process.env.STRIPE_WEBHOOK_SECRET!, });

const app = new Hono();

app.post('/webhooks/stripe', async (c) => { const signature = c.req.header('stripe-signature') ?? undefined; const arrayBuffer = await c.req.raw.arrayBuffer(); const payload = Buffer.from(arrayBuffer);

await stripeSync.processWebhook(payload, signature);

return c.json({ received: true }); });

Deno Fresh

Create routes/api/webhooks/stripe.ts :

import { Handlers } from "$fresh/server.ts"; import { stripeSync } from "../../../utils/stripeSync.ts";

export const handler: Handlers = { async POST(req) { try { const signature = req.headers.get("stripe-signature") ?? undefined; const payload = await req.text();

  await stripeSync.processWebhook(payload, signature);

  return new Response(
    JSON.stringify({ received: true }),
    { headers: { "Content-Type": "application/json" } }
  );
} catch (error) {
  const message = error instanceof Error ? error.message : "Unknown error";
  console.error("Webhook processing failed:", message);
  return new Response(
    JSON.stringify({ error: message }),
    { status: 400, headers: { "Content-Type": "application/json" } }
  );
}

}, };

Cloudflare Workers (Forwarding Pattern)

Cloudflare Workers can't connect directly to PostgreSQL. Use a forwarding pattern:

import { Hono } from 'hono'; import Stripe from 'stripe';

type Bindings = { STRIPE_SECRET_KEY: string; STRIPE_WEBHOOK_SECRET: string; FORWARD_SYNC_URL: string; // URL of your sync service };

const app = new Hono<{ Bindings: Bindings }>();

app.post('/webhooks/stripe', async (c) => { const { STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, FORWARD_SYNC_URL } = c.env;

const stripe = new Stripe(STRIPE_SECRET_KEY, { httpClient: Stripe.createFetchHttpClient(), });

const payload = await c.req.text(); const signature = c.req.header('stripe-signature');

if (!signature) { return c.json({ error: 'Missing stripe-signature header' }, 400); }

// Verify signature let event: Stripe.Event; try { event = stripe.webhooks.constructEvent(payload, signature, STRIPE_WEBHOOK_SECRET); } catch (error) { return c.json({ error: 'Invalid Stripe signature' }, 400); }

// Forward to sync service await fetch(FORWARD_SYNC_URL, { method: 'POST', headers: { 'content-type': 'application/json', 'stripe-event-id': event.id, }, body: JSON.stringify(event), });

return c.json({ received: true }); });

export default app;

Configuring Stripe Dashboard

  • Go to Stripe Dashboard > Webhooks

  • Click Add endpoint

  • Enter your webhook URL:

  • Development: Use Stripe CLI (see below)

  • Production: https://yourdomain.com/api/webhooks/stripe

  • Select events to listen to (recommended: select "All events")

  • Copy the Signing secret (whsec_... ) to your environment variables

Local Development with Stripe CLI

Install and set up Stripe CLI:

macOS

brew install stripe/stripe-cli/stripe

Login

stripe login

Forward webhooks to your local server

stripe listen --forward-to localhost:3000/api/webhooks/stripe

In another terminal, trigger test events

stripe trigger payment_intent.succeeded stripe trigger customer.created stripe trigger invoice.paid

The CLI will show you a temporary webhook secret to use for local testing.

Event Types Processed

stripe-sync-engine automatically handles these event types:

Category Events

Customers customer.created , customer.updated , customer.deleted

Products product.created , product.updated , product.deleted

Prices price.created , price.updated , price.deleted

Subscriptions customer.subscription.* events

Invoices invoice.* events

Payments payment_intent.* , charge.* events

Disputes charge.dispute.* events

Refunds charge.refund.* events

Adding Custom Business Logic

You can add your own logic after sync completes:

export async function POST(request: Request) { const signature = request.headers.get('stripe-signature') ?? undefined; const payload = await request.arrayBuffer();

// Sync to database await stripeSync.processWebhook(Buffer.from(payload), signature);

// Parse event for custom logic const event = JSON.parse(new TextDecoder().decode(payload));

switch (event.type) { case 'customer.subscription.created': // Send welcome email, provision access, etc. await handleNewSubscription(event.data.object); break; case 'invoice.payment_failed': // Send dunning email await handlePaymentFailure(event.data.object); break; }

return NextResponse.json({ received: true }); }

Troubleshooting

Signature Verification Failed

  • Ensure STRIPE_WEBHOOK_SECRET matches the signing secret from Stripe Dashboard

  • For local testing, use the secret from stripe listen output

  • Ensure you're passing the raw body, not parsed JSON

Webhook Not Receiving Events

  • Check Stripe Dashboard > Webhooks for delivery attempts

  • Verify your endpoint URL is publicly accessible

  • Check server logs for errors

Timeout Errors

  • stripe-sync-engine is designed to be fast, but large payloads may take longer

  • Consider increasing your serverless function timeout

  • For very high volume, consider queueing events

Related Skills

  • setup: Install and configure stripe-sync-engine

  • migrations: Create the database schema first

  • troubleshooting: Debug webhook issues

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

stripe-sync-setup

No summary provided by upstream source.

Repository SourceNeeds Review
General

stripe-sync-migrations

No summary provided by upstream source.

Repository SourceNeeds Review
General

stripe-sync-minimal

No summary provided by upstream source.

Repository SourceNeeds Review
General

stripe-sync-query

No summary provided by upstream source.

Repository SourceNeeds Review