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

# Webhooks

> Les webhooks vous permettent de configurer un systeme de notification qui peut etre utilise pour recevoir des mises a jour sur certaines requetes effectuees a l API Yiksi Pay.

<Note>
  En resume<br />
  Les webhooks envoient des notifications en temps reel a votre serveur lorsque des evenements se produisent—depots, retraits, swaps et plus. Au lieu de consulter l'API, votre serveur recoit des mises a jour instantanees lorsque les transactions sont terminees.
</Note>

## Prerequis

Avant de configurer des webhooks, assurez-vous d'avoir :

<Steps>
  <Step title="Cle API">
    Obtenez votre cle API depuis le [Tableau de bord Yiksi Pay](https://dashboard.yiksipay.com). Naviguez vers **Developers** pour en generer une.
  </Step>

  <Step title="Endpoint Webhook">
    Creez un endpoint POST sur votre serveur qui peut recevoir des payloads JSON et retourner une reponse `200 OK`.
  </Step>

  <Step title="URL HTTPS (Production)">
    Pour la production, votre URL webhook doit utiliser HTTPS. Pour les tests locaux, utilisez des outils comme [ngrok](https://ngrok.com/) ou [webhook.site](https://webhook.site).
  </Step>

  <Step title="Configuration de l'URL">
    Configurez votre URL webhook sur la page développeurs depuis votre espace d'accueil.
  </Step>
</Steps>

## Comment Ca Fonctionne

Lorsque vous faites une requete a un endpoint API, vous vous attendez a obtenir une reponse quasi immediate. Cependant, certaines requetes peuvent prendre beaucoup de temps a traiter, ce qui peut entrainer des erreurs de timeout. Afin d'eviter une erreur de timeout, une reponse en attente est retournee. Puisque vos enregistrements doivent etre mis a jour avec l'etat final de la requete, vous devez soit :

1. Faire une requete pour une mise a jour (communement appelee polling) ou,
2. Ecouter les evenements en utilisant une URL webhook.

<Tip>
  Conseil Utile<br />
  Nous recommandons d'utiliser les webhooks pour fournir de la valeur a vos clients plutot que d'utiliser des callbacks ou le polling. Avec les callbacks, nous n'avons pas de controle sur ce qui se passe du cote du client. Vous non plus. Les callbacks peuvent echouer si la connexion reseau sur l'appareil d'un client echoue ou est faible ou si l'appareil s'eteint apres une transaction.
</Tip>

## Polling vs Webhooks

Le polling necessite de faire une requete `GET` a intervalles reguliers pour obtenir le statut final d'une requete. Par exemple, lorsque vous attribuez une adresse a un client pour les depots, vous continuez a faire une requete pour les transactions liees a l'adresse jusqu'a ce que vous en trouviez une.

Avec les webhooks, le serveur de ressources, Yiksi Pay dans ce cas, envoie des mises a jour a votre serveur lorsque le statut de votre requete change. Le changement de statut d'une requete est appele un evenement. Vous ecouterez typiquement ces evenements sur un endpoint POST appele votre URL webhook.

Le tableau ci-dessous met en evidence quelques differences entre le polling et les webhooks :

|                            | **Polling** | **Webhooks** |
| -------------------------- | ----------- | ------------ |
| **Mode de mise a jour**    | Manuel      | Automatique  |
| **Limitation de debit**    | Oui         | Non          |
| **Impacte par le scaling** | Oui         | Non          |

## Creer une URL webhook

Une URL webhook est simplement un endpoint POST vers lequel un serveur de ressources envoie des mises a jour. L'URL doit analyser une requete JSON et retourner un `200 OK` :

<CodeGroup>
  ```javascript webhook.js theme={null}
  // Using Express
  app.post("/my/webhook/url", function(req, res) {
      // Retrieve the request's body
      const event = req.body;
      // Do something with event
      res.send(200);
  });
  ```

  ```php webhook.php theme={null}
  <?php
  // Retrieve the request's body and parse it as JSON
  $input = file_get_contents("php://input");
  $event = json_decode($input, true);

  // Check for JSON parsing errors
  if (json_last_error() !== JSON_ERROR_NONE) {
      http_response_code(400); // Bad Request
      echo json_encode(["error" => "Invalid JSON"]);
      exit();
  }

  // Do something with $event
  // For example, log the event or process it
  // log_event($event);

  // Send a successful response
  http_response_code(200); // HTTP status code 200 OK
  echo json_encode(["status" => "success"]);
  ?>
  ```
</CodeGroup>

Lorsque votre URL webhook recoit un evenement, elle doit analyser et accuser reception de l'evenement. Accuser reception d'un evenement signifie retourner un `200 OK` dans l'en-tete HTTP. Sans un `200 OK` dans l'en-tete de reponse, nous continuerons a envoyer des evenements pendant les 2 heures et 35 minutes suivantes :

* Nous tenterons d'envoyer les webhooks 5 fois avec un delai croissant entre chaque tentative, en commencant par 5 minutes et en augmentant de maniere exponentielle jusqu'a 80 minutes. La duree totale pour ces 5 tentatives sera d'environ 2 heures et 35 minutes.

<Warning>
  Evitez les taches de longue duree<br />
  Si vous avez des taches de longue duree dans votre fonction webhook, vous devriez accuser reception de l'evenement avant d'executer les taches de longue duree. Les taches de longue duree entraineront un timeout de requete et une reponse d'erreur automatique de votre serveur. Sans une reponse 200 OK, nous reessayons comme decrit dans le paragraphe ci-dessus.
</Warning>

## Tester les Webhooks Localement

Pendant le developpement, vous pouvez configurer votre URL webhook dans votre environnement de portefeuille principal TEST vers une adresse locale, telle que `http://localhost` ou `127.0.0.1`.

Pour exposer votre serveur local a Internet a des fins de test, envisagez d'utiliser un outil comme [ngrok](https://ngrok.com/) ou [webhook.site](https://webhook.site). Ces outils vous permettent de voir a quoi ressemble le payload webhook et de simuler des evenements webhook localement avant de deployer votre application dans un environnement de production.

En utilisant ces outils, vous pouvez vous assurer que votre integration webhook fonctionne correctement et gerer tous les problemes dans un environnement local et controle avant de passer a la production.

### Renvoyer le Webhook de Transaction

Dans le cas ou pour une raison quelconque vous ne recevez pas le webhook de transaction et que le temps de backoff est ecoule, nous avons fourni une API que vous pouvez utiliser pour renvoyer un webhook de transaction

<Warning>
  Utilisez avec precaution !<br />
  Cela peut conduire au traitement de transactions deja completees, assurez-vous d'avoir une validation appropriee en place lors de l'utilisation de cet endpoint.
</Warning>

<CodeGroup>
  ```bash resend.cmd theme={null}
  curl --request POST \
    --url https://api.yiksipay.com/v1/wallets/{walletId}/transactions/webhooks/resend \
    --header 'Content-Type: application/json' \
    --header 'x-api-key: <api-key>' \
    --data '{
    "id": "TRANSACTION_ID"
  }'
  ```

  ```js resend.js theme={null}
  const options = {
    method: 'POST',
    headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
    body: '{"id":"TRANSACTION_ID"}'
  };

  fetch('https://api.yiksipay.com/v1/wallets/{walletId}/transactions/webhooks/resend', options)
    .then(response => response.json())
    .then(response => console.log(response))
    .catch(err => console.error(err));
  ```
</CodeGroup>

## Verifier l'origine de l'evenement

Puisque votre URL webhook est publiquement accessible, vous devez verifier que les evenements proviennent de Yiksi Pay et non d'un acteur malveillant. Il existe deux facons de s'assurer que les evenements vers votre URL webhook proviennent de Yiksi Pay :

1. Validation de signature (recommande)

### Validation de signature

Les evenements envoyes depuis Yiksi Pay portent l'en-tete x-yiksipay-signature. La valeur de cet en-tete est une signature HMAC SHA512 du payload de l'evenement signee en utilisant votre cle secrete. La verification de la signature de l'en-tete doit etre effectuee avant de traiter l'evenement :

<CodeGroup>
  ```js signature.js theme={null}
  const crypto = require('crypto');
  const apiKey = process.env.WALLET_API_KEY;
  // Using Express
  app.post("/my/webhook/url", function(req, res) {
      //validate event
      const hash = crypto.createHmac('sha512', apiKey).update(JSON.stringify(req.body)).digest('hex');
      if (hash == req.headers['x-yiksipay-signature']) {
      // Retrieve the request's body
      const event = req.body;
      // Do something with event
      }
      res.send(200);
  });
  ```

  ```php signature.php theme={null}
  <?php

  // Retrieve the request's body
  $body = file_get_contents('php://input');

  // Get the API key from the environment
  $apiKey = getenv('WALLET_API_KEY');

  // Using HMAC-SHA512 for hashing
  $signature = hash_hmac('sha512', $body, $apiKey);

  // Check if the signature matches the one provided in the headers
  if ($signature === $_SERVER['HTTP_X_YIKSIPAY_SIGNATURE']) {
      // The signature is valid, proceed with processing the event
      $event = json_decode($body, true);
      // Do something with $event
  }

  // Send a 200 OK response
  http_response_code(200);
  ```

  ```python signature.py theme={null}
  import hmac
  import hashlib
  import json
  from flask import Flask, request, jsonify

  app = Flask(__name__)

  @app.route("/my/webhook/url", methods=["POST"])
  def webhook():
      # Retrieve the request's body
      body = request.get_data()

      # Get the API key
      api_key = os.environ.get('WALLET_API_KEY')

      # Using HMAC-SHA512 for hashing
      signature = hmac.new(api_key.encode('utf-8'), body, hashlib.sha512).hexdigest()

      # Check if the signature matches the one provided in the headers
      if signature == request.headers.get('X-YiksiPay-Signature'):
          # The signature is valid, proceed with processing the event
          event = json.loads(body.decode('utf-8'))
          # Do something with event

      # Send a 200 OK response
      return '', 200
  ```
</CodeGroup>

## Checklist de Mise en Production

Maintenant que vous avez cree avec succes votre URL webhook, voici quelques facons d'assurer une experience agreable :

* Ajoutez l'URL webhook sur votre page développeurs sur le tableau de bord [Yiksi Pay](https://dashboard.yiksipay.com/developers)
* Assurez-vous que votre URL webhook est publiquement accessible (les URL localhost ne peuvent pas recevoir d'evenements)
* Si vous utilisez `.htaccess`, n'oubliez pas d'ajouter le `/` final a l'URL
* Testez votre webhook pour vous assurer que vous obtenez le corps JSON et retournez une reponse HTTP `200 OK`
* Si votre fonction webhook a des taches de longue duree, vous devriez d'abord accuser reception du webhook en retournant un `200 OK` avant de proceder aux taches de longue duree
* Si nous n'obtenons pas une reponse HTTP `200 OK` de vos webhooks, nous la signalons comme une tentative echouee
* Nous tenterons d'envoyer les webhooks 5 fois avec un delai croissant entre chaque tentative, en commencant par 5 minutes et en augmentant de maniere exponentielle jusqu'a 80 minutes. La duree totale pour ces 5 tentatives sera d'environ 2 heures et 35 minutes.

## Types d'evenements

Voici les evenements que nous declenchons actuellement. Nous ajouterons d'autres a cette liste a mesure que nous nous connecterons a plus d'actions a l'avenir.

## Exemples d'Evenements

Voici des exemples de payloads webhook pour certains des evenements les plus courants :

<Tabs>
  <Tab title="Depot Reussi">
    ```json theme={null}
    {
        "event": "deposit.success",
        "data": {
            "id": "6d2f9646-cae4-48a5-8bfe-1f9379868d4f",
            "reference": "LSk5RLfSrR",
            "senderAddress": "0x2455eC6700092991Ce0782365A89d5Cd89c8Fa22",
            "recipientAddress": "0xe1037B45b48390285e5067424053fa35c478296b",
            "amount": "10.0",
            "amountPaid": "10.0",
            "fee": null,
            "currency": "USD",
            "blockNumber": 6928760,
            "blockHash": "0x5f2e0ed782752b9559e7a3d89c0fb9f6706e4866e74ba7a434cf933bb3f02a2b",
            "hash": "0x94c733496df59c15e5a489f20374096bba31166a8e149ceea4d410e3e5821357",
            "confirmations": 6,
            "confirmed": true,
            "gasPrice": "1201381238",
            "gasUsed": "62159",
            "gasFee": "0.000074676656372842",
            "status": "SUCCESS",
            "type": "DEPOSIT",
            "note": null,
            "amlScreening": {
                "provider": "ofac",
                "status": "success",
                "message": "Address is not sanctioned"
            },
            "network": "testnet",
            "chainId": 11155111,
            "metadata": {
                "user_id": 1
            },
            "createdAt": "2024-10-23T11:19:58.451Z",
            "updatedAt": "2024-10-23T11:19:58.451Z",
            "asset": {
                "id": "fe04a28c-c615-4e41-8eda-f84c862864f5",
                "name": "USDC Coin",
                "symbol": "USDC",
                "decimals": 6
            },
            "address": {
                "id": "0a69c48a-6c6f-422c-bd6a-70de3306a3ac",
                "address": "0xe1037B45b48390285e5067424053fa35c478296b",
                "name": "Customer 1"
            },
            "blockchain": {
                "id": "85ffc132-3972-4c9e-99a5-5cf0ccb688bf",
                "name": "ethereum",
                "symbol": "eth",
                "slug": "ethereum"
            },
            "wallet": {
                "id": "d236a191-c1d4-423c-a439-54ce6542ca41",
                "name": "Ethereum Master Wallet",
                "address": "0x947514e4B803e312C312da0F1B41fEDdbe15ae7a"
            }
        }
    }
    ```
  </Tab>

  <Tab title="Depot en Traitement">
    ```json theme={null}
    {
        "event": "deposit.processing",
        "data": {
            "id": "6d2f9646-cae4-48a5-8bfe-1f9379868d4f",
            "reference": "LSk5RLfSrR",
            "senderAddress": "0x2455eC6700092991Ce0782365A89d5Cd89c8Fa22",
            "recipientAddress": "0xe1037B45b48390285e5067424053fa35c478296b",
            "amount": "10.0",
            "amountPaid": "10.0",
            "status": "PROCESSING",
            "type": "DEPOSIT",
            "network": "testnet"
        }
    }
    ```
  </Tab>

  <Tab title="Retrait Reussi">
    ```json theme={null}
    {
        "event": "withdraw.success",
        "data": {
            "id": "081d6315-159f-4c38-b02a-c4708836c5bd",
            "reference": "y8lvy55cK",
            "senderAddress": "0x947514e4B803e312C312da0F1B41fEDdbe15ae7a",
            "recipientAddress": "0x2455eC6700092991Ce0782365A89d5Cd89c8Fa22",
            "amount": "10",
            "amountPaid": "10",
            "status": "SUCCESS",
            "type": "WITHDRAW",
            "network": "testnet"
        }
    }
    ```
  </Tab>

  <Tab title="Swap Reussi">
    ```json theme={null}
    {
        "event": "swap.success",
        "data": {
            "id": "99a2b490-0798-460b-9265-4d99f182fe52",
            "reference": "ZMxcorDGtf",
            "senderAddress": "0xAA2d5fd5e7bE97E214f8565DCf3a4862719960b5",
            "recipientAddress": "0xb55c054D8eE75224E1033e6eC775B4F62D942b43",
            "amount": "5",
            "status": "SUCCESS",
            "type": "SWAP",
            "network": "mainnet",
            "toAmount": "4.965398",
            "rate": "0.9930796000000001",
            "asset": {
                "name": "USD Coin",
                "symbol": "USDC"
            },
            "toAsset": {
                "name": "Tether USD",
                "symbol": "USDT"
            }
        }
    }
    ```
  </Tab>
</Tabs>

### Types d'Evenements Disponibles

| Evenement             | Description                                        |
| --------------------- | -------------------------------------------------- |
| `deposit.processing`  | Un depot est en cours de traitement                |
| `deposit.success`     | Un depot a ete traite avec succes                  |
| `deposit.failed`      | Un depot a echoue                                  |
| `deposit.cancelled`   | Un depot a ete annule                              |
| `withdraw.processing` | Un retrait est en cours de traitement              |
| `withdraw.success`    | Un retrait a ete traite avec succes                |
| `withdraw.failed`     | Un retrait a echoue                                |
| `withdraw.cancelled`  | Un retrait a ete annule                            |
| `swap.success`        | Un swap a ete execute avec succes                  |
| `swap.failed`         | Un swap a echoue                                   |
| `signed.success`      | Une transaction signee a ete completee avec succes |
| `signed.failed`       | Une transaction signee a echoue                    |

<Note>
  Les payloads webhook complets incluent des informations detaillees sur les transactions, actifs, blockchains et portefeuilles. Consultez les onglets d'exemples ci-dessus pour les structures de payload completes.
</Note>

<br />

<br />

Bon codage !
