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

# Receptores de webhooks

> Recibe webhooks de Rhombus en servidores privados detrás de firewalls usando túneles SSH inversos, ngrok o un proxy inverso, sin necesidad de una IP pública ni reenvío de puertos.

<Note>
  Esta página fue traducida automáticamente. Si encuentra errores o tiene sugerencias, [contáctenos](mailto:support@rhombus.com).
</Note>

<Info>
  **Problema que resuelve**

  Esta guía te muestra cómo recibir **webhooks de Rhombus** en servidores detrás de firewalls o NAT sin necesidad de una dirección IP pública ni de una configuración de VPN compleja.
</Info>

Al trabajar con integraciones de webhooks, es habitual necesitar un endpoint de acceso público. Sin embargo, algunos entornos —especialmente las redes locales o protegidas— no permiten la exposición directa de una IP pública. Esta guía explica cómo usar un **túnel SSH inverso** para exponer un receptor de webhooks que se ejecuta en un servidor privado.

## Casos de uso

Este método es ideal para distintos escenarios en los que no se dispone de acceso público directo o no se desea:

<CardGroup cols={2}>
  <Card title="Requisitos de seguridad" icon="lock">
    Tu servidor está detrás de un NAT/firewall y no puede tener una IP pública
  </Card>

  <Card title="Integración de webhooks" icon="bell">
    Necesitas recibir solicitudes POST de webhooks desde Rhombus
  </Card>

  <Card title="Seguro y sencillo" icon="shield">
    Quieres una forma segura de reenviar tráfico a tu receptor de webhooks local
  </Card>

  <Card title="Redes empresariales" icon="building">
    Los firewalls corporativos impiden las conexiones entrantes directas
  </Card>
</CardGroup>

## Descripción general de la arquitectura

<Info>
  **Cómo funciona**

  El túnel SSH inverso conecta el relay público de vuelta a tu servidor local, reenviando de forma segura el tráfico externo a tu receptor de webhooks.
</Info>

### Componentes

| Componente             | Función                           | Ejemplos                  |
| ---------------------- | --------------------------------- | ------------------------- |
| **Servidor privado**   | Ejecuta el receptor de webhooks   | `localhost:8080`          |
| **Relay público**      | Pequeña instancia de nube pública | EC2, Linode, DigitalOcean |
| **Emisor de webhooks** | Envía solicitudes HTTP POST       | Rhombus Cloud Services    |

## Implementación paso a paso

