Skip to main content

Webhook Integration

Learn how to integrate webhooks to receive real-time notifications about account onboarding status changes.

Why Use Webhooks?

Webhooks provide real-time notifications when account statuses change, eliminating the need to poll the API repeatedly.

Benefits

Real-time Updates

Receive notifications instantly when status changes

Reduced API Calls

No need to poll for status updates

Automated Workflows

Trigger actions automatically based on events

Better UX

Provide immediate feedback to users

Setting Up Webhooks

Step 1: Create a Webhook Endpoint

Create an HTTPS endpoint in your application to receive webhook notifications:
const express = require('express');
const app = express();

app.post('/webhooks/onboarding', express.json(), async (req, res) => {
  const event = req.body;
  
  // Acknowledge receipt immediately
  res.status(200).send('OK');
  
  // Process webhook asynchronously
  processWebhook(event);
});

async function processWebhook(event) {
  console.log('Received event:', event.event);
  console.log('Account ID:', event.data.account_id);
  console.log('New status:', event.data.status);
  
  // Update your database
  await updateAccountStatus(
    event.data.account_id,
    event.data.status
  );
  
  // Trigger notifications
  if (event.data.status === 'approved') {
    await notifyUser(event.data.account_id, 'Account approved!');
  }
}

app.listen(3000);

Step 2: Register Your Webhook

Register your webhook URL with WEpayments:
const response = await fetch('https://api.wepayments.com/v1/account/webhook', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    url: 'https://your-domain.com/webhooks/onboarding',
    events: ['onboarding'],
    description: 'Production onboarding webhook'
  })
});

const webhook = await response.json();
console.log('Webhook ID:', webhook.data.webhook_id);
Save the webhook_id for future reference. You’ll need it to update or delete the webhook.

Step 3: Handle Webhook Events

Process different account statuses:
function handleOnboardingEvent(event) {
  const { account_id, status, previous_status, reason } = event.data;
  
  switch (status) {
    case 'pending':
      console.log(`Account ${account_id} is pending review`);
      break;
      
    case 'under_review':
      console.log(`Account ${account_id} is under review`);
      // Notify user that review is in progress
      break;
      
    case 'approved':
      console.log(`Account ${account_id} has been approved!`);
      // Enable account features
      // Send welcome email
      break;
      
    case 'rejected':
      console.log(`Account ${account_id} was rejected: ${reason}`);
      // Notify user with rejection reason
      // Provide instructions for resubmission
      break;
  }
}

Webhook Payload

Structure

{
  "event": "onboarding",
  "event_id": "evt_1234567890",
  "timestamp": "2024-01-15T10:30:00Z",
  "data": {
    "account_id": "acc_1234567890",
    "status": "approved",
    "previous_status": "under_review",
    "business_name": "Example Company Ltd",
    "document": "12345678000190",
    "updated_at": "2024-01-15T10:30:00Z",
    "reason": null
  }
}

Field Descriptions

FieldTypeDescription
eventstringAlways "onboarding" for account events
event_idstringUnique identifier for this event
timestampstringWhen the event occurred (ISO 8601)
data.account_idstringThe account identifier
data.statusstringNew account status
data.previous_statusstringPrevious account status
data.reasonstringRejection reason (if applicable)

Best Practices

Your endpoint should return a 200 OK response within 5 seconds. Process the webhook data asynchronously.
app.post('/webhook', (req, res) => {
  // Return immediately
  res.status(200).send('OK');
  
  // Process asynchronously
  processInBackground(req.body);
});
Use the event_id to prevent processing the same event multiple times:
const processedEvents = new Set();

function processWebhook(event) {
  if (processedEvents.has(event.event_id)) {
    console.log('Event already processed');
    return;
  }
  
  processedEvents.add(event.event_id);
  // Process event...
}
If your processing fails, store the event and retry later:
async function processWebhook(event) {
  try {
    await updateDatabase(event);
  } catch (error) {
    await storeForRetry(event);
    console.error('Processing failed, will retry', error);
  }
}
  • Use HTTPS only
  • Validate webhook signatures (if provided)
  • Implement rate limiting
  • Log all webhook deliveries

Testing Webhooks Locally

Use ngrok or localtunnel to test webhooks on your local machine:
# Install ngrok
npm install -g ngrok

# Start your local server
node server.js

# Expose it via ngrok
ngrok http 3000
Then register the ngrok URL as your webhook:
{
  "url": "https://abc123.ngrok.io/webhooks/onboarding",
  "events": ["onboarding"]
}

Managing Webhooks

List All Webhooks

const response = await fetch('https://api.wepayments.com/v1/account/webhook', {
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY'
  }
});

const webhooks = await response.json();

Update Webhook URL

await fetch(`https://api.wepayments.com/v1/account/webhook/${webhookId}`, {
  method: 'PUT',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    url: 'https://new-domain.com/webhooks/onboarding'
  })
});

Delete Webhook

await fetch(`https://api.wepayments.com/v1/account/webhook/${webhookId}`, {
  method: 'DELETE',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY'
  }
});

Troubleshooting

Checklist:
  • Endpoint is using HTTPS
  • Endpoint is publicly accessible
  • Endpoint returns 200 OK
  • No firewall blocking requests
  • Webhook is registered correctly
Cause: Your endpoint didn’t return 200 OK quickly enoughSolution: Return 200 immediately and process asynchronously
Cause: Endpoint was down or returned an errorSolution: Implement monitoring and alerting for your webhook endpoint

Next Steps