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

# Webhook

**A webhook is an HTTP-based callback function that allows lightweight, event-driven communication between 2 application programming interfaces (APIs). Webhooks are used by a wide variety of web apps to receive small amounts of data from other apps。**

**Response Data(That is the response data that webhookUrl in the request parameter needs to give us)**
<Note> If success, http statusCode it must be 200</Note>

* **statusCode** is the http status  of response to your request . If success,it must be **200**. If you do not return a status code value of 200, we will retry the response to your webhook address.

**Response Data(The response result we give to the webhookUrl)**
**Content-Type: application/json**
**Response  Attributes**

| **Parameter** | **Type** | **Value** | **Description**                                                                                  |
| ------------- | -------- | --------- | ------------------------------------------------------------------------------------------------ |
| signature     | String   |           | message body signature: signature  =sha1(sort(clientId、timestamp、nonce, dataEncrypt))            |
| dataEncrypt   | String   |           | message body encryption, need decryption processing is required to obtain the real response data |
| timestamp     | Number   |           |                                                                                                  |
| nonce         | String   |           |                                                                                                  |

```json theme={null}
{
  "signature": "04e30dd43d9d8f95dd7c127dad617f0929d61c1d",
  "dataEncrypt": "LuG1OVSVIwOO/xpW00eSYo77Ncxa9h4VKmOJRjwoyoAmCIS/8FdJRJ+BpZn90BVAAg8xpU1bMmcDlAYDT010Wa9tNi1jivX25Ld03iA4EKs=",
  "timestamp": 1710757981609,
  "nonce": "1529"
}
```

When we complete the signature checksum and dataEncrypt decryption, we can get the real response content.
The decrypted content of dataEncrypt is:

| **Parameter** | **Type** | **Value**                                                                                                | **Description**                                                                                                                               |
| ------------- | -------- | -------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| \_id          | String   |                                                                                                          | \_id: returned by each interface                                                                                                              |
| status        | Number   | 2  or  3  or 4                                                                                           | status: the status of  image or video or faceswap or background change or avatar or   audio： 【1:queueing, 2:processing,3:completed, 4:failed】 |
| type          | String   | faceswap or image or audio or talking photo or video translate or background change or avatar or lipsync | Distinguish the type of each interface                                                                                                        |
| url           | String   |                                                                                                          | when staus = 3, the url  is the final result about audio, image, and video.                                                                   |

**Next, we will introduce the process and methods of encryption and decryption.**

### Encryption and Decryption technology solution

The encryption and decryption technical solution is implemented based on the AES encryption and decryption algorithm, as follows:

1. clientSecret: This is the message encryption and decryption Key. The length is fixed at 24 characters. ClientSecret is used as the encryption key.
2. AES adopts CBC mode, the secret key length is 24 bytes (192 bits), and the data is filled with PKCS#7; PKCS#7: K is the number of bytes of the secret key (24 is used), Buf is the content to be encrypted, N is its number of bytes. Buf needs to be filled to an integer multiple of K. Fill (K - N%K) bytes at the end of Buf, and the content of each byte is (K - N%K).
3. The IV length of AES is 16 bytes, and clientId is used as the IV.

**Message body encryption**
dataEncrypt is the result of the platform encrypting the message as follows:

* dataEncrypt = AES\_Encrypt( data, clientId, clientSecret )
  Among them, data is the body content we need to transmit, clientId is the initial vector, and clientSecret is the encryption key.

**Message body signature**
In order to verify the legitimacy of the message body, developers can verify the authenticity of the message body and decrypt the message body that passes the verification.
Specific method: dataSignature=sha1(sort(clientId、timestamp、nonce, dataEncrypt))

| **Parameter** | **Description**                                            |
| ------------- | ---------------------------------------------------------- |
| clientId      | clientId  of  user key pair                                |
| timestamp     | timestamp in body                                          |
| nonce         | nonce in body                                              |
| dataEncrypt   | The previous article describes the ciphertext message body |

**Message body verification and decryption**
The developer first verifies the correctness of the message body signature, and then decrypts the message body after passing the verification.

**Ways of identifying:**

1. The developer calculates the signature,compareSignature=sha1(sort(clientId、timestamp、nonce, dataEncrypt))
2. Compare compareSignature and the signature in the body to see if they are equal. If they are equal, the verification is passed.

The decryption method is as follows:

