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

# Quick Integration Guide

#### ✅ Step 1: Add Webhook URL to Your Payment Link

When creating a Payment Link:

* Go to **Step 3: Advanced >> Select Webhook**
* Paste your backend URL (e.g., `https://yourdomain.com/webhook`)
* Choose which events you want to receive

#### ✅ Step 2: Verify Signature of Incoming Webhook Request

When a payment occurred, Paymento sends a `POST` request to your endpoint with:

* `Content-Type: application/json`
* `x-signature: <HMAC signature>`

To secure your endpoint:

* Get your `webhook secretkey` from Paymento settings
* Generate HMAC-SHA256 hash of the raw body
* Compare it to the `x-signature` header

**Node.js Example:**

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

const signature = req.headers['x-paymento-signature'];
const secretKey = 'YOUR_MERCHANT_SECRET_KEY'; // From Paymento dashboard

const computed = crypto
  .createHmac('sha256', secretKey)
  .update(req.rawBody)
  .digest('hex');

if (signature !== computed) {
  return res.status(401).send('Invalid signature');
}
```

#### ✅ Step 3: Handle Events

#### Use Events to Automate Logic

Example use cases:

* `payment_link.paid`: Subscribe user to your service
* `subscription.renewed`: Extend subscription
* `subscription.grace_expired`: Revoke access
* `payment_link.failed`: Alert user or retry flow

**Node.js Example:**

```javascript
const event = req.body;

switch (event.event.type) {
  case 'payment_link.paid':
    // Customer paid successfully
    activateSubscription(event.customer.email);
    break;
    
  case 'payment_link.deferred':
    // Payment was not made on time
    suspendSubscription(event.customer.email);
    break;
}

res.status(200).json({ received: true });
```

### Checklist ✅

Before going live, Make sure:

* [ ] &#x20;Endpoint uses HTTPS
* [ ] &#x20;Signature verification implemented
* [ ] &#x20;Returns 200 OK within 5 seconds
* [ ] &#x20;Handles idempotency (checks `event.id`)
* [ ] &#x20;Logs all webhook requests
* [ ] &#x20;Secret key stored securely (environment variable)
* [ ] &#x20;Error handling implemented
* [ ] &#x20;Tested with Paymento test webhook feature<br>

#### Headers Reference

```http
X-Paymento-Signature: <hmac-sha256-hex>
X-Paymento-Timestamp: <unix-timestamp>
X-Paymento-Event-Id: evt_<unique-id>
X-Paymento-Event-Type: payment_link.paid
```

### Body Structure

```json
{
  "event": {
    "id": "evt_...",
    "type": "payment_link.paid | payment_link.deferred",
    "createdAt": "ISO-8601",
    "apiVersion": "v1"
  },
  "paymentLink": {
    "id": "pl_...",
    "title": "string",
    "description": "string",
    "status": "paid | deferred",
    "type": "one_time | scheduled",
    "createdAt": "ISO-8601",
    "paidAt": "ISO-8601 | null",
    "url": "string"
  },
  "customer": {
    "email": "string",
    "name": "string",
    "metadata": {
      "order_id": "string?",
      "payment_id": "string?"
    }
  },
  "merchant": {
    "id": "string",
    "name": "string"
  }
}
```

#### 🔍 Available Events

| Event                        | Description                       |
| ---------------------------- | --------------------------------- |
| `payment_link.paid`          | Payment completed                 |
| `payment_link.failed`        | Payment failed                    |
| `payment_link.expired`       | Link expired without payment      |
| `subscription.renewed`       | Subscription renewed by user      |
| `subscription.reminder_sent` | Reminder sent (email or Telegram) |
| `subscription.grace_expired` | User did not pay, grace ended     |

### Signature Verification (Code Samples)

#### Node.js

```javascript
const crypto = require('crypto');
const signature = crypto
  .createHmac('sha256', secretKey)
  .update(rawBody)
  .digest('hex');
```

#### Python

```python
import hmac
import hashlib
signature = hmac.new(
    secret_key.encode('utf-8'),
    raw_body.encode('utf-8'),
    hashlib.sha256
).hexdigest()
```

#### PHP

```php
$signature = hash_hmac('sha256', $rawBody, $secretKey);
```

#### C\#

```csharp
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secretKey));
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(rawBody));
var signature = BitConverter.ToString(hash).Replace("-", "").ToLower();
```

#### Ruby

```ruby
require 'openssl'
signature = OpenSSL::HMAC.hexdigest('sha256', secret_key, raw_body)
```

#### Go

```go
import "crypto/hmac"
import "crypto/sha256"
import "encoding/hex"

mac := hmac.New(sha256.New, []byte(secretKey))
mac.Write([]byte(rawBody))
signature := hex.EncodeToString(mac.Sum(nil))
```

#### Java

```java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Hex;

Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256");
mac.init(secretKeySpec);
byte[] hash = mac.doFinal(rawBody.getBytes());
String signature = Hex.encodeHexString(hash);
```
