> For the complete documentation index, see [llms.txt](https://docs.ledig.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ledig.io/hooks/webhooks.md).

# Webhooks

Ledig uses webhooks to notify your system in near‑real time when key events occur in your account.\
When an event is triggered, Ledig sends an HTTPS `POST` request with a JSON body to your registered webhook URL.

***

## Configure your webhook URL

You can configure your webhook URL in the Ledig Dashboard under **Settings → API & Webhooks**.\
If you do not see this section, contact us through **Request an account** on the homepage and we’ll follow up within 24 hours.

**Requirements**

* Your endpoint **must be HTTPS** and publicly reachable.
* Respond **quickly** and do heavier processing asynchronously.
* If you rotate API keys, remember to **update any downstream services** that depend on webhook data.

***

## Delivery behavior

* **Method**: `POST`
* **Content-Type**: `application/json`
* **Retries**: If your server responds with a non‑2xx code, Ledig retries the request **up to 3 times**.
* **Acknowledgement**: Always return **HTTP 200 OK**. You may optionally return `{ "ok": true }` in the response body.

> Tip: Because retries can produce duplicates, write your handler to be **idempotent**. Use the event `id` when present, or a dedup hash of the payload.

***

## Example delivery

```
POST /your/webhook/endpoint HTTP/1.1
Host: client.com
Content-Type: application/json
```

```json
{
  "event": "crypto_received",
  "id": "57L94BW6EOAGC58X",
  "wallet_alias": "proper Vault",
  "wallet_address": "0x20f4065BA127a801Ef20a4D7a1C94e61896857a0",
  "tx_hash": "0x496a74033fb7e489044297eb84594292ec781a4f19ca5ca091b343527514bde1",
  "status": "successful",
  "Business": "Facebook(test)",
  "coin": "USDC",
  "Amount": "0.5",
  "fee": "0"
}
```

**Expected response from your server**

```json
{ "ok": true }
```

***

## Event summary

| Event                       | When it fires                                            | Key fields                                                                                                                    |
| --------------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `settlement_wallet_update`  | A settlement wallet you submitted is reviewed or updated | `Alias`, `Address`, `Network`, `Asset Supported`, `status`, `Business`                                                        |
| `settlement_account_update` | A fiat settlement account is reviewed or updated         | `Alias`, `Bank Name`, `Account Number`, `Account Name`, `status`, `Currency`, `other details`                                 |
| `crypto_received`           | On‑chain funds are detected on one of your wallets       | `id`, `wallet_alias`, `wallet_address`, `tx_hash`, `coin`, `Amount`, `status`, `fee`                                          |
| `virtual_account_created`   | A new fiat virtual account is issued to you              | `Alias`, `Bank`, `Account Number`, `Account Name`, `Merchant Associated`, `Business`, `Currency`                              |
| `virtual_account_credited`  | A deposit lands in one of your virtual accounts          | `id`, `currency`, `Amount`, `status`, `Account received alias`, `Sender Bank`, `Sender account name`, `Sender account number` |
| `crypto_payout_update`      | The status of a crypto payout changes                    | `id`, `coin`, `Amount sent`, `Wallet received alias`, `status`, `fee`, `tx_hash`                                              |
| `admin_funding`             | An admin credits or debits your balance                  | `id`, `Asset`, `Amount`, `status`, `Business`, `fee`, `credit/debit`, `fiat/crypto`                                           |

***

## Event payloads

### 1. `settlement_wallet_update`

```json
{
  "event": "settlement_wallet_update",
  "Alias": "testing vaulty",
  "Address": "0x20f4065BA127a801Ef20a4D7a1C94e61896857a0",
  "Network": "Ethereum Erc20",
  "Asset Supported": "USDT, USDC",
  "status": "Rejected",
  "Business": "Facebook(test)"
}
```

**Use it to**

* Track the review process and final status for wallets submitted via **Add Settlement Wallet**.
* Update your allow‑list of payout destinations once a wallet becomes **Whitelisted**.

***

### 2. `settlement_account_update`

```json
{
  "event": "settlement_account_update",
  "Alias": "qasq",
  "Bank Name": "qa",
  "Account Number": "0129293239339",
  "Account Name": "aaqaq",
  "status": "Whitelisted",
  "Business": "Facebook(test)",
  "other details": "ssaaa\nggjntg\ngtrgkngthgkntknh\ntrmglmlthg",
  "Currency": "KES"
}
```

**Use it to**

* Detect when fiat settlement accounts become **Whitelisted** and safe for payouts.
* Refresh banking details when admins make changes.

***

### 3. `crypto_received`

```json
{
  "event": "crypto_received",
  "id": "57L94BW6EOAGC58X",
  "wallet_alias": "proper Vault",
  "wallet_address": "0x20f4065BA127a801Ef20a4D7a1C94e61896857a0",
  "tx_hash": "0x496a74033fb7e489044297eb84594292ec781a4f19ca5ca091b343527514bde1",
  "status": "successful",
  "Business": "Facebook(test)",
  "coin": "USDC",
  "Amount": "0.5",
  "fee": "0"
}
```

**Use it to**

* Credit customer balances when on‑chain deposits arrive.
* Update transaction history with `tx_hash` and final `status`.

***

### 4. `virtual_account_created`

```json
{
  "event": "virtual_account_created",
  "Alias": "Treasury account",
  "Bank": "Ledig bank",
  "Account Number": "001726334",
  "Account Name": "Konoha LTD",
  "Merchant Associated": "Uchiha LTD",
  "Business": "Konoha LTD",
  "Currency": "NGN"
}
```

**Use it to**

* Store the newly issued virtual account details for invoicing or internal routing.

***

### 5. `virtual_account_credited`

```json
{
  "event": "virtual_account_credited",
  "id": "dfeff3fcdd31dsdd",
  "currency": "NGN",
  "status": "successful",
  "Amount": "30000000",
  "Account received alias": "Vault B",
  "Business": "Konoha LTD",
  "Merchant Associated": "Uchiha Ltd",
  "Sender Bank": "Yaegar Bank",
  "Sender account name": "Paradis LTD",
  "Sender account number": "002912283"
}
```

**Use it to**

* Credit the correct sub‑ledger when a bank transfer lands in your virtual account.
* Reconcile sender details with your payers list.

***

### 6. `crypto_payout_update`

```json
{
  "event": "crypto_payout_update",
  "id": "dfeff3fcdd31dsdd",
  "coin": "usdt",
  "status": "successful",
  "Amount sent": "30000000",
  "Wallet received alias": "receiver A",
  "Business": "Konoha LTD",
  "fee": "20 usdt",
  "tx_hash": "gfgfhgghgjtyhjtyjjjkjmu"
}
```

**Use it to**

* Update payout status in your UI and post the blockchain `tx_hash` for tracking.
* Trigger notifications to finance or counterparties when payouts settle.

***

### 7. `admin_funding`

```json
{
  "event": "admin_funding",
  "id": "dfeff3fcdd31dsdd",
  "Asset": "NGN",
  "status": "successful",
  "Amount": "30000000",
  "Business": "Konoha LTD",
  "fee": "0",
  "credit/debit": "Credit",
  "fiat/crypto": "Fiat"
}
```

**Use it to**

* Reflect manual adjustments performed by Ledig admins in your internal balances.

***

## Building your webhook handler

Below are minimal examples. They simply parse JSON, log the event, and return `{ "ok": true }` quickly. Do heavier processing asynchronously.

### Node.js (Express)

```js
import express from "express";

const app = express();
app.use(express.json({ type: "application/json" }));

app.post("/webhooks/ledig", async (req, res) => {
  const evt = req.body;

  // TODO: implement idempotency (evt.id when present)
  console.log("Ledig webhook:", evt);

  // Acknowledge quickly
  return res.status(200).json({ ok: true });
});

app.listen(3000, () => console.log("Webhook server listening on 3000"));
```

### Python (Flask)

```python
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.post("/webhooks/ledig")
def ledig_webhook():
    evt = request.get_json(force=True, silent=True) or {}
    # TODO: idempotency using evt.get("id")
    print("Ledig webhook:", evt)
    return jsonify({"ok": True}), 200

if __name__ == "__main__":
    app.run(port=3000)
```

### cURL test

```bash
curl -X POST https://your-domain.com/webhooks/ledig   -H "Content-Type: application/json"   -d '{
    "event":"crypto_received",
    "id":"TEST123",
    "coin":"USDT",
    "Amount":"10",
    "status":"successful"
  }'
```

***

## Best practices

* **Acknowledge fast**. Do not block on long‑running work.
* **Idempotency**. Use `id` when present, or hash the payload.
* **Queue processing**. Publish to a queue or job worker, then return 200.
* **Monitor failures**. Alert on repeated non‑2xx responses from your endpoint.
* **Keep your URL updated**. Rotate or migrate endpoints via the dashboard settings.

***

## Troubleshooting

* You are not receiving events
  * Confirm your URL is publicly reachable over HTTPS.
  * Check that the URL is correctly configured in **Settings → API & Webhooks**.
  * Inspect your server logs for non‑2xx status codes and timeouts.
* You see duplicate deliveries
  * Implement idempotency as described above. Retries can cause duplicates.
* Payload fields differ from your expectations
  * Some attributes may change as Ledig evolves. Write tolerant parsers and log unknown fields for visibility.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.ledig.io/hooks/webhooks.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
