Skip to main content

Overview

Setting up webhooks allows your application to receive real-time notifications about payment events. This guide will walk you through the complete setup process.

Prerequisites

Before setting up webhooks, ensure you have:
1

HTTPS Endpoint

A publicly accessible HTTPS endpoint (webhooks cannot be sent to HTTP endpoints)
2

Server Capability

Ability to receive and process POST requests
3

API Key

Your InventPay API key from the dashboard
Webhook endpoints must use HTTPS. HTTP endpoints will be rejected for security reasons.

Configuration Methods

You can configure webhooks in two ways:

Dashboard

Visual interface for easy setup Best for: Non-technical users, testing

API

Programmatic configuration Best for: Automated deployments, CI/CD

Setup via Dashboard

Step 1: Access Webhook Settings

  1. Log in to InventPay Dashboard
  2. Navigate to SettingsWebhooks
  3. Click Configure Webhook

Step 2: Enter Webhook URL

Enter your webhook endpoint URL:
https://yourapp.com/api/webhooks/inventpay
Use a dedicated webhook endpoint path for easier monitoring and debugging.

Step 3: Save Configuration

  1. Click Save Webhook URL
  2. Copy your Webhook Secret (shown once)
  3. Store the secret securely in your environment variables
The webhook secret is shown only once. Store it immediately in a secure location.

Step 4: Test Your Webhook

Click Send Test Webhook to verify your endpoint is working correctly.

Setup via API

Configure Webhook Endpoint

const sdk = new PaymentSDK({
  apiKey: process.env.INVENTPAY_API_KEY,
});

// Configure webhook URL
await sdk.configureWebhook({
  webhookUrl: "https://yourapp.com/api/webhooks/inventpay",
});

console.log("Webhook configured successfully");

Get Current Configuration

const config = await sdk.getWebhookConfig();
console.log("Webhook URL:", config.data.webhookUrl);
console.log("Active:", config.data.active);

Test Webhook Delivery

const result = await sdk.testWebhook();
console.log(result.message); // "Webhook test successful"

Implementing Your Webhook Endpoint

Basic Webhook Handler

Here’s a complete webhook endpoint implementation:
const express = require("express");
const crypto = require("crypto");

const app = express();
app.use(express.json());

const WEBHOOK_SECRET = process.env.INVENTPAY_WEBHOOK_SECRET;