* data = AES\_Decrypt(dataEncrypt, clientSecret);

**Example: Encryption and Decryption**

1. To use nodejs or python or java for encryption.

<CodeGroup>
  ```javascript Nodejs theme={null}
  // To use nodejs for encryption, you need to install crypto-js. Use the command npm install crypto-js to install it.
  const CryptoJS = require('crypto-js')
  const crypto = require('crypto');


  // Generate signature
  function generateMsgSignature(clientId, timestamp, nonce, msgEncrypt){
      const sortedStr = [clientId, timestamp, nonce, msgEncrypt].sort().join('');
      const hash = crypto.createHash('sha1').update(sortedStr).digest('hex');
      return hash;
  }


  // decryption algorithm
  function generateAesDecrypt(dataEncrypt,clientId,clientSecret){
      const aesKey = clientSecret
      const key = CryptoJS.enc.Utf8.parse(aesKey)
      const iv = CryptoJS.enc.Utf8.parse(clientId)
      const decrypted = CryptoJS.AES.decrypt(dataEncrypt, key, {
          iv: iv,
          mode: CryptoJS.mode.CBC,
          padding: CryptoJS.pad.Pkcs7
      })
      return decrypted.toString(CryptoJS.enc.Utf8)
  }


  // Encryption Algorithm
  function generateAesEncrypt(data,clientId,clientSecret){
      const aesKey = clientSecret
      const key = CryptoJS.enc.Utf8.parse(aesKey)
      const iv = CryptoJS.enc.Utf8.parse(clientId)
      const srcs = CryptoJS.enc.Utf8.parse(data)
      // CBC encryption method, Pkcs7 padding method
      const encrypted = CryptoJS.AES.encrypt(srcs, key, {
              iv: iv,
              mode: CryptoJS.mode.CBC,
              padding: CryptoJS.pad.Pkcs7
      })
      return encrypted.toString()
  }
  ```

  ```python Python theme={null}
  from hashlib import sha1
  from Crypto.Cipher import AES
  from Crypto.Util.Padding import pad, unpad
  from Crypto.Random import get_random_bytes

  # Generate signature
  def generate_msg_signature(client_id, timestamp, nonce, msg_encrypt):
      sorted_str = ''.join(sorted([client_id, timestamp, nonce, msg_encrypt]))
      hash_obj = sha1(sorted_str.encode())
      return hash_obj.hexdigest()


  # Decryption algorithm
  def generate_aes_decrypt(data_encrypt, client_id, client_secret):
      aes_key = client_secret.encode()
      iv = client_id.encode()
      cipher = AES.new(aes_key, AES.MODE_CBC, iv)
      decrypted = unpad(cipher.decrypt(data_encrypt), AES.block_size)
      return decrypted.decode()


  # Encryption algorithm
  def generate_aes_encrypt(data, client_id, client_secret):
      aes_key = client_secret.encode()
      iv = client_id.encode()
      cipher = AES.new(aes_key, AES.MODE_CBC, iv)
      padded_data = pad(data.encode(), AES.block_size)
      encrypted = cipher.encrypt(padded_data)
      return encrypted
  ```

  ```java Java theme={null}
  import java.security.MessageDigest;
  import javax.crypto.Cipher;
  import javax.crypto.spec.IvParameterSpec;
  import javax.crypto.spec.SecretKeySpec;
  import java.util.Arrays;
  import java.nio.charset.StandardCharsets;
  import javax.xml.bind.DatatypeConverter;

  public class CryptoUtils {

      // Generate signature
      public static String generateMsgSignature(String clientId, String timestamp, String nonce, String msgEncrypt) {
          String[] arr = {clientId, timestamp, nonce, msgEncrypt};
          Arrays.sort(arr);
          String sortedStr = String.join("", arr);
          return sha1(sortedStr);
      }

      // SHA-1 hash function
      private static String sha1(String input) {
          try {
              MessageDigest md = MessageDigest.getInstance("SHA-1");
              byte[] hashBytes = md.digest(input.getBytes(StandardCharsets.UTF_8));
              return DatatypeConverter.printHexBinary(hashBytes).toLowerCase();
          } catch (Exception e) {
              e.printStackTrace();
              return null;
          }
      }

      // Decryption algorithm
      public static String generateAesDecrypt(String dataEncrypt, String clientId, String clientSecret) {
          try {
              byte[] keyBytes = clientSecret.getBytes(StandardCharsets.UTF_8);
              byte[] ivBytes = clientId.getBytes(StandardCharsets.UTF_8);

              SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
              IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);

              Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
              cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);

              byte[] encryptedBytes = DatatypeConverter.parseHexBinary(dataEncrypt);
              byte[] decryptedBytes = cipher.doFinal(encryptedBytes);

              return new String(decryptedBytes, StandardCharsets.UTF_8);
          } catch (Exception e) {
              e.printStackTrace();
              return null;
          }
      }

      // Encryption algorithm
      public static String generateAesEncrypt(String data, String clientId, String clientSecret) {
          try {
              byte[] keyBytes = clientSecret.getBytes(StandardCharsets.UTF_8);
              byte[] ivBytes = clientId.getBytes(StandardCharsets.UTF_8);

              SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
              IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);

              Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
              cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);

              byte[] encryptedBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
              return DatatypeConverter.printHexBinary(encryptedBytes).toLowerCase();
          } catch (Exception e) {
              e.printStackTrace();
              return null;
          }
      }

      // Example usage
      public static void main(String[] args) {
          String clientId = "your_client_id";
          String clientSecret = "your_client_secret";
          String timestamp = "your_timestamp";
          String nonce = "your_nonce";
          String msgEncrypt = "your_encrypted_message";

          // Generate signature
          String signature = generateMsgSignature(clientId, timestamp, nonce, msgEncrypt);
          System.out.println("Signature: " + signature);

          // Encryption
          String data = "your_data_to_encrypt";
          String encryptedData = generateAesEncrypt(data, clientId, clientSecret);
          System.out.println("Encrypted Data: " + encryptedData);

          // Decryption
          String decryptedData = generateAesDecrypt(encryptedData, clientId, clientSecret);
          System.out.println("Decrypted Data: " + decryptedData);
      }
  }

  ```
