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

# Webhook Setup

> Configure and troubleshoot your webhook endpoints

This guide walks you through setting up webhooks in your Quickbutik store and configuring your application to receive and process webhook events reliably.

## Configuration in Quickbutik

<Steps>
  <Step title="Access webhook settings">
    Log into your Quickbutik Control Panel and navigate to **Settings → Webhooks**
  </Step>

  <Step title="Add webhook URL">
    Enter your webhook endpoint URL where you want to receive notifications:

    ```
    https://your-domain.com/webhooks/quickbutik
    ```

    <Note>
      Your webhook URL must be publicly accessible and respond to GET requests. Use HTTPS in production for security.
    </Note>
  </Step>

  <Step title="Select events">
    Choose which events should trigger webhook notifications:

    * **Order events**: `order.new`, `order.done`, `order.cancelled`
    * **Product events**: `product.add`, `product.update`, `product.delete`
  </Step>

  <Step title="Test your webhook">
    Use the test function in the Quickbutik panel to verify your endpoint is working correctly
  </Step>
</Steps>

## Development Setup

For local development, use a tool like ngrok to expose your local server:

<CodeGroup>
  ```bash Terminal theme={null}
  # Install ngrok
  npm install -g ngrok

  # Start your local webhook server
  node webhook-server.js

  # In another terminal, expose your local server
  ngrok http 3000

  # Copy the ngrok URL to your Quickbutik webhook settings
  # Example: https://abc123.ngrok.io/webhooks/quickbutik
  ```

  ```javascript Local Server theme={null}
  const express = require('express');
  const app = express();

  app.get('/webhooks/quickbutik', (req, res) => {
    console.log('Webhook received:', {
      event_type: req.query.event_type,
      order_id: req.query.order_id,
      product_id: req.query.product_id,
      timestamp: new Date().toISOString(),
      ip: req.ip,
      headers: req.headers
    });
    
    res.status(200).send('OK');
  });

  app.listen(3000, () => {
    console.log('Webhook server listening on port 3000');
  });
  ```
</CodeGroup>

## Production Deployment

For production environments, ensure your webhook endpoint is robust and scalable:

<CodeGroup>
  ```javascript Production Webhook theme={null}
  const express = require('express');
  const rateLimit = require('express-rate-limit');
  const helmet = require('helmet');

  const app = express();

  // Security middleware
  app.use(helmet());

  // Rate limiting
  const webhookLimiter = rateLimit({
    windowMs: 1 * 60 * 1000, // 1 minute
    max: 100, // limit each IP to 100 requests per windowMs
    message: 'Too many webhook requests from this IP',
    standardHeaders: true,
    legacyHeaders: false,
  });

  app.use('/webhooks', webhookLimiter);

  // Health check endpoint
  app.get('/health', (req, res) => {
    res.status(200).json({
      status: 'healthy',
      timestamp: new Date().toISOString()
    });
  });

  // Webhook endpoint
  app.get('/webhooks/quickbutik', async (req, res) => {
    const { event_type, order_id, product_id } = req.query;
    
    // Log webhook receipt
    console.log(`Webhook received: ${event_type}`, {
      order_id,
      product_id,
      timestamp: new Date().toISOString(),
      ip: req.ip
    });
    
    // Respond immediately
    res.status(200).send('OK');
    
    try {
      // Add to processing queue
      await addToQueue({
        event_type,
        order_id,
        product_id,
        received_at: new Date().toISOString()
      });
    } catch (error) {
      console.error('Failed to queue webhook:', error);
      
      // Send alert but don't fail the webhook response
      await sendAlert({
        type: 'webhook_queue_error',
        event_type,
        error: error.message
      });
    }
  });

  async function addToQueue(webhookData) {
    // Add to Redis queue, SQS, or your preferred queue system
    // This ensures webhook processing doesn't block the response
    
    if (process.env.REDIS_URL) {
      const redis = require('redis');
      const client = redis.createClient({ url: process.env.REDIS_URL });
      await client.lPush('webhook_queue', JSON.stringify(webhookData));
    }
  }

  const PORT = process.env.PORT || 3000;
  app.listen(PORT, () => {
    console.log(`Webhook server running on port ${PORT}`);
  });
  ```

  ```dockerfile Dockerfile theme={null}
  FROM node:18-alpine

  WORKDIR /app

  # Install dependencies
  COPY package*.json ./
  RUN npm ci --only=production

  # Copy application
  COPY . .

  # Create non-root user
  RUN addgroup -g 1001 -S webhook
  RUN adduser -S webhook -u 1001

  # Security
  RUN chown -R webhook:webhook /app
  USER webhook

  # Health check
  HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:3000/health || exit 1

  EXPOSE 3000

  CMD ["node", "webhook-server.js"]
  ```
</CodeGroup>

## Troubleshooting

### Common Issues

<AccordionGroup>
  <Accordion title="Webhook not receiving events">
    **Possible causes:**

    * Webhook URL is not publicly accessible
    * Firewall blocking incoming requests
    * Server not running or crashed
    * Wrong endpoint path configured

    **Solutions:**

    * Test your endpoint with curl: `curl "https://your-domain.com/webhooks/quickbutik?event_type=test"`
    * Check server logs for errors
    * Verify webhook URL in Quickbutik settings
    * Use tools like ngrok for local testing
  </Accordion>

  <Accordion title="Getting timeout errors">
    **Possible causes:**

    * Webhook handler takes too long to respond
    * Processing heavy operations synchronously
    * Database or external API calls blocking response

    **Solutions:**

    * Always respond with 200 OK immediately
    * Process webhook data asynchronously
    * Use queue systems for heavy processing
    * Implement timeout handling
  </Accordion>

  <Accordion title="Receiving duplicate events">
    **Possible causes:**

    * Webhook endpoint responding slowly or with errors
    * Network issues causing retries
    * Processing failures triggering redelivery

    **Solutions:**

    * Implement idempotent processing
    * Store processed webhook IDs to prevent duplicates
    * Respond quickly with 200 OK
    * Use database transactions for atomic operations
  </Accordion>

  <Accordion title="Missing webhook events">
    **Possible causes:**

    * Endpoint was down during event
    * Processing errors causing webhook to be marked as failed
    * Rate limiting rejecting webhooks

    **Solutions:**

    * Implement reliable webhook processing with retries
    * Monitor webhook endpoint uptime
    * Use dead letter queues for failed webhooks
    * Regularly poll API for missed events as backup
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Event Types" icon="list" href="/webhooks/events">
    Explore all available webhook events and their data
  </Card>
</CardGroup>
