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

# Intégration

Voici les étapes à suivre pour une intégration correcte des webhooks :

<Steps>
  <Step title="Créer un point de terminaison HTTP pour une callback afin de recevoir les requêtes des webhooks.">
    Ce point de terminaison doit être capable de traiter les requêtes POST telle que ci-dessous:

    * **URL**: `https://website.com/webhook_payment`
    * **METHOD**: POST
    * **HEADERS**:

    ```
    ContentType: application/json
    HUB2-Signature: s1=XXXXXX,s0=XXXXXX
    ```

    * **BODY**:

    <Accordion title="Appuyer pour révéler.">
      ```json theme={null}
      {
      	"type": "payment_intent.created",
      	"data": {
      		"id":"pi_9lEjld8yF2USvijl7mnId",
      		"merchantId":"10",
      		"createdAt":"2021-03-03T11:16:39.280Z",
      		"updatedAt":"2021-03-03T11:16:39.288Z",
      				"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXJjaGFudElkIjoiMTAiLCJtb2RlIjoic2FuZGJveCIsInBheW1lbnRJZCI6InBpXzlsRWpsZDh5RjJVU3Zpamw3bW5JZCIsImlhdCI6MTYxNDc3MDE5OX0.fkak8HAfHvcCeCxtzBEx1bE39oWl4vkGNgWdhnAmhXo",
      		"purchaseReference":"ref_2020_11_10_001",
      		"customerReference":"cust_01924059",
      		"status":"payment_required",
      		"amount":100,
      		"currency":"XOF",
      		"payments":[],
      		"mode":"sandbox"
      	},
      	"id": "evt_O80mmIF5CNrBMbZIyHJye",
      	"createdAt": "2021-03-03 11:16:39.685+00"
      }
      ```
    </Accordion>

    <Note>
      C'est un exemple de webhook retourné en cas d'événement `payment_intent.created`.
    </Note>
  </Step>

  <Step title="Référencer ce point de terminaison dans l'API HUB2 et le souscrire à un événement.">
    L'API HUB2 a un point de terminaison dédié à cette action qui doit être appelé avec le contenu suivant :

    <Accordion title="Appuyer pour révéler.">
      ```json theme={null}
      {
      	"url": "https://website.com/webhook_payment",
      	"events": [
      		"payment.created",
      		"payment_intent.created",
      	],
      	"description": "This is a webhook trigger upon payment & payment_intent creation",
      	"metadata": {}
      }
      ```
    </Accordion>

    Voici des exemples de code pour faire ainsi :

    <CodeGroup>
      ```bash Curl theme={null}
      curl -X POST \
      	-H "Content-Type: application/json" \
      	-H "ApiKey: Your API KEY" \
      	-H "MerchantId: Your merchant Id" \
      	-H "Environment: Your API KEY environment 'live' or 'sandbox'" \
      	-d '{ "url": "https://my.webhook.target", "events": ["payment.created", "payment_intent.created"], "description": "This is a webhook trigger upon payment & payment_intent creation", "metadata": {} }' \
      https://api.hub2.io/webhooks
      ```

      ```typescript Typescript theme={null}
      import fetch from 'node-fetch';

      async function createWebhook() {
      		const response = await fetch('https://api.hub2.io/webhooks', {
      				method: 'POST',
      				headers: {
      						'Content-Type': 'application/json',
      						'ApiKey': 'Your API KEY',
      						'MerchantId': 'Your merchant Id',
      						'Environment': 'Your API KEY environment \'live\' or \'sandbox\''
      				},
      				body: JSON.stringify({
      						"url": "https://my.webhook.target",
      						"events": ["payment.created", "payment_intent.created"],
      						"description": "This is a webhook trigger upon payment & payment_intent creation",
      						"metadata": {}
      				})
      		});

      		if (response.ok) {
      				const result = await response.json();
      				console.log(result);
      		} else {
      				console.log(`HTTP Status: ${response.status}`);
      		}
      }

      createWebhook();
      ```

      ```python Python theme={null}
      import requests
      import json

      url = 'https://api.hub2.io/webhooks'

      headers = {
      		'Content-Type': 'application/json',
      		'ApiKey': 'Your API KEY',
      		'MerchantId': 'Your merchant Id',
      		'Environment': 'Your API KEY environment \'live\' or \'sandbox\'',
      }

      data = {
      		"url": "https://my.webhook.target",
      		"events": ["payment.created", "payment_intent.created"],
      		"description": "This is a webhook trigger upon payment & payment_intent creation",
      		"metadata": {}
      }

      response = requests.post(url, headers=headers, data=json.dumps(data))

      if response.status_code == 200:
      		print(response.json())
      else:
      		print(f'HTTP Status: {response.status_code}')
      ```
    </CodeGroup>

    Voici un exemple de réponse de l'API HUB2 à cet appel :

    <Accordion title="Appuyer pour révéler.">
      ```json theme={null}
      {
      	"id": "wh_z1urYtVFgEebtcj8fxp4v",
      	"createdAt": "2020-10-15T12:09:49.355Z",
      	"updatedAt": "2020-10-15T12:09:49.355Z",
      	"mode": "live",
      	"description": "This is a webhook trigger upon payment & payment_intent creation",
      	"events": ["payment.created", "payment_intent.created"],
      	"metadata": { },
      	"secret": "5257a869e7ecebeda32affa62cd...",
      	"status": "enabled",
      	"url": "https://website.com/webhook_payment"
      }
      ```
    </Accordion>

    <Note>
      Cette réponse contient un secret associé au webhook créé: `"secret": "5257a869e7ecebeda32affa62cd..."`.
    </Note>

    Ce secret doit être gardé précieusement, il sera nécessaire pour vérifier l'intégrité du webhook reçu.

    Pour plus de détails sur l'API Webhooks, consulter la documentation suivante :: [Documentation API Webhooks](/api-reference/webhooks)
  </Step>

  <Step title="Vérification de la signature du webhook.">
    <Warning>
      **Cette étape est nécessaire pour s'assurer que personne ne peut forger de faux webhooks.**

      Passer cette étape laisse une vulnérabilité pour des personnes malicieuses qui pourront valider leurs transactions eux-mêmes.
    </Warning>

    Afin de s'assurer que le webhook reçu provient bien de l'API HUB2, il est impératif de verifier la signature du body (payload).

    ### a. Se prémunir du secret associé au webhook.

    Ce secret a été généré à l'étape 2 (`"secret": "5257a869e7ecebeda32affa62cd..."` dans notre exemple).

    ### b. Signer le payload.

    Extraire le contenu du BODY de la requête POST envoyée par HUB2 (voir [Json response](#1-cr%C3%A9er-un-endpoint-de-callback-pour-les-webhooks-dans-votre-environnement-serveur)). Il en résulte une chaîne de caractères qui doit être signée via HMAC256 et le `secret`.

    Voici quelques exemples de procédure selon le langage de programmation utilisé :

    <CodeGroup>
      ```js Javascript theme={null}
      // Example with Javascript/NestJS
      import { createHmac, Hmac } from 'crypto';

      sign(json: string, secret: string): string {
      	const hmac: Hmac = createHmac('sha256', secret);
      	hmac.update(json);
      	return hmac.digest('hex');
      }
      ```

      ```python Python theme={null}
      # Example with Python
      import hashlib
      import hmac

      def sign(json, secret):
      	hmac_obj = hmac.new(secret.encode('utf-8'), json.encode('utf-8'), hashlib.sha256)
      	return hmac_obj.hexdigest()
      ```

      ```java Java theme={null}
      // Example with java
      import javax.crypto.Mac;
      import javax.crypto.spec.SecretKeySpec;
      import java.security.InvalidKeyException;
      import java.security.NoSuchAlgorithmException;

      public String sign(String json, String secret) {
      	try {
      		Mac mac = Mac.getInstance("HmacSHA256");
      		SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
      		mac.init(secretKey);
      		byte[] hmacBytes = mac.doFinal(json.getBytes());
      		return javax.xml.bind.DatatypeConverter.printHexBinary(hmacBytes).toLowerCase();
      	} catch (NoSuchAlgorithmException | InvalidKeyException e) {
      		// Handle exceptions
      	}
      }
      ```

      ```ruby Ruby theme={null}
      # Example with ruby
      require 'openssl'

      def sign(json, secret)
      	hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), secret, json)
      end
      ```

      ```c# C# theme={null}
      // Example with C#
      using System.Security.Cryptography;
      using System.Text;

      public string Sign(string json, string secret)
      {
      	using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret))
      	{
      		byte[] bytes = Encoding.UTF8.GetBytes(json);
      		byte[] hashBytes = hmac.ComputeHash(bytes);
      		return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
      	}
      }
      ```

      ```php PHP theme={null}
      // Example with PHP
      function sign($json, $secret) {
      	$hash = hash_hmac('sha256', $json, $secret);
      	return $hash;
      }
      ```
    </CodeGroup>

    Le corps de la requête doit être une string JSON. Soit le framework web utilisé retourne directement du JSON, soit il faut faire un appel type `JSON.stringify()` sur le corps de votre requête pour l'obtenir.

    ### c. Vérifier la signature.

    Pour finir il faut comparer la signature calculée à celle fournie par HUB2. La signature se situe dans les HEADERS de la requête.

    ```
    HUB2-Signature: s1=ABCD,s0=XYZ
    ```

    * `HUB2-Signature`: Nom du header
    * `s1`: Correspond à la signature faite avec le `secret` actif.
    * `s0`: Correspond à la signature faite avec un ancien `oldSecret` si présent.

    <Tip>
      Lors d'une mis à jour d'un `secret`, le précédent `secret` actif devient `oldSecret` pendant une durée de 24h et est utilisé pour générer la signature `s0`.
    </Tip>
  </Step>
</Steps>
