> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dcash.africa/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

> Receive real-time notifications about transaction events

## Overview

Webhooks allow you to receive real-time notifications when transaction events occur. Instead of polling for transaction status updates, DCash will send HTTP POST requests to your configured webhook URL when transactions complete.

## Configuring Webhooks

You can configure webhook URLs in two ways:

1. **Per-request**: Include the `webhook_url` parameter in your API request
2. **Default URL**: Set a default webhook URL in your [merchant portal](https://merchants.dcash.africa)

<Note>
  Per-request webhook URLs take precedence over the default URL configured in your merchant portal.
</Note>

## Webhook Security

To ensure webhook requests originated from DCash:

* **Verify the source IP address**: All webhooks are sent from `41.209.57.197`
* **Use HTTPS endpoints**: Ensure encrypted transmission of transaction data
* **Validate transaction data**: Cross-check the transaction details against your records

## Webhook Payload Structure

### Deposit (C2B) Webhooks

When a C2B deposit transaction completes, your webhook receives:

```json theme={null}
{
  "transaction_id": "skjr3",
  "reference_id": "abcd",
  "transaction_status": "completed",
  "user_email": "test.user@dcash.africa",
  "amount": 10,
  "currency": "USD",
  "description": "Test Deposit",
  "date_completed": 20241214125109
}
```

<ParamField body="transaction_id" type="string">
  Unique identifier for the transaction
</ParamField>

<ParamField body="reference_id" type="string">
  Merchant-provided reference ID from the original request
</ParamField>

<ParamField body="transaction_status" type="string">
  Status of the transaction (e.g., "completed", "failed")
</ParamField>

<ParamField body="user_email" type="string">
  Email of the user who made the deposit
</ParamField>

<ParamField body="amount" type="number">
  Amount deposited
</ParamField>

<ParamField body="currency" type="string">
  Currency code (e.g., "USD")
</ParamField>

<ParamField body="description" type="string">
  Description of the transaction
</ParamField>

<ParamField body="date_completed" type="number">
  Timestamp of completion (format: YYYYMMDDHHMMSS)
</ParamField>

### Withdrawal (B2C) Webhooks

When a B2C withdrawal transaction completes, your webhook receives:

```json theme={null}
{
  "transaction_id": "skjr7",
  "reference_id": "abcd",
  "transaction_status": "completed",
  "user_email": "test.user@dcash.africa",
  "amount": 10,
  "currency": "USD",
  "description": "Test withdrawal",
  "date_completed": 20250401125109
}
```

The payload structure is identical to deposits, containing the same fields.

## Responding to Webhooks

Your webhook endpoint should:

1. **Respond quickly**: Return a `200 OK` response within 5 seconds
2. **Process asynchronously**: Handle the webhook data in a background job if needed
3. **Be idempotent**: Handle duplicate webhook deliveries gracefully using `transaction_id`

```javascript Example Webhook Handler theme={null}
app.post('/webhook/dcash', async (req, res) => {
  // Verify the request comes from DCash
  const clientIp = req.ip || req.connection.remoteAddress;
  if (clientIp !== '41.209.57.197') {
    return res.status(403).send('Forbidden');
  }

  // Respond immediately
  res.status(200).send('OK');

  // Process asynchronously
  const { transaction_id, transaction_status, amount } = req.body;

  // Check if already processed (idempotency)
  if (await isProcessed(transaction_id)) {
    return;
  }

  // Handle the webhook
  if (transaction_status === 'completed') {
    await processSuccessfulTransaction(req.body);
  } else if (transaction_status === 'failed') {
    await processFailedTransaction(req.body);
  }

  // Mark as processed
  await markAsProcessed(transaction_id);
});
```

## Webhook Retry Logic

If your endpoint doesn't respond with a `200 OK` status:

* DCash will retry the webhook up to 3 times
* Retries occur at increasing intervals (5 min, 30 min, 2 hours)
* After 3 failed attempts, you'll need to use the [Check Transaction Status](/api-reference/transactions/check-status) endpoint

<Warning>
  If webhooks consistently fail, ensure your endpoint is accessible, responds quickly, and returns a 200 status code.
</Warning>

## Testing Webhooks

During development, you can test webhooks using:

1. **Webhook testing tools**: Use services like [webhook.site](https://webhook.site) or [ngrok](https://ngrok.com) to create temporary public URLs
2. **Sandbox environment**: All sandbox transactions trigger webhooks to help you test your integration

## Transaction Statuses

Webhook notifications may include these transaction statuses:

| Status      | Description                        |
| ----------- | ---------------------------------- |
| `completed` | Transaction completed successfully |
| `failed`    | Transaction failed                 |
| `pending`   | Transaction is still processing    |

<Check>
  When you receive a "completed" status, the funds have been successfully transferred.
</Check>

## Troubleshooting

### Webhook not received

If you don't receive a webhook notification:

1. Check that your webhook URL is correctly configured
2. Verify your endpoint is publicly accessible
3. Use the [Check Transaction Status](/api-reference/transactions/check-status) endpoint to get the transaction result
4. Check your server logs for incoming requests

### Multiple webhook deliveries

Webhooks may be delivered more than once. Implement idempotency using the `transaction_id` to prevent duplicate processing.

## Best Practices

<AccordionGroup>
  <Accordion title="Use HTTPS endpoints">
    Always use HTTPS webhook URLs to ensure secure transmission of transaction data.
  </Accordion>

  <Accordion title="Verify source IP address">
    Always verify that webhook requests come from DCash's server IP: 41.209.57.197
  </Accordion>

  <Accordion title="Validate webhook data">
    Verify that the transaction details match your records before processing.
  </Accordion>

  <Accordion title="Log all webhooks">
    Keep logs of all webhook deliveries for debugging and audit purposes.
  </Accordion>

  <Accordion title="Handle errors gracefully">
    If processing fails, return 200 OK to prevent retries, then handle the error separately.
  </Accordion>

  <Accordion title="Monitor webhook health">
    Set up alerts for failed webhook deliveries to catch issues quickly.
  </Accordion>
</AccordionGroup>
