> For the complete documentation index, see [llms.txt](https://docs.useglyde.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.useglyde.io/webhooks.md).

# Webhooks

Webhooks are a great way for Glyde to keep your application informed of changes in your account and transaction status updates.

When a transaction is initiated, it progresses through various stages, from pending to either successful or failed. At each stage, we will send a notification to the webhook URL registered in your merchant account.

### Webhook Setup

Log into your account and go to Settings > API Keys & Webhook. From there, update your webhook URL.

#### Webhook URL

The webhook URL is a publicly accessible endpoint on your application/website that can receive a post request from Glyde. We will send updates about transactions to the endpoint.

#### Signing Key

The webhook will be signed using the secret key, a secure, randomly generated string. This ensures that the request originates from Glyde. The signing key will be included in the webhook request header X-Signature-Hash when sending data to your webhook URL.

**Signature Validation**

{% tabs %}
{% tab title="PHP" %}

```php
<?php

if (strtoupper($_SERVER['REQUEST_METHOD']) != 'POST' || !in_array('HTTP_X_SIGNATURE_HASH', $_SERVER)) {
  exit();
}

// Get the input from the request.
$input = @file_get_contents("php://input");

// Replace SIGNING_KEY with the signing key from your account
define('GLYDE_SIGNING_KEY', 'SIGNING_KEY');

// Validate the authenticity of the data sent
if ($_SERVER['HTTP_X_SIGNATURE_HASH'] !== hash_hmac('sha256', $input, GLYDE_SIGNING_KEY)) {
  exit();
}

// Send an HTTP success response back to Glyde

http_response_code(200);

//Decode the JSON string and convert it to an associative array.
$event = json_decode($input, true);

// **(Optional Processing Placeholder):**
// Add your code here to process the data in the $event variable

exit();

```

{% endtab %}

{% tab title="Python" %}

```python
import http.server
import hashlib
import json

class GlydeWebhookHandler(http.server.BaseHTTPRequestHandler):
    def do_POST(self):
        if self.path != '/':
            self.send_response(404)
            self.end_headers()
            return

        if 'x-signature-hash' not in self.headers:
            self.send_response(400)
            self.end_headers()
            self.wfile.write(b'Invalid request missing signature header.')
            return

        input_data = self.rfile.read(int(self.headers['Content-Length']))

        if not input_data:
            self.send_response(400)
            self.end_headers()
            self.wfile.write(b'Failed to read request body.')
            return

        # Replace 'SIGNING_KEY' with the actual signing key provided by Glyde
        GLYDE_SIGNING_KEY = b'SIGNING_KEY'

        # Validate the authenticity of the data sent
        if self.headers['x-signature-hash'].encode() != hashlib.sha256(input_data + GLYDE_SIGNING_KEY).hexdigest().encode():
            self.send_response(401)
            self.end_headers()
            self.wfile.write(b'Invalid signature.')
            return

        # Decode the JSON data
        try:
            event = json.loads(input_data.decode())
        except ValueError:
            self.send_response(400)
            self.end_headers()
            self.wfile.write(b'Invalid JSON format in request body.')
            return

        # Optional processing logic
        # Add your code here to process the event data

        self.send_response(200)
        self.end_headers()

if __name__ == '__main__':
    server_address = ('', 8000)
    httpd = http.server.HTTPServer(server_address, GlydeWebhookHandler)
    print('Server running on port 8000...')
    httpd.serve_forever()

```

{% endtab %}

{% tab title="NodeJs" %}

```javascript
const crypto = require('crypto');
const http = require('http');

const PORT = process.env.PORT || 3000; // Use environment variable for port or default to 3000
const GLYDE_SIGNING_KEY = 'YOUR_SIGNING_KEY'; // Replace with your actual signing key

const server = http.createServer((req, res) => {
  if (req.method !== 'POST' || !req.headers['http-x-signature-hash']) {
    res.statusCode = 400;
    res.end('Invalid request method or missing signature header.');
    return;
  }

  let inputData = '';
  req.on('data', (chunk) => {
    inputData += chunk.toString();
  });

  req.on('end', () => {
    const signature = req.headers['http-x-signature-hash'];
    const calculatedHash = crypto.createHmac('sha256', GLYDE_SIGNING_KEY)
      .update(inputData)
      .digest('hex');

    if (signature !== calculatedHash) {
      res.statusCode = 401;
      res.end('Invalid signature.');
      return;
    }

    res.statusCode = 200;
    res.end();

    // Parse JSON data (assuming it's in the request body)
    try {
      const event = JSON.parse(inputData);
      // Process the data in the 'event' object here
      console.log('Received event:', event);
    } catch (error) {
      console.error('Error parsing JSON:', error.message);
      // Handle JSON parsing error appropriately (e.g., send error response)
    }
  });
});

server.listen(PORT, () => {
  console.log(`Server listening on port ${PORT}`);
});

```

{% endtab %}
{% endtabs %}

**Event Types**

{% tabs %}
{% tab title="Transfer Success" %}

```json
{
  "event": "transfer.successful",
  "data": {
    "reference": "fa59e3c4-14b6-370e-ab0c-a8eaa7af2056",
    "merchant_reference": "fa6ba254-ba5c-4db2-9015-8caf3107cd56",
    "type": "debit",
    "amount": 200,
    "status": "successful",
    "fee": 20,
    "created_at": "2025-03-01T21:20:54.000000Z"
  }
}
```

{% endtab %}

{% tab title="Transfer Failed" %}

```json
{
  "event": "transfer.failed",
  "data": {
    "reference": "fa59e3c4-14b6-370e-cb0c-a8eaa7af2056",
    "merchant_reference": "fa9ba254-ha5c-4db2-9015-8caf3107cd56",
    "type": "debit",
    "amount": 200,
    "status": "failed",
    "fee": 20,
    "created_at": "2025-03-01T21:10:54.000000Z"
  }
}
```

{% endtab %}
{% endtabs %}