// Verify webhook signature
function verifyWebhookSignature(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac("sha256", secret)
    .update(JSON.stringify(payload))
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

app.post("/api/webhooks/inventpay", async (req, res) => {
  try {
    const signature = req.headers["x-webhook-signature"];
    const event = req.body;

    // Verify signature
    if (!verifyWebhookSignature(event, signature, WEBHOOK_SECRET)) {
      return res.status(401).json({ error: "Invalid signature" });
    }

    // Process event
    await handleWebhookEvent(event);

    // Return 200 OK
    res.status(200).json({ received: true });
  } catch (error) {
    console.error("Webhook error:", error);
    res.status(500).json({ error: "Internal server error" });
  }
});

async function handleWebhookEvent(event) {
  switch (event.event) {
    case "payment.confirmed":
      await handlePaymentConfirmed(event.data);
      break;
    case "payment.expired":
      await handlePaymentExpired(event.data);
      break;
    // ... handle other events
  }
}

app.listen(3000, () => {
  console.log("Webhook server running on port 3000");
});

Key Implementation Points

Always verify the webhook signature before processing to ensure the request is from InventPay.
if (!verifySignature(payload, signature, secret)) {
  return res.status(401).send('Invalid signature');
}
Respond with 200 status within 5 seconds to acknowledge receipt. javascript // Return 200 immediately res.status(200).send('OK'); // Process asynchronously processWebhook(event).catch(console.error);
Use webhook ID or payment ID to prevent duplicate processing.
const webhookId = req.headers['x-webhook-id'];
if (await isProcessed(webhookId)) {
  return res.status(200).send('Already processed');
}
Log all webhook deliveries for debugging and auditing.
logger.info('Webhook received', {
  event: event.event,
  paymentId: event.data.paymentId,
  webhookId: webhookId
});

Testing Your Webhook

Local Testing with ngrok

For local development, use ngrok to expose your local server:
1

Install ngrok

Download from ngrok.com
2

Start Your Server

Run your webhook server locally (node server.js or python app.py)
3

Expose with ngrok

Run: ngrok http 3000
4

Use ngrok URL

Copy the HTTPS URL (e.g., https://abc123.ngrok.io) and set it as your webhook URL
5

Test

Send a test webhook from dashboard or API
Starting your server:
node server.js
# or
python app.py
Exposing with ngrok:
ngrok http 3000
Never use ngrok URLs in production. They’re temporary and will expire.

Testing Checklist

Before going live, verify:
Test with both valid and invalid signatures
Ensure you handle all relevant event types
Send duplicate webhooks to verify idempotency
Test error scenarios and recovery
Ensure endpoint responds quickly
Verify SSL certificate is valid and trusted

Webhook Security Best Practices

Use HTTPS Only

Never accept webhooks over HTTP

Verify Signatures

Always verify HMAC signature

Validate IP Addresses

Optional: Whitelist InventPay IPs

Rate Limiting

Implement rate limiting on webhook endpoint

Monitor Failures

Set up alerts for failed webhooks

Rotate Secrets

Periodically rotate webhook secrets

Security Guide

Learn more about webhook security

Monitoring Webhooks

Dashboard Monitoring

View webhook activity in your dashboard:
  1. Go to WebhooksDeliveries
  2. See recent deliveries and their status
  3. View response codes and retry attempts
  4. Inspect failed deliveries

API Monitoring

// Get recent deliveries
const deliveries = await sdk.getWebhookDeliveries({
  page: 1,
  limit: 10,
  success: true, // or false for failures only
});

// Get webhook statistics
const stats = await sdk.getWebhookStats(7); // Last 7 days
console.log("Success Rate:", stats.data.summary.successRate);
console.log("Total Sent:", stats.data.summary.totalSent);
console.log("Total Failed:", stats.data.summary.totalFailed);

Troubleshooting

Possible Causes:
  • Webhook URL not configured
  • Firewall blocking requests
  • Server not responding
Solutions:
  1. Verify webhook URL in dashboard
  2. Check firewall and security group rules
  3. Test endpoint with test webhook
  4. Check server logs for errors
Possible Causes: - Using wrong webhook secret - Body modified by middleware - Incorrect signature calculation Solutions: 1. Verify webhook secret from dashboard 2. Use raw request body for verification 3. Check HMAC algorithm (SHA-256) 4. Log both signatures for comparison
Possible Causes: - Synchronous processing taking too long - Database queries blocking response Solutions: 1. Return 200 immediately 2. Process webhooks asynchronously 3. Use background jobs for heavy processing 4. Optimize database queries
This is Normal: Retries may cause duplicatesSolution: Implement idempotency using webhook ID or payment ID
const webhookId = req.headers['x-webhook-id'];
if (await db.isProcessed(webhookId)) {
  return res.status(200).send('Already processed');
}
await db.markProcessed(webhookId);

Advanced Configuration

Custom Headers

Add custom headers to webhook requests (Enterprise feature):
await sdk.configureWebhook({
  webhookUrl: "https://yourapp.com/api/webhooks/inventpay",
  customHeaders: {
    "X-Custom-Header": "custom-value",
    "X-Environment": "production",
  },
});

Event Filtering

Subscribe to specific events only (Enterprise feature):
await sdk.configureWebhook({
  webhookUrl: "https://yourapp.com/api/webhooks/inventpay",
  events: ["payment.confirmed", "payment.expired", "withdrawal.completed"],
});

Multiple Webhook URLs

Configure different URLs for different event types (Enterprise feature):
await sdk.configureMultipleWebhooks([
  {
    url: "https://yourapp.com/webhooks/payments",
    events: ["payment.confirmed", "payment.expired"],
  },
  {
    url: "https://yourapp.com/webhooks/withdrawals",
    events: ["withdrawal.completed", "withdrawal.failed"],
  },
]);

Enterprise Features

Contact sales for advanced webhook features

Webhook IP Addresses

For additional security, you can whitelist InventPay webhook IPs:
52.89.214.238
34.212.75.30
54.218.53.128
IP addresses are subject to change. We recommend signature verification over IP whitelisting.

Next Steps