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

# Introduction

# Webhooks Introduction

Webhooks enable your application to receive instant notifications about important events, making it easy to automate workflows and keep external systems in sync with Carbon's API.

## What Are Webhooks?

Webhooks are HTTP callbacks triggered by specific events in your Carbon account. When an event occurs, Carbon sends a POST request to your configured webhook URL, allowing your server to process the event in real time.

## How Webhooks Work

<Steps>
  <Step title="Configure Your Webhook URL">
    Set your webhook endpoint using the Carbon Business dashboard. Make sure your server is ready to accept POST requests.
  </Step>

  <Step title="Event Triggered">
    When a relevant event occurs (e.g., a transaction is completed), Carbon automatically sends a POST request to your webhook URL with event details.
  </Step>

  <Step title="Acknowledge Receipt">
    Your server should respond with a 2xx status code to confirm successful receipt. If not, Carbon may retry delivery.
  </Step>
</Steps>

## Key Features

<AccordionGroup>
  <Accordion title="Real-time Notifications">
    Receive immediate updates for events such as transactions, account changes, and more.
  </Accordion>

  <Accordion title="Customizable">
    Easily update your webhook URL or select which events you want to subscribe to.
  </Accordion>

  <Accordion title="Secure Delivery">
    Each webhook request includes a HMAC-SHA256 signature in the `X-Carbon-Baas-Signature` header for verification. The signature is calculated by JSON-encoding the payload and hashing it with your secret key. Always validate the signature to ensure authenticity and prevent tampering.
  </Accordion>
</AccordionGroup>

## Example Webhook Events

Some common events you can subscribe to:

**Account events:**

* `account.incoming-transaction`
* `account.outgoing-transaction`

**Loan events:**

* `loan.application.received`
* `loan.offer.generated`
* `loan.offer.accepted`
* `loan.disbursed`
* `loan.repayment.successful`
* `loan.closed`

For a full list and details, see the [Webhook Events](/webhooks/events) documentation.

## Best Practices

<AccordionGroup>
  <Accordion title="Validate Webhook Signatures">
    <Info>
      Always verify the signature included in webhook requests to confirm they originate from Carbon.
    </Info>

    ### How Signature Verification Works

    Carbon signs each webhook with HMAC-SHA256 using your webhook secret and sends the signature in the `X-Carbon-Baas-Signature` header.

    **Signature Generation:**

    1. JSON-encode the webhook payload
    2. Create HMAC-SHA256 hash using your secret key
    3. The result is sent in the `X-Carbon-Baas-Signature` header

    ### Finding Your Webhook Secret

    Your webhook secret can be found in your Carbon dashboard on the **Developer** page.

    ### Implementation Examples

    <CodeGroup>
      ```php PHP theme={null}
      <?php

      function verifyWebhookSignature($payload, $signature, $secret) {
          $expectedSignature = hash_hmac('sha256', $payload, $secret);
          return hash_equals($expectedSignature, $signature);
      }

      // Usage
      $payload = file_get_contents('php://input');
      $signature = $_SERVER['HTTP_X_CARBON_BAAS_SIGNATURE'];
      $secret = 'your-webhook-secret-from-dashboard';

      if (!verifyWebhookSignature($payload, $signature, $secret)) {
          http_response_code(401);
          exit('Invalid signature');
      }

      $data = json_decode($payload, true);
      // Process webhook data...
      ```

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

      function verifyWebhookSignature(payload, signature, secret) {
          const expectedSignature = crypto
              .createHmac('sha256', secret)
              .update(payload, 'utf8')
              .digest('hex');
          
          return crypto.timingSafeEqual(
              Buffer.from(signature, 'hex'),
              Buffer.from(expectedSignature, 'hex')
          );
      }

      // Express.js example
      app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => {
          const signature = req.headers['x-carbon-baas-signature'];
          const secret = process.env.CARBON_WEBHOOK_SECRET;
          
          if (!verifyWebhookSignature(req.body, signature, secret)) {
              return res.status(401).send('Invalid signature');
          }
          
          const data = JSON.parse(req.body);
          // Process webhook data...
          res.status(200).send('OK');
      });
      ```

      ```python Python theme={null}
      import hmac
      import hashlib
      import json

      def verify_webhook_signature(payload, signature, secret):
          expected_signature = hmac.new(
              secret.encode('utf-8'),
              payload.encode('utf-8'),
              hashlib.sha256
          ).hexdigest()
          
          return hmac.compare_digest(expected_signature, signature)

      # Flask example
      from flask import Flask, request

      @app.route('/webhook', methods=['POST'])
      def webhook():
          payload = request.get_data(as_text=True)
          signature = request.headers.get('X-Carbon-Baas-Signature')
          secret = os.environ.get('CARBON_WEBHOOK_SECRET')
          
          if not verify_webhook_signature(payload, signature, secret):
              return 'Invalid signature', 401
          
          data = json.loads(payload)
          # Process webhook data...
          return 'OK', 200
      ```

      ```ruby Ruby theme={null}
      require 'openssl'
      require 'json'

      def verify_webhook_signature(payload, signature, secret)
        expected_signature = OpenSSL::HMAC.hexdigest('sha256', secret, payload)
        Rack::Utils.secure_compare(expected_signature, signature)
      end

      # Sinatra example
      post '/webhook' do
        payload = request.body.read
        signature = request.env['HTTP_X_CARBON_BAAS_SIGNATURE']
        secret = ENV['CARBON_WEBHOOK_SECRET']
        
        unless verify_webhook_signature(payload, signature, secret)
          halt 401, 'Invalid signature'
        end
        
        data = JSON.parse(payload)
        # Process webhook data...
        status 200
      end
      ```
    </CodeGroup>

    ### Security Best Practices

    * **Use constant-time comparison**: Always use `hash_equals()` (PHP), `crypto.timingSafeEqual()` (Node.js), `hmac.compare_digest()` (Python), or equivalent functions to prevent timing attacks
    * **Validate before processing**: Never process webhook data before verifying the signature
    * **Keep secrets secure**: Store your webhook secret as an environment variable, never in your codebase
    * **Use HTTPS**: Always use HTTPS endpoints to protect data in transit
  </Accordion>

  <Accordion title="Handle Retries Gracefully">
    <Note>
      If your server does not respond with a 2xx status code, Carbon will retry delivery up to 3 times. Ensure your endpoint can handle duplicate events safely.
    </Note>

    ### Manual Resend Options

    If automatic retries fail, you can manually resend webhook events:

    * **Dashboard**: Navigate to the **Nexus** menu in your Carbon dashboard to resend failed webhooks
    * **API**: Use the [Resend Webhook Event](/api-reference/webhooks/resend-webhook-event) API endpoint for programmatic resending

    This gives you full control over webhook delivery and allows you to retry specific events as needed.
  </Accordion>

  <Accordion title="Monitor and Log Events">
    <Info>
      Set up logging and monitoring for your webhook endpoint to track received events and troubleshoot issues quickly.
    </Info>
  </Accordion>
</AccordionGroup>

## Troubleshooting & Support

If you experience issues with webhook delivery or event processing, check your server logs and ensure your endpoint is publicly accessible. For further assistance, refer to the [Error Handling](/error) documentation or contact Carbon support.