<Steps>
  <Step title="Aprovisiona un servidor relay público">
    Configura un servidor Linux ligero (por ejemplo, Ubuntu) en un proveedor de nube como AWS, GCP o DigitalOcean.

    **Requisitos:**

    * Asigna una IP pública o un nombre de dominio (por ejemplo, `relay.yourdomain.com`)
    * Abre los puertos entrantes (**80** o **443**) para el tráfico HTTP/HTTPS
    * Especificaciones mínimas: 1 CPU, 512MB de RAM es suficiente

    <Tabs>
      <Tab title="AWS EC2">
        ```bash AWS EC2 Setup theme={null}
        # Ejemplo de configuración de una instancia AWS EC2
        aws ec2 run-instances \
          --image-id ami-0abcdef1234567890 \
          --count 1 \
          --instance-type t2.micro \
          --key-name my-key-pair \
          --security-groups my-security-group
        ```
      </Tab>

      <Tab title="DigitalOcean">
        ```bash DigitalOcean Setup theme={null}
        # Ejemplo de configuración de un droplet de DigitalOcean
        doctl compute droplet create relay-server \
          --size s-1vcpu-512mb-10gb \
          --image ubuntu-20-04-x64 \
          --region nyc3
        ```
      </Tab>

      <Tab title="Google Cloud">
        ```bash Google Cloud Setup theme={null}
        # Ejemplo de configuración de una VM de Google Cloud
        gcloud compute instances create relay-server \
          --zone=us-central1-a \
          --machine-type=e2-micro \
          --image-family=ubuntu-2004-lts \
          --image-project=ubuntu-os-cloud
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Configura SSH para el túnel remoto">
    En el **servidor relay**, modifica la configuración del daemon SSH para permitir el reenvío de puertos remotos:

    ```bash Edit SSH Config theme={null}
    sudo nano /etc/ssh/sshd_config
    ```

    Asegúrate de que las siguientes opciones estén establecidas:

    ```bash SSH Configuration theme={null}
    # Habilita los puertos de gateway para el reenvío remoto
    GatewayPorts yes

    # Permite el reenvío TCP
    AllowTcpForwarding yes

    # Permite abrir cualquier puerto
    PermitOpen any
    ```

    <Warning>
      **Nota de seguridad**

      Estos ajustes permiten el reenvío de puertos remotos. Habilítalos solo en servidores relay dedicados y protégelos con reglas de firewall adecuadas.
    </Warning>

    Reinicia el servicio SSH:

    ```bash Restart SSH theme={null}
    sudo systemctl restart ssh

    # Verifica que SSH se está ejecutando
    sudo systemctl status ssh
    ```
  </Step>

  <Step title="Configura la autenticación con clave SSH">
    En tu **servidor privado** (donde se ejecuta el receptor de webhooks), genera claves SSH y cópialas al relay:

    ```bash Generate SSH Keys theme={null}
    # Genera el par de claves SSH
    ssh-keygen -t rsa -b 4096 -C "webhook-tunnel@yourdomain.com"

    # Copia la clave pública al servidor relay
    ssh-copy-id -i ~/.ssh/id_rsa.pub user@<RELAY_PUBLIC_IP>
    ```

    Verifica el acceso SSH sin contraseña:

    ```bash Test Connection theme={null}
    # Prueba la conexión (no debería pedir contraseña)
    ssh user@<RELAY_PUBLIC_IP>
    ```

    <Tip>
      Usa una clave SSH dedicada para el túnel a fin de facilitar la rotación de claves y mejorar el aislamiento de seguridad.
    </Tip>
  </Step>

  <Step title="Establece el túnel SSH inverso">
    Ejecuta el siguiente comando en tu **servidor privado**:

    <Tabs>
      <Tab title="Basic Tunnel">
        ```bash Basic Reverse SSH Tunnel theme={null}
        # Túnel SSH inverso básico
        ssh -R 80:localhost:8080 user@<RELAY_PUBLIC_IP>
        ```

        **Explicación:**

        * `80` - Puerto externo expuesto por el servidor relay
        * `localhost:8080` - Dirección de tu receptor de webhooks local
        * La conexión permanece activa en primer plano
      </Tab>

      <Tab title="Background Process">
        ```bash Background Tunnel theme={null}
        # Ejecuta el túnel en segundo plano
        ssh -Nf -R 80:localhost:8080 user@<RELAY_PUBLIC_IP>
        ```

        **Opciones:**

        * `-N` - No ejecuta comandos remotos
        * `-f` - Pasa a segundo plano tras la autenticación
        * `-R` - Reenvío de puertos remotos
      </Tab>

      <Tab title="Persistent Tunnel">
        ```bash Persistent Tunnel with autossh theme={null}
        # Instala autossh para túneles persistentes
        sudo apt install autossh

        # Ejecuta el túnel persistente
        autossh -M 0 -Nf -R 80:localhost:8080 user@<RELAY_PUBLIC_IP>
        ```

        **Ventajas:**

        * Se reconecta automáticamente si la conexión se cae
        * Monitoreo y recuperación integrados
        * Ideal para entornos de producción
      </Tab>
    </Tabs>
  </Step>

  <Step title="Prueba la configuración">
    Ahora comprueba que tu túnel funciona correctamente:

    ```bash Test Webhook theme={null}
    # 1. Inicia tu receptor de webhooks localmente
    # Ejemplo: servidor Node.js en el puerto 8080
    node webhook-server.js

    # 2. Prueba desde una fuente externa
    curl -X POST http://<RELAY_PUBLIC_IP>/webhook \
      -H "Content-Type: application/json" \
      -d '{"test": "webhook payload"}'

    # 3. Revisa los logs de tu servidor local en busca de la solicitud
    ```

    **URL del webhook para Rhombus:**

    ```text theme={null}
    http://<RELAY_PUBLIC_IP>/your-webhook-endpoint
    ```

    <Check>
      **Indicador de éxito**

      Si ves la solicitud en los logs de tu receptor de webhooks local, ¡el túnel funciona correctamente!
    </Check>
  </Step>
</Steps>

## Mejoras de seguridad

### HTTPS con NGINX

Para entornos de producción, añade soporte para HTTPS:

<Tabs>
  <Tab title="NGINX Setup">
    ```bash Install NGINX theme={null}
    # Instala NGINX en el servidor relay
    sudo apt update
    sudo apt install nginx

    # Crea una configuración básica
    sudo nano /etc/nginx/sites-available/webhook-tunnel
    ```
  </Tab>

  <Tab title="SSL Certificate">
    ```bash Let's Encrypt SSL theme={null}
    # Instala Certbot para Let's Encrypt
    sudo apt install certbot python3-certbot-nginx

    # Genera el certificado SSL
    sudo certbot --nginx -d your-domain.com
    ```
  </Tab>

  <Tab title="Configuration">
    ```nginx NGINX Configuration theme={null}
    server {
        listen 443 ssl;
        server_name your-domain.com;

        ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;

        location / {
            proxy_pass http://localhost:80;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
    ```
  </Tab>
</Tabs>

### Buenas prácticas de seguridad

<AccordionGroup>
  <Accordion title="Autenticación" icon="key">
    **Autenticación basada en claves:**

    * Usa solo autenticación SSH basada en claves
    * Deshabilita la autenticación por contraseña
    * Rota las claves SSH con regularidad

    ```bash Secure SSH theme={null}
    # Deshabilita la autenticación por contraseña
    sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
    sudo systemctl restart ssh
    ```
  </Accordion>

  <Accordion title="Seguridad de red" icon="shield">
    **Configuración del firewall:**

    * Restringe el tráfico con reglas de firewall
    * Usa fail2ban para proteger SSH
    * Monitorea las conexiones del túnel

    ```bash Firewall Rules theme={null}
    # Ejemplo de reglas de firewall (UFW)
    sudo ufw allow ssh
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    sudo ufw --force enable
    ```
  </Accordion>

  <Accordion title="Control de acceso" icon="lock">
    **Restringe el acceso:**

    * Limita el acceso SSH a IPs específicas cuando sea posible
    * Usa puertos SSH no estándar
    * Habilita la autenticación de dos factores para SSH

    ```bash IP Restriction theme={null}
    # Permite SSH solo desde una IP específica
    sudo ufw allow from YOUR_IP to any port 22
    ```
  </Accordion>
</AccordionGroup>

## Despliegue en producción

### Servicio systemd para el inicio automático

Crea un servicio systemd para iniciar automáticamente el túnel al arrancar:

```bash Create Service File theme={null}
# Crea el archivo de servicio
sudo nano /etc/systemd/system/webhook-tunnel.service
```

```ini Systemd Service Configuration theme={null}
[Unit]
Description=Webhook SSH Tunnel
After=network.target

[Service]
Type=simple
User=your-username
ExecStart=/usr/bin/autossh -M 0 -N -R 80:localhost:8080 user@relay-server.com
Restart=always
RestartSec=5
Environment="AUTOSSH_GATETIME=0"
Environment="AUTOSSH_POLL=30"

[Install]
WantedBy=multi-user.target
```

```bash Enable Service theme={null}
# Habilita e inicia el servicio
sudo systemctl daemon-reload
sudo systemctl enable webhook-tunnel
sudo systemctl start webhook-tunnel

# Comprueba el estado
sudo systemctl status webhook-tunnel
```

### Monitoreo y registro

```bash Monitor Tunnel theme={null}
# Monitorea el estado del túnel
ps aux | grep autossh

# Revisa los logs del túnel
journalctl -u webhook-tunnel -f

# Prueba la salud del túnel
curl -s http://<RELAY_PUBLIC_IP>/health || echo "Tunnel down"
```

## Ventajas de este enfoque

<CardGroup cols={2}>
  <Card title="Funciona detrás de firewalls" icon="shield-check">
    Funciona perfectamente detrás de un NAT o de firewalls corporativos sin ninguna regla de entrada
  </Card>

  <Card title="No requiere VPN" icon="circle-xmark">
    Elimina la configuración compleja de una VPN y su sobrecarga de mantenimiento
  </Card>

  <Card title="Automatización sencilla" icon="robot">
    Fácil de automatizar con autossh y systemd para una fiabilidad de producción
  </Card>

  <Card title="Seguro para empresas" icon="building">
    Conexión totalmente saliente, segura para la mayoría de las políticas de red empresariales
  </Card>

  <Card title="Rentable" icon="dollar-sign">
    Usa recursos mínimos en una pequeña instancia de nube (\$5-10/mes)
  </Card>

  <Card title="Muy fiable" icon="check">
    Se reconecta automáticamente y se autorrepara con la configuración adecuada
  </Card>
</CardGroup>

## Resolución de problemas

<AccordionGroup>
  <Accordion title="La conexión SSH falla" icon="triangle-exclamation">
    **Problema:** No se puede establecer la conexión SSH con el servidor relay

    **Soluciones:**

    ```bash Diagnose SSH Issues theme={null}
    # Comprueba el estado del servicio SSH
    sudo systemctl status ssh

    # Verifica que el firewall permite SSH
    sudo ufw status

    # Prueba con registro detallado
    ssh -v user@<RELAY_PUBLIC_IP>

    # Comprueba la configuración de SSH
    sudo sshd -t
    ```
  </Accordion>

  <Accordion title="El túnel no funciona" icon="circle-xmark">
    **Problema:** El túnel se estableció pero las solicitudes de webhook no llegan al servidor local

    **Soluciones:**

    ```bash Diagnose Tunnel Issues theme={null}
    # Comprueba si el puerto está enlazado en el relay
    ss -tlnp | grep :80

    # Prueba el servidor de webhooks local
    curl localhost:8080/test

    # Verifica el ajuste GatewayPorts
    sudo grep GatewayPorts /etc/ssh/sshd_config

    # Revisa los logs del servidor relay
    sudo journalctl -u ssh -f
    ```
  </Accordion>

  <Accordion title="El puerto ya está en uso" icon="ban">
    **Problema:** El puerto 80 ya está en uso en el servidor relay

    **Soluciones:**

    ```bash Resolve Port Conflicts theme={null}
    # Encuentra qué está usando el puerto 80
    sudo lsof -i :80

    # Usa un puerto alternativo
    ssh -R 8080:localhost:8080 user@<RELAY_PUBLIC_IP>

    # Detén el servicio en conflicto (por ejemplo, Apache)
    sudo systemctl stop apache2
    ```
  </Accordion>

  <Accordion title="La conexión se cae con frecuencia" icon="signal">
    **Problema:** El túnel se desconecta con regularidad

    **Soluciones:**

    * Usa `autossh` en lugar del `ssh` normal
    * Añade ajustes de keep-alive a la configuración de SSH
    * Comprueba la estabilidad de la red entre servidores
    * Aumenta los valores de timeout

    ```bash SSH Keep-Alive theme={null}
    # Añade a ~/.ssh/config
    Host relay-server
        HostName <RELAY_PUBLIC_IP>
        ServerAliveInterval 60
        ServerAliveCountMax 3
    ```
  </Accordion>
</AccordionGroup>

## Ejemplos de implementaciones de webhooks

<Tabs>
  <Tab title="Node.js">
    ```javascript webhook-server.js theme={null}
    // webhook-server.js
    const express = require('express');
    const app = express();

    app.use(express.json());

    // Endpoint de webhook de Rhombus
    app.post('/rhombus-webhook', (req, res) => {
      console.log('Received webhook:', req.body);

      // Procesa la carga útil: una regla se activó y referencia uno o varios eventos de dispositivo
      const { ruleUuid, triggeredTimestampMs, deviceEvents = [], ruleTriggers = [] } = req.body;

      const triggerTypes = ruleTriggers.map((t) => t.type).join(', ');
      console.log(`Rule ${ruleUuid} fired at ${triggeredTimestampMs} (triggers: ${triggerTypes})`);

      // Tu lógica de negocio aquí: itera los eventos de dispositivo que coincidieron con la regla
      for (const event of deviceEvents) {
        const activities = (event.activities || []).join(', ');
        console.log(
          `Device ${event.deviceUuid} (${event.deviceType}) at location ${event.locationUuid} ` +
          `reported [${activities}] at ${event.timestampMs}`
        );
      }

      // Responde para confirmar la recepción
      res.status(200).json({ status: 'received' });
    });

    // Endpoint de comprobación de salud
    app.get('/health', (req, res) => {
      res.status(200).json({ status: 'healthy' });
    });

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

    **Instalación:**

    ```bash theme={null}
    npm install express
    node webhook-server.js
    ```
  </Tab>

  <Tab title="Python">
    ```python webhook_server.py theme={null}
    # webhook_server.py
    from flask import Flask, request, jsonify
    import logging

    app = Flask(__name__)
    logging.basicConfig(level=logging.INFO)

    @app.route('/rhombus-webhook', methods=['POST'])
    def webhook():
        data = request.get_json()
        app.logger.info(f'Received webhook: {data}')

        # Procesa la carga útil: una regla se activó y referencia uno o varios eventos de dispositivo
        rule_uuid = data.get('ruleUuid')
        triggered_timestamp_ms = data.get('triggeredTimestampMs')
        rule_triggers = data.get('ruleTriggers', [])
        device_events = data.get('deviceEvents', [])

        trigger_types = ', '.join(t.get('type', '') for t in rule_triggers)
        app.logger.info(f'Rule {rule_uuid} fired at {triggered_timestamp_ms} (triggers: {trigger_types})')

        # Tu lógica de negocio aquí: itera los eventos de dispositivo que coincidieron con la regla
        for event in device_events:
            activities = ', '.join(event.get('activities', []))
            app.logger.info(
                f"Device {event.get('deviceUuid')} ({event.get('deviceType')}) "
                f"at location {event.get('locationUuid')} reported [{activities}] "
                f"at {event.get('timestampMs')}"
            )

        # Responde para confirmar la recepción
        return jsonify({'status': 'received'}), 200

    @app.route('/health', methods=['GET'])
    def health():
        return jsonify({'status': 'healthy'}), 200

    if __name__ == '__main__':
        app.run(host='localhost', port=8080, debug=True)
    ```

    **Instalación:**

    ```bash theme={null}
    pip install flask
    python webhook_server.py
    ```
  </Tab>

  <Tab title="C#">
    ```csharp WebhookListener.cs theme={null}
    // WebhookListener.cs
    using Microsoft.AspNetCore.Mvc;
    using System.Linq;
    using System.Text.Json;

    [ApiController]
    [Route("/")]
    public class WebhookController : ControllerBase
    {
        private readonly ILogger<WebhookController> _logger;

        public WebhookController(ILogger<WebhookController> logger)
        {
            _logger = logger;
        }

        [HttpPost("rhombus-webhook")]
        public IActionResult ReceiveWebhook([FromBody] JsonElement payload)
        {
            _logger.LogInformation($"Received webhook: {payload}");

            // Procesa la carga útil: una regla se activó y referencia uno o varios eventos de dispositivo
            string ruleUuid = payload.GetProperty("ruleUuid").GetString();
            long triggeredTimestampMs = payload.GetProperty("triggeredTimestampMs").GetInt64();

            _logger.LogInformation($"Rule {ruleUuid} fired at {triggeredTimestampMs}");

            // Tu lógica de negocio aquí: itera los eventos de dispositivo que coincidieron con la regla
            foreach (var evt in payload.GetProperty("deviceEvents").EnumerateArray())
            {
                string deviceUuid = evt.GetProperty("deviceUuid").GetString();
                string deviceType = evt.GetProperty("deviceType").GetString();
                string locationUuid = evt.GetProperty("locationUuid").GetString();
                var activities = evt.GetProperty("activities")
                    .EnumerateArray()
                    .Select(a => a.GetString());

                _logger.LogInformation(
                    $"Device {deviceUuid} ({deviceType}) at location {locationUuid} " +
                    $"reported [{string.Join(", ", activities)}]");
            }

            // Responde para confirmar la recepción
            return Ok(new { status = "received" });
        }

        [HttpGet("health")]
        public IActionResult Health()
        {
            return Ok(new { status = "healthy" });
        }
    }
    ```

    **Ejecutar:**

    ```bash theme={null}
    dotnet run
    ```
  </Tab>

  <Tab title="Go">
    ```go webhook-server.go theme={null}
    // webhook-server.go
    package main

    import (
        "encoding/json"
        "fmt"
        "log"
        "net/http"
    )

    type DeviceEvent struct {
        EventUUID    string   `json:"eventUuid"`
        DeviceUUID   string   `json:"deviceUuid"`
        DeviceType   string   `json:"deviceType"`
        LocationUUID string   `json:"locationUuid"`
        TimestampMs  int64    `json:"timestampMs"`
        Activities   []string `json:"activities"`
    }

    type RuleTrigger struct {
        Type string `json:"type"`
    }

    type WebhookPayload struct {
        UUID                 string        `json:"uuid"`
        OrgUUID              string        `json:"orgUuid"`
        RuleUUID             string        `json:"ruleUuid"`
        TriggeredTimestampMs int64         `json:"triggeredTimestampMs"`
        DeviceEvents         []DeviceEvent `json:"deviceEvents"`
        RuleTriggers         []RuleTrigger `json:"ruleTriggers"`
    }

    func webhookHandler(w http.ResponseWriter, r *http.Request) {
        if r.Method != http.MethodPost {
            http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
            return
        }

        var payload WebhookPayload
        err := json.NewDecoder(r.Body).Decode(&payload)
        if err != nil {
            http.Error(w, "Bad request", http.StatusBadRequest)
            return
        }

        log.Printf("Received webhook: %+v", payload)
        log.Printf("Rule %s fired at %d", payload.RuleUUID, payload.TriggeredTimestampMs)

        // Itera los eventos de dispositivo que coincidieron con la regla
        for _, event := range payload.DeviceEvents {
            log.Printf("Device %s (%s) at location %s reported %v at %d",
                event.DeviceUUID, event.DeviceType, event.LocationUUID,
                event.Activities, event.TimestampMs)
        }

        // Responde para confirmar la recepción
        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(map[string]string{"status": "received"})
    }

    func healthHandler(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(map[string]string{"status": "healthy"})
    }

    func main() {
        http.HandleFunc("/rhombus-webhook", webhookHandler)
        http.HandleFunc("/health", healthHandler)

        port := ":8080"
        fmt.Printf("Webhook server running on port %s\n", port)
        log.Fatal(http.ListenAndServe(port, nil))
    }
    ```

    **Ejecutar:**

    ```bash theme={null}
    go run webhook-server.go
    ```
  </Tab>
</Tabs>

## Configurar webhooks en Rhombus

Una vez que tu receptor esté en ejecución y el túnel esté establecido:

<Steps>
  <Step title="Obtén la URL de tu webhook">
    La URL pública de tu webhook será:

    ```text theme={null}
    http://<RELAY_PUBLIC_IP>/rhombus-webhook
    ```

    o con HTTPS:

    ```text theme={null}
    https://your-domain.com/rhombus-webhook
    ```
  </Step>

  <Step title="Configura en la Consola de Rhombus">
    1. Inicia sesión en [Rhombus Console](https://console.rhombussystems.com)
    2. Navega a **Settings** → **Third Party Integrations** > **Webhooks**
    3. Haz clic en **Add Webhook**
    4. Introduce la URL pública de tu webhook
    5. Selecciona los eventos que quieres recibir
    6. Guarda la configuración
  </Step>

  <Step title="Monitorea los eventos">
    Observa los logs de tu servidor de webhooks para ver los eventos entrantes en tiempo real.
  </Step>
</Steps>

## Próximos pasos

<Check>
  **¡Éxito!**

  Ahora tienes una forma segura y fiable de recibir webhooks de Rhombus en tu infraestructura privada sin exponer tus servidores a internet ni requerir configuraciones de VPN complejas.
</Check>

<CardGroup cols={2}>
  <Card title="Rhombus Console" icon="desktop" href="https://console.rhombussystems.com">
    Configura webhooks en la Consola de Rhombus
  </Card>

  <Card title="Webhooks Overview" icon="webhook" href="/es/webhooks">
    Conoce los tipos de eventos de webhook de Rhombus y los formatos de carga útil
  </Card>

  <Card title="Developer Community" icon="users" href="https://rhombus.community">
    Únete a nuestra comunidad para obtener soporte sobre la integración de webhooks
  </Card>
</CardGroup>

<Note>
  Para despliegues en producción: valida las firmas de los webhooks, usa HTTPS, implementa la limitación de velocidad y mantén registros completos de los eventos de webhook. Configura monitoreo y alertas para los fallos en la entrega de webhooks.
</Note>
