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

# Signature Verification

> Create webhook subscriptions through the dashboard or through the API

For each event delivery, Paylias will include a webhook signature header in the HTTP request for event authenticity verification provided that your webhook subscription has been setup with a shared secret key. The signature will be available in the headers under the key `X-PAYLIAS-SIGNATURE`.

Paylias uses the entire [Event](/concepts/webhooks/event-structure#event-definition) to generate signature. The payload is first marshaled to its raw JSON bytes, then an HMAC is computed over those bytes using SHA‑512 with your secret as the key, and finally the resulting digest is encoded as a hexadecimal string.

## Sample Code

Please review the sample code below carefully to ensure your verification code aligns with it and passes the signature example provided below.

<Warning>The following code samples were generated with the help of AI. Please verify them before using them in production.</Warning>

<CodeGroup>
  ```go verification.go theme={null}
  package webhook

  import (
    "crypto/hmac"
    "crypto/sha512"
    "encoding/hex"
  )

  // VerifyPayloadSignature returns true if `signature` matches the HMAC‑SHA512 of `payload` using `secret`.
  func VerifyPayloadSignature(secret string, payload []byte, signature string) bool {
    mac := hmac.New(sha512.New, []byte(secret))
    mac.Write(payload)
    expected := hex.EncodeToString(mac.Sum(nil))
    // hmac.Equal is timing‑safe
    return hmac.Equal([]byte(expected), []byte(signature))
  }
  ```

  ```javascript verification.js theme={null}
  const crypto = require('crypto');

  /**
   * @param {string} secret      The HMAC secret
   * @param {Buffer|string} payload  The raw JSON payload
   * @param {string} signature   Hex‑encoded HMAC to verify
   * @returns {boolean}
   */
  function verifyPayloadSignature(secret, payload, signature) {
    const expected = crypto
      .createHmac('sha512', secret)
      .update(payload)
      .digest('hex');

    const sigBuf      = Buffer.from(signature, 'hex');
    const expectedBuf = Buffer.from(expected, 'hex');
    if (sigBuf.length !== expectedBuf.length) return false;
    return crypto.timingSafeEqual(sigBuf, expectedBuf);
  }

  module.exports = { verifyPayloadSignature };
  ```

  ```java verification.java theme={null}
  import javax.crypto.Mac;
  import javax.crypto.spec.SecretKeySpec;
  import java.nio.charset.StandardCharsets;
  import java.security.MessageDigest;

  public class WebhookVerifier {
      /**
       * Verify signature using HMAC‑SHA512.
       *
       * @param secret    The HMAC secret
       * @param payload   Raw JSON bytes
       * @param signature Hex‑encoded HMAC string to verify
       * @return true if signature is valid
       */
      public static boolean verifySignature(String secret, byte[] payload, String signature) throws Exception {
          Mac mac = Mac.getInstance("HmacSHA512");
          SecretKeySpec key = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA512");
          mac.init(key);
          byte[] rawHmac = mac.doFinal(payload);
          String expected = bytesToHex(rawHmac);

          byte[] sigBytes      = signature.getBytes(StandardCharsets.UTF_8);
          byte[] expectedBytes = expected.getBytes(StandardCharsets.UTF_8);
          // constant‑time comparison
          return MessageDigest.isEqual(expectedBytes, sigBytes);
      }

      private static String bytesToHex(byte[] bytes) {
          StringBuilder sb = new StringBuilder(bytes.length * 2);
          for (byte b : bytes) {
              sb.append(String.format("%02x", b & 0xff));
          }
          return sb.toString();
      }
  }
  ```

  ```ruby verification.rb theme={null}
  require 'openssl'
  require 'rack/utils'  # for secure_compare

  # @param secret    [String] HMAC secret
  # @param payload   [String] raw JSON payload
  # @param signature [String] hex‑encoded HMAC to verify
  # @return [Boolean]
  def verify_payload_signature(secret, payload, signature)
    expected = OpenSSL::HMAC.hexdigest('sha512', secret, payload)
    return false unless expected.bytesize == signature.bytesize
    Rack::Utils.secure_compare(expected, signature)
  end
  ```
</CodeGroup>
