Developer Tools

Webhooks

Webhooks tell your server when something happens in ClapPay. When a payment succeeds, a subscription renews, or a dispute is opened, you'll know instantly.

8 min read

What Are Webhooks?

Imagine you're running an online store. A customer buys something, but instead of staying on your page, they close their browser right after paying. How do you know they paid?

That's where webhooks come in. A webhook is a message that ClapPay sends to your server when something happens. It's like getting a text notification, but for your code.

Without webhooks, you'd have to keep asking ClapPay "Did anything happen? Did anything happen?" over and over. With webhooks, ClapPay tells you right when it happens.

Why You Need Webhooks

Webhooks are important for:

Fulfill Orders

Ship products or grant access when a payment succeeds

Handle Failures

Know when subscription payments fail so you can notify customers

Stay in Sync

Keep your database updated with payment status

Respond to Disputes

Get alerts when customers dispute charges

Common Webhook Events

Here are the most important events you should listen for:

EventWhen It Happens
payment_intent.succeededA payment was successful
payment_intent.failedA payment failed
customer.subscription.createdA new subscription started
customer.subscription.deletedA subscription was canceled
invoice.paidA subscription invoice was paid
invoice.payment_failedA subscription payment failed
charge.refundedA refund was issued
charge.dispute.createdA customer disputed a charge

How to Set Up Webhooks

Step 1: Create an Endpoint

First, create a URL on your server that can receive POST requests. This is where ClapPay will send events.

Example endpoint (Node.js/Express)

const express = require('express');
const app = express();

// Important: Use raw body for signature verification
app.post('/webhooks/clappay', 
  express.raw({type: 'application/json'}),
  (req, res) => {
    const event = JSON.parse(req.body);
    
    // Handle the event
    switch (event.type) {
      case 'payment_intent.succeeded':
        const payment = event.data.object;
        console.log('Payment succeeded:', payment.id);
        // Fulfill the order here
        break;
        
      case 'payment_intent.failed':
        console.log('Payment failed');
        // Notify the customer
        break;
    }
    
    // Return 200 to acknowledge receipt
    res.status(200).send('OK');
  }
);

Step 2: Register in Dashboard

  1. Go to Settings → Webhooks in your Dashboard
  2. Click Add Endpoint
  3. Enter your endpoint URL (example: https://yoursite.com/webhooks/clappay)
  4. Select which events you want to receive
  5. Click Add Endpoint

Step 3: Get Your Signing Secret

After creating the endpoint, you'll get a signing secret (starts with whsec_). Save this - you'll need it to verify webhooks are really from ClapPay.

Verify Webhook Signatures

Anyone could send a fake webhook to your endpoint. To make sure a webhook really came from ClapPay, check the signature.

Warning: Never skip signature verification! Without it, attackers could trick your server into fulfilling fake orders.

Every webhook includes a signature in the ClapPay-Signature header. Use our SDK to verify it:

Verify the signature

const clappay = require('@clappay/sdk')('sk_test_...');
const endpointSecret = 'whsec_...';

app.post('/webhooks/clappay',
  express.raw({type: 'application/json'}),
  (req, res) => {
    const sig = req.headers['clappay-signature'];
    
    let event;
    try {
      // This throws an error if signature is invalid
      event = clappay.webhooks.constructEvent(
        req.body, 
        sig, 
        endpointSecret
      );
    } catch (err) {
      console.log('Invalid signature:', err.message);
      return res.status(400).send('Invalid signature');
    }
    
    // Signature verified! Safe to process
    // Handle the event...
    
    res.status(200).send('OK');
  }
);

Handling Retries

If your endpoint doesn't return a 2xx response (like 200), ClapPay will try again. We retry with increasing delays for up to 3 days:

  • First retry: 1 minute later
  • Second retry: 5 minutes later
  • Third retry: 30 minutes later
  • Then: Every few hours for up to 3 days

Handle Events Only Once

Because of retries, you might receive the same event multiple times. To handle this, check if you've already processed the event:

// Store processed event IDs in your database
async function handleEvent(event) {
  // Check if already processed
  const exists = await db.processedEvents.findOne({ 
    eventId: event.id 
  });
  
  if (exists) {
    console.log('Event already processed, skipping');
    return;
  }
  
  // Process the event
  // ...
  
  // Mark as processed
  await db.processedEvents.create({ 
    eventId: event.id,
    processedAt: new Date()
  });
}

Testing Webhooks Locally

ClapPay can't send webhooks to localhost. But you can test locally using our CLI tool:

  1. Install the ClapPay CLI
  2. Run clappay listen --forward-to localhost:3000/webhooks/clappay
  3. The CLI will give you a signing secret to use locally
  4. Make test payments - events will be forwarded to your local server

You can also use the Dashboard to send test events:

  1. Go to Developers → Webhooks
  2. Click on your endpoint
  3. Click Send Test Webhook
  4. Choose an event type and click Send

Best Practices

  • Return 200 quickly - Process the event in the background if it takes time. Return 200 first, then do the work.
  • Use idempotency - Make sure processing an event twice doesn't cause problems (like charging twice or sending two emails).
  • Log everything - Keep logs of incoming webhooks. They help when debugging issues.
  • Monitor failures - Set up alerts if your webhook endpoint starts failing.
  • Use HTTPS - Your endpoint URL must use HTTPS in production.

Troubleshooting

Webhooks not arriving?

  • • Check your endpoint URL is correct in the Dashboard
  • • Make sure your server is running and accessible from the internet
  • • Check your firewall isn't blocking ClapPay's IP addresses
  • • Look at webhook logs in the Dashboard for error messages

Signature verification failing?

  • • Make sure you're using the correct signing secret for your endpoint
  • • Use the raw request body, not parsed JSON
  • • Don't modify the request body before verifying
  • • Check that your clock is accurate (signatures expire after 5 minutes)

Related Articles