Skip to main content
POST
https://your.endpoint.to.notify
Callback Payment
curl --request POST \
  --url https://your.endpoint.to.notify/ \
  --header 'Authorization: Bearer <token>'
{
  "id": 123,
  "invoice": "<string>",
  "status": {
    "id": 123,
    "name": "<string>"
  },
  "updated_at": "<string>",
  "status_detail": {
    "code": "<string>",
    "detail": "<string>"
  }
}

Callbacks

Receive updates about your payout.

Cash-out

Endpoint: POST https://your.endpoint.to.notifyThis is your endpoint where WEpayments will send notifications about payout status changes.

Response

You should respond with 200 OK to acknowledge receipt of the webhook.

Body

The webhook payload contains the following fields:
id
integer
Cash-out IDExample: 2322977
invoice
string
Cash-out invoiceExample: 575e8327-f145-48ff-b207-737eef2d6f3f
status
object
Object that contains the current status of your payout.
updated_at
string
Last update of your payout.Format: <date-time>Example: 2024-09-25 15:55:18
status_detail
object
This object will only be returned if the payout is canceled and the merchant is using the “Account Mismatch” functionality. It provides more details on the reason for the cancellation.

Webhook Payload Example

{
  "id": 2322977,
  "invoice": "575e8327-f145-48ff-b207-737eef2d6f3f",
  "status": {
    "id": 6,
    "name": "Cancelled"
  },
  "updated_at": "2024-09-25 15:55:18",
  "status_detail": {
    "code": "WE0001",
    "detail": "The payment was made to an unregistered account"
  }
}

Status Codes

Common payout status codes:
Status IDStatus NameDescription
1CreatedCash-out has been created
2ProcessingCash-out is being processed
3PaidCash-out has been paid successfully
4FailedCash-out failed
5RejectedCash-out rejected by compliance
6CancelledCash-out was cancelled

Implementing the Webhook Endpoint

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

app.use(express.json());

app.post('/webhook/payout', (req, res) => {
  const { id, invoice, status, updated_at, status_detail } = req.body;
  
  console.log(`Received payout webhook for ID: ${id}`);
  console.log(`Invoice: ${invoice}`);
  console.log(`Status: ${status.name} (${status.id})`);
  console.log(`Updated at: ${updated_at}`);
  
  // Handle different statuses
  switch (status.id) {
    case 3: // Paid
      console.log('✓ Cash-out paid successfully');
      handleSuccessfulPayout(id, invoice);
      break;
      
    case 6: // Cancelled
      console.log('✗ Cash-out cancelled');
      if (status_detail) {
        console.log(`Reason: ${status_detail.code} - ${status_detail.detail}`);
      }
      handleCancelledPayout(id, invoice, status_detail);
      break;
      
    case 4: // Failed
      console.log('✗ Cash-out failed');
      handleFailedPayout(id, invoice);
      break;
      
    case 5: // Rejected
      console.log('✗ Cash-out rejected');
      handleRejectedPayout(id, invoice);
      break;
      
    default:
      console.log(`Status: ${status.name}`);
  }
  
  // Always respond 200 OK
  res.status(200).json({ received: true });
});

function handleSuccessfulPayout(id, invoice) {
  // Update your database
  // Send confirmation email
  // Update order status
}

function handleCancelledPayout(id, invoice, statusDetail) {
  // Log cancellation reason
  // Notify admin
  // Update records
}

function handleFailedPayout(id, invoice) {
  // Retry logic
  // Alert admin
}

function handleRejectedPayout(id, invoice) {
  // Review compliance issue
  // Contact support if needed
}

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

Best Practices

Always Respond 200 OK: Your endpoint must respond with HTTP 200 to acknowledge receipt. Otherwise, WEpayments will retry sending the webhook.
Validate Webhook Signature: In production, always validate the webhook signature to ensure it’s from WEpayments. See Webhook Signature Documentation for details.
Process Asynchronously: Handle webhook processing asynchronously to respond quickly and avoid timeouts.

Webhook Retry Logic

If your endpoint doesn’t respond with 200 OK, WEpayments will retry sending the webhook:
  • 1st retry: After 1 minute
  • 2nd retry: After 5 minutes
  • 3rd retry: After 15 minutes
  • 4th retry: After 1 hour
  • 5th retry: After 6 hours
After 5 failed attempts, the webhook will be marked as failed and no more retries will be attempted.

Testing Webhooks

1

Set Up Local Endpoint

Create a webhook endpoint in your local development environment.
2

Use Ngrok or Similar

Use a tool like ngrok to expose your local endpoint to the internet:
ngrok http 3000
3

Configure Webhook URL

Use the ngrok URL when creating a payout with notification_url.
4

Test Different Scenarios

Create test payouts and observe the webhooks received.