</CodeGroup>

2. Assume that our webhookUrl has obtained the corresponding data, such as the following corresponding data

```json theme={null}
{
  "signature": "04e30dd43d9d8f95dd7c127dad617f0929d61c1d",
  "dataEncrypt": "LuG1OVSVIwOO/xpW00eSYo77Ncxa9h4VKmOJRjwoyoAmCIS/8FdJRJ+BpZn90BVAAg8xpU1bMmcDlAYDT010Wa9tNi1jivX25Ld03iA4EKs=",
  "timestamp": 1710757981609,
  "nonce": 1529
}
```

3. To verify the correctness of the signature and decrypt the content, clientId and clientSecret are required.

<CodeGroup>
  ```javascript Nodejs theme={null}
  // express example
  const obj = {
    "signature": "04e30dd43d9d8f95dd7c127dad617f0929d61c1d",
    "dataEncrypt": "LuG1OVSVIwOO/xpW00eSYo77Ncxa9h4VKmOJRjwoyoAmCIS/8FdJRJ+BpZn90BVAAg8xpU1bMmcDlAYDT010Wa9tNi1jivX25Ld03iA4EKs=",
    "timestamp": 1710757981609,
    "nonce": 1529
  }
   
   let clientId = "AKDt8rWEczpYPzCGur2xE="
   let clientSecret = "nmwUjMAK0PJpl0MOiXLOOOwZADm0gkLo"
   let signature = obj.signature
   let msg_encrypt = obj.dataEncrypt
   let timestamp = obj.timestamp
   let nonce = obj.nonce
   let newSignature = generateMsgSignature(clientId,timestamp,nonce,msg_encrypt)
   if (signature===newSignature) {
       let result = generateAesDecrypt(msg_encrypt,clientId,clientSecret)
       // Handle your own business logic
       response.status(200).json({})  // If the processing is successful,http statusCode:200 must be returned.
    }else {
       response.status(400).json({})
    }
  ```

  ```python Python theme={null}
  import hashlib
  from Crypto.Cipher import AES
  from Crypto.Util.Padding import unpad
  import base64

  # Generate signature
  def generate_msg_signature(client_id, timestamp, nonce, msg_encrypt):
      sorted_str = ''.join(sorted([client_id, str(timestamp), str(nonce), msg_encrypt]))
      hash_obj = hashlib.sha1(sorted_str.encode())
      return hash_obj.hexdigest()

  # Decryption algorithm
  def generate_aes_decrypt(data_encrypt, client_id, client_secret):
      aes_key = client_secret.encode()
      iv = client_id.encode()
      cipher = AES.new(aes_key, AES.MODE_CBC, iv)
      decrypted = unpad(cipher.decrypt(base64.b64decode(data_encrypt)), AES.block_size)
      return decrypted.decode()

  # Example usage
  if __name__ == "__main__":
      obj = {
          "signature": "04e30dd43d9d8f95dd7c127dad617f0929d61c1d",
          "dataEncrypt": "LuG1OVSVIwOO/xpW00eSYo77Ncxa9h4VKmOJRjwoyoAmCIS/8FdJRJ+BpZn90BVAAg8xpU1bMmcDlAYDT010Wa9tNi1jivX25Ld03iA4EKs=",
          "timestamp": 1710757981609,
          "nonce": 1529
      }

      clientId = "AKDt8rWEczpYPzCGur2xE="
      clientSecret = "nmwUjMAK0PJpl0MOiXLOOOwZADm0gkLo"
      signature = obj["signature"]
      msg_encrypt = obj["dataEncrypt"]
      timestamp = obj["timestamp"]
      nonce = obj["nonce"]

      new_signature = generate_msg_signature(clientId, timestamp, nonce, msg_encrypt)
      if signature == new_signature:
          result = generate_aes_decrypt(msg_encrypt, clientId, clientSecret)
          # Handle your own business logic
          print("Decrypted Data:", result)
          # Return success http satusCode 200
          
      else:
          # Return error http statuCode 400

  ```

  ```java Java theme={null}
  import java.security.MessageDigest;
  import java.util.Arrays;
  import javax.crypto.Cipher;
  import javax.crypto.spec.IvParameterSpec;
  import javax.crypto.spec.SecretKeySpec;
  import java.util.Base64;

  public class CryptoUtils {

      // Generate signature
      public static String generateMsgSignature(String clientId, long timestamp, int nonce, String msgEncrypt) {
          String[] arr = {clientId, String.valueOf(timestamp), String.valueOf(nonce), msgEncrypt};
          Arrays.sort(arr);
          String sortedStr = String.join("", arr);
          return sha1(sortedStr);
      }

      // SHA-1 hash function
      private static String sha1(String input) {
          try {
              MessageDigest md = MessageDigest.getInstance("SHA-1");
              byte[] hashBytes = md.digest(input.getBytes());
              StringBuilder hexString = new StringBuilder();
              for (byte b : hashBytes) {
                  String hex = Integer.toHexString(0xff & b);
                  if (hex.length() == 1) hexString.append('0');
                  hexString.append(hex);
              }
              return hexString.toString();
          } catch (Exception e) {
              e.printStackTrace();
              return null;
          }
      }

      // Decryption algorithm
      public static String generateAesDecrypt(String dataEncrypt, String clientId, String clientSecret) {
          try {
              byte[] keyBytes = clientSecret.getBytes();
              byte[] ivBytes = clientId.getBytes();

              SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
              IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);

              Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
              cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);

              byte[] encryptedBytes = Base64.getDecoder().decode(dataEncrypt);
              byte[] decryptedBytes = cipher.doFinal(encryptedBytes);

              return new String(decryptedBytes);
          } catch (Exception e) {
              e.printStackTrace();
              return null;
          }
      }

      // Example usage
      public static void main(String[] args) {
          String clientId = "AKDt8rWEczpYPzCGur2xE=";
          String clientSecret = "nmwUjMAK0PJpl0MOiXLOOOwZADm0gkLo";
          String signature = "04e30dd43d9d8f95dd7c127dad617f0929d61c1d";
          String msgEncrypt = "LuG1OVSVIwOO/xpW00eSYo77Ncxa9h4VKmOJRjwoyoAmCIS/8FdJRJ+BpZn90BVAAg8xpU1bMmcDlAYDT010Wa9tNi1jivX25Ld03iA4EKs=";
          long timestamp = 1710757981609L;
          int nonce = 1529;

          String newSignature = generateMsgSignature(clientId, timestamp, nonce, msgEncrypt);
          if (signature.equals(newSignature)) {
              String result = generateAesDecrypt(msgEncrypt, clientId, clientSecret);
              // Handle your own business logic
              System.out.println("Decrypted Data: " + result);
              // must be Return success http satusCode 200
          } else {
              // must be Return error http satusCode 400
          }
      }
  }

  ```
</CodeGroup>
