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

# Webhooks

> Set up real-time payment notifications

## Overview

Webhooks allow you to receive real-time notifications when payment events occur. This is essential for updating your application's state when payments are completed, expired, or fail.

## Supported Events

<Columns cols={2}>
  <Card title="Payment Completed" icon="check-circle">
    Triggered when a payment is successfully completed and confirmed on the blockchain.
  </Card>

  <Card title="Payment Expired" icon="clock">
    Triggered when a payment expires without being completed.
  </Card>
</Columns>

## Setting Up Webhooks

### Step 1: Configure Webhook URL

Set your webhook URL in the merchant dashboard or when creating payments:

```json theme={null}
{
  "webhookUrl": "https://yoursite.com/webhook"
}
```

### Step 2: Create Webhook Endpoint

Create an endpoint in your application to receive webhook notifications:

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

app.post('/webhook', (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const payload = JSON.stringify(req.body);
  
  // Verify webhook signature
  const expectedSignature = crypto
    .createHmac('sha256', process.env.WEBHOOK_SECRET)
    .update(payload)
    .digest('hex');
  
  if (signature !== expectedSignature) {
    return res.status(400).send('Invalid signature');
  }
  
  // Handle the event
  handleWebhookEvent(req.body);
  
  res.status(200).send('OK');
});
```

### Step 3: Handle Events

Process different webhook events in your application:

```javascript theme={null}
function handleWebhookEvent(event) {
  switch (event.event) {
    case 'payment.completed':
      console.log('Payment completed:', event.payment.id);
      // Update order status, send confirmation email, etc.
      break;
      
    case 'payment.expired':
      console.log('Payment expired:', event.payment.id);
      // Handle expired payment, maybe retry or cancel order
      break;
      
    default:
      console.log('Unknown event:', event.event);
  }
}
```

## Webhook Payloads

### Payment Completed

```json theme={null}
{
  "event": "payment.completed",
  "payment": {
    "id": "pay_abc123def456",
    "status": "completed",
    "amountCrypto": "0.00012345",
    "crypto": "BTC",
    "address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
    "incomingTxHash": "abc123...",
    "completedAt": "2024-01-01T00:30:00Z",
    "customerId": "cus_V6n6SN2KnsIFCuQU",
    "orderId": "order_123",
    "metadata": {
      "description": "Premium subscription"
    },
    "customFields": {
      "customer_name": "John Doe"
    }
  },
  "timestamp": "2024-01-01T00:30:00Z"
}
```

### Payment Expired

```json theme={null}
{
  "event": "payment.expired",
  "payment": {
    "id": "pay_abc123def456",
    "status": "expired",
    "expiresAt": "2024-01-01T01:00:00Z"
  },
  "timestamp": "2024-01-01T01:00:00Z"
}
```

## Webhook Verification

All webhooks are signed using HMAC-SHA256 to ensure they come from Transaction API.

### Verification Process

<Steps>
  <Step title="Get Webhook Secret">
    Find your webhook secret in the merchant dashboard.
  </Step>

  <Step title="Create HMAC Hash">
    Create HMAC-SHA256 hash of the request body using your secret.
  </Step>

  <Step title="Compare Signatures">
    Compare the computed hash with the `X-Webhook-Signature` header.
  </Step>
</Steps>

### Example Implementation

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

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

// Usage
const isValid = verifyWebhook(
  JSON.stringify(req.body),
  req.headers['x-webhook-signature'],
  process.env.WEBHOOK_SECRET
);
```

## Webhook Retries

Transaction API will retry failed webhook deliveries:

* **Retry Schedule:** 1, 5, 15, 30, 60 minutes
* **Max Retries:** 5 attempts
* **Timeout:** 30 seconds per attempt
* **Success Response:** HTTP 200 status code

<Warning>
  Always respond with HTTP 200 to successful webhook processing to prevent retries.
</Warning>

## Testing Webhooks

### Using ngrok for Local Development

```bash theme={null}
# Install ngrok
npm install -g ngrok

# Expose local server
ngrok http 3000

# Use the HTTPS URL for webhook testing
# Example: https://abc123.ngrok.io/webhook
```

### Webhook Logs

Monitor webhook delivery in your dashboard:

1. Go to **Webhook Logs** in your merchant dashboard
2. View delivery status and response codes
3. Debug failed deliveries with request/response details

## Best Practices

<Steps>
  <Step title="Verify Signatures">
    Always verify webhook signatures to ensure authenticity.
  </Step>

  <Step title="Handle Duplicates">
    Implement idempotency to handle duplicate webhook deliveries.
  </Step>

  <Step title="Respond Quickly">
    Process webhooks asynchronously to avoid timeouts.
  </Step>

  <Step title="Log Everything">
    Log all webhook events for debugging and auditing.
  </Step>
</Steps>

## Common Issues

<AccordionGroup>
  <Accordion title="Webhook Not Receiving">
    * Check if your endpoint is accessible from the internet
    * Verify the webhook URL is correct
    * Ensure your server is running and responding
  </Accordion>

  <Accordion title="Signature Verification Failing">
    * Ensure you're using the correct webhook secret
    * Check that you're hashing the raw request body
    * Verify the signature header format
  </Accordion>

  <Accordion title="Duplicate Events">
    * Implement idempotency using payment IDs
    * Store processed event IDs to prevent reprocessing
  </Accordion>
</AccordionGroup>
