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

# Webhooks

> Receive and secure status change notifications.

Webhooks let iMoney Encaissement automatically send a notification to your application when a payment changes state. Use them to update an order, sync a back office or trigger internal processing without continuously polling the API.

A webhook complements the status lookup, it does not replace it: the notification tells you as soon as a state changes, while [Retrieve a transaction](https://docs.i-pay.money/en/api-reference/transactions/retrieve-a-payment.md) gives the status at the time of the call and serves as a fallback or for reconciliation.

## Creating a webhook

In the merchant dashboard, open **Développeurs** (Developers), then **Webhooks**. Then click **Ajouter** (Add) to register a new webhook.

![](https://mintcdn.com/i-futur/xDQnlGzGF7WUnnqj/documentation-assets/developer.png?fit=max\&auto=format\&n=xDQnlGzGF7WUnnqj\&q=85\&s=4137d26b5d50950fccfa1a0889525bfb)

![](https://mintcdn.com/i-futur/xDQnlGzGF7WUnnqj/documentation-assets/webhooks.png?fit=max\&auto=format\&n=xDQnlGzGF7WUnnqj\&q=85\&s=65bbb9aff9b7914e3969bb2c5d78c9a8)

The form asks for the following information:

| Field | Description |
| - | - |
| **URL** | URL of your receiving endpoint. If no protocol is given, iMoney Encaissement automatically adds `https://`. |
| **Hash secret** (Secret hash) | A value that **you** define. iMoney Encaissement sends it back unchanged in the `Secret-Hash` header of every notification, so that your server can compare it with what you configured here. |
| **Événements créés** (Created events) | Enables `payment_created` notifications. |
| **Événements en attente** (Pending events) | Enables `payment_pending` notifications. |
| **Événements réussis** (Succeeded events) | Enables `payment_succeeded` notifications. |
| **Événements échoués** (Failed events) | Enables `payment_failed` notifications. |
| **Événements remboursés** (Refunded events) | Enables `payment_refunded` notifications. |

You can enable one or more events on the same webhook. Only the checked events are sent to the configured URL.

![](https://mintcdn.com/i-futur/xDQnlGzGF7WUnnqj/documentation-assets/webhooks-create.png?fit=max\&auto=format\&n=xDQnlGzGF7WUnnqj\&q=85\&s=a398b00b4ca707be975593707e30b66a)

> **Important — what `Secret-Hash` is:** it is **not** a signature computed from the notification body (no HMAC, no hash of the payload). It is a static shared secret: you choose its value when creating the webhook, and iMoney Encaissement simply copies it unchanged into the `Secret-Hash` header on every delivery. Your server only has to compare the received value with the one you configured — there is nothing to recompute.

![](https://mintcdn.com/i-futur/xDQnlGzGF7WUnnqj/documentation-assets/api-keys.png?fit=max\&auto=format\&n=xDQnlGzGF7WUnnqj\&q=85\&s=a3148ccc168eb05f407aebf15c3d6a09)

> **Warning:** never share your webhook's secret hash. It is the only piece of information that lets your server check that a notification really comes from iMoney Encaissement rather than from a third party who guessed your URL.

Once you have chosen the events to receive, click **Enregistrer** (Save).

## Available events

There are five events, all related to the payment lifecycle:

| Event | When it is sent |
| - | - |
| `payment_created` | The payment has just been created. |
| `payment_pending` | The payment moves to the pending state. |
| `payment_succeeded` | The payment is successfully validated. |
| `payment_failed` | The payment fails. |
| `payment_refunded` | The payment is refunded. |

There are no events other than these five: only enable the ones your integration actually needs.

## Receiving a notification

When an enabled event occurs, iMoney Encaissement sends a `POST` request to your URL with a JSON body and the following headers:

```http theme={"theme":{"light":"github-light","dark":"github-dark"}}
Content-Type: application/json
Accept: application/json
Secret-Hash: your_secret_hash
```

Your endpoint must:

1. check that `Secret-Hash` matches the value configured in the dashboard;
2. process the JSON body;
3. return an HTTP `2xx` response to acknowledge receipt.

Non-`2xx` responses and network errors (timeout, unreachable endpoint) are recorded in the webhook history.

## Payload format

All notifications use the same base structure:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "data": {
    "external_reference": "ORDER-2026-001",
    "reference": "ipay_ref_123",
    "status": "succeeded",
    "msisdn": "97000000",
    "net_amount": 950,
    "amount": 1000,
    "failure_reason": null,
    "customer_name": "Client Demo",
    "payment_method": "credit_card",
    "validated_at": "2026-06-04T10:30:00.000Z"
  }
}
```

### Payload fields

| Field | Description |
| - | - |
| `external_reference` | Reference sent by your system when the payment was created (your `transaction_id`). |
| `reference` | iMoney Encaissement internal reference of the payment. |
| `status` | Current payment status: `initiated`, `pending`, `succeeded`, `failed` or `refunded`. |
| `msisdn` | Customer's payment number. |
| `net_amount` | Net amount after fees. |
| `amount` | Gross payment amount. |
| `failure_reason` | Reason for the failure when the payment failed, otherwise `null`. |
| `customer_name` | Customer name when available. |
| `payment_method` | Payment method used — see the [payment methods](https://docs.i-pay.money/en/guides/payouts-and-fees.md#fees-by-payment-method). |
| `validated_at` | Payment validation date when available, otherwise `null`. |

Depending on where the payment comes from, iMoney Encaissement may also add the following fields — they are **not** present on every notification:

| Conditional field | Present when |
| - | - |
| `dynamic_payment_reference` | The payment is linked to a dynamic payment. |
| `external_payment_reference` | The payment is linked to a [payment link](https://docs.i-pay.money/en/api-reference/payment-by-link/create-a-payment-link.md). |

On a failed payment, `failure_reason` holds the reason for the refusal when it is provided, and `validated_at` stays `null`; the
possible `status` values and the full contract of a payment's fields (types, constraints)
are described in [Retrieve a transaction](https://docs.i-pay.money/en/api-reference/transactions/retrieve-a-payment.md).

## Retry behavior

iMoney Encaissement sends the notification **once** as soon as the event occurs, then schedules a catch-up delivery ten minutes later. This catch-up delivery is only sent if **no delivery attempt has been recorded** for this event.

However, an attempt is recorded in both cases: when your server responded, and when the delivery failed (unreachable endpoint, non-`2xx` response, timeout). What this means:

* **a failed delivery is not replayed**: the ten-minute catch-up only covers the case where no delivery took place, not the case of a delivery that went wrong;
* there are **no** unlimited retries and no configurable number of attempts;
* once an attempt has failed, your application will not receive any more notifications for this event and must fall back on [Retrieve a transaction](https://docs.i-pay.money/en/api-reference/transactions/retrieve-a-payment.md) to get the final status.

So never treat the absence of a webhook as the absence of a state change, and do not build your integration on the assumption that a failure will be caught up: always reconcile through the API status lookup, especially for payments that stay `pending` longer than expected. The status lookup, not the notification, is the source of truth.

## Viewing the history

The **Webhooks** page shows the configured webhooks with their URL, enabled events, creation date and available actions.

For each webhook, the **Logs** button shows the history of delivery attempts, including the catch-up delivery where applicable. The history shows:

* the payment reference;
* the event sent;
* the HTTP status returned by your server;
* the body of the request sent;
* the response returned by your server;
* the delivery date.

The detail of a log lets you check the full payload and the information of the payment concerned.

## Best practices

* Use a stable public HTTPS URL.
* Always check the `Secret-Hash` header before processing the notification — it is a direct comparison with the value you configured, not a cryptographic computation.
* Return an HTTP `2xx` response quickly after receipt, before starting any long processing.
* Make your processing idempotent by using the iMoney Encaissement `reference`: do not process the same event twice if a notification reaches you more than once.
* Do not rely on the exact order of notifications: always check the `status` received rather than assuming a sequence.
* Do not wait indefinitely for a webhook that never arrives: reconcile pending payments with [Retrieve a transaction](https://docs.i-pay.money/en/api-reference/transactions/retrieve-a-payment.md).

Try these rules out in Sandbox before going live: the test numbers that produce a successful,
failed or pending payment — and therefore the corresponding events — are listed in the
[Sandbox and testing guide](https://docs.i-pay.money/en/guides/sandbox-and-testing.md). Once your webhook URL has been
tested in Sandbox, configure it again on your Live account by following
[Going live](https://docs.i-pay.money/en/getting-started.md#going-live).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.