Webhook Security - Signature Key

Real-time event notifications for your application

To ensure authenticity and integrity of webhook requests, we include a digital signature using the HMAC-SHA256 algorithm. This signature is sent in the request header as x-signature.

This ensures:

  • The payload was not modified
  • The request came from our API
  • Protection against man-in-the-middle attacks
  • 1Sample Payload & Headers

    Sample Webhook Payload:

    json
    {
      "transactionId": "trx_123",
      "externalId": "ext_456",
      "payerDocument": "12345678900",
      "payerFullName": "João da Silva",
      "endToEnd": "E123456789123456789",
      "status": "APPROVED",
      "amount": 5000,
      "type": "TRANSACTION"
    }

    Request Headers:

    x-signature: e1a95db39ef6a1a8f3f35f33e63b527a16f4f2c...
    Content-Type: application/json

    2Signature Validation

    You must validate that the x-signature received matches the HMAC signature generated locally using the raw JSON payload and your secretKey.

    Important Notes:

  • The JSON must be serialized exactly as it was when the signature was created
  • Object keys must be sorted alphabetically
  • If the payload includes a signature field, remove it before verifying
  • Use the same secret key provided during webhook setup
  • 3Basic TypeScript Example

    typescript
    import * as crypto from 'crypto';
    
    function sortObjectKeys(obj: any): any {
      if (obj === null || typeof obj !== 'object' || obj instanceof Date) {
        return obj;
      }
    
      if (Array.isArray(obj)) {
        return obj.map((item) => sortObjectKeys(item));
      }
    
      const sortedObj: any = {};
      Object.keys(obj)
        .sort()
        .forEach((key) => {
          sortedObj[key] = sortObjectKeys(obj[key]);
        });
    
      return sortedObj;
    }
    
    export function verifySignature(
      payload: any,
      receivedSignature: string,
      secret: string
    ): boolean {
      const sortedPayload = sortObjectKeys(payload);
      const payloadString = JSON.stringify(sortedPayload);
    
      const calculatedSignature = crypto
        .createHmac("sha256", secret)
        .update(payloadString)
        .digest("hex");
    
      return calculatedSignature === receivedSignature;
    }

    4Full NestJS Example

    typescript
    import {
      Controller,
      Post,
      Req,
      Headers,
      UnauthorizedException,
    } from '@nestjs/common';
    import { Request } from 'express';
    import { verifySignature } from './utils/verifySignature';
    
    @Controller()
    export class WebhookController {
      @Post('/webhook')
      async handleWebhook(
        @Req() req: Request,
        @Headers('x-signature') signature: string,
      ) {
        const secret = 'YOUR_SECRET_KEY_HERE';
        const payload = req.body;
    
        const isValid = verifySignature(payload, signature, secret);
    
        if (!isValid) {
          throw new UnauthorizedException('Invalid signature');
        }
    
        // ✅ Signature is valid. Process the webhook
        console.log('Received valid webhook:', payload);
    
        // Process your business logic here
    
        return { status: 'success' };
      }
    }

    5Security Best Practices

    Keep your secret key safe:

  • Never expose your secretKey in client-side code
  • Store it securely in environment variables
  • Rotate the key periodically
  • Always verify the signature:

  • Reject any webhook request with invalid signature
  • Log failed signature attempts for security monitoring
  • Implement rate limiting to prevent brute force attacks
  • Handle webhooks securely:

  • Process webhooks asynchronously to avoid blocking
  • Implement idempotency to handle duplicate webhooks
  • Return HTTP 200 only after successful signature validation
  • Store webhook events for audit and debugging purposes
  • Security First

    Always validate webhook signatures to ensure authenticity and prevent security vulnerabilities.

    Need more help?

    Check our complete API reference or contact our support team for assistance.