# Integración para bots de terceros — cómo un bot cobra con QuickPay

¿Tienes un bot de WhatsApp, Telegram o tu propia app? Integra QuickPay en 3 pasos y **cobra a tus clientes sin construir infraestructura bancaria**.

El flujo es simple: tu bot crea un link de pago, lo envía en un mensaje con botón, QuickPay cobra, y te avisa por webhook.

## Flujo de pago del usuario final

```
1. Cliente abre WhatsApp → ve mensaje de tu bot con botón "Pagar"
2. Toca el botón → abre en WhatsApp el checkout hosteado de QuickPay
3. Selecciona su banco, autoriza con la clave de 8 dígitos que le envía su banco (SMS, notificación o correo)
4. QuickPay cobra y, si enviaste `success_url`, lo devuelve a tu web
5. Tu bot se entera por webhook → entrega el servicio
```

## Paso 1: Obtén tu llave

1. Abre tu cuenta de comercio en el portal (con tu cédula o el RIF de tu empresa).
2. En **Integraciones › Llaves de API**, crea una llave de **prueba**. Tiene la forma `tu-comercio:sk_test_…` y se muestra una sola vez.
3. Guárdala en una variable de entorno de tu servidor (nunca en el código del bot que corre en el teléfono del cliente).

Cuando todo funcione en prueba, crea la de producción: → [Pasar a producción](/developers/pasar-a-produccion)

## Paso 2: Crea un link de pago desde tu bot

**Cuando un cliente quiera pagar**, crea un link:

### Ejemplo: bot de Node.js

```js
const axios = require('axios');

async function crearLinkDePago(monto, concepto, metaDatos) {
  const response = await axios.post(
    'https://pay.pagaconquickpay.com/switch/v1/links',
    {
      monto,
      concepto,
      expira_horas: 24,
      metadata: metaDatos,          // tus datos; vuelven al crear, no en el webhook
      idempotency_key: metaDatos.orden, // reintentar no duplica el cobro
    },
    {
      headers: {
        'x-switch-key': process.env.QUICKPAY_KEY,
        'content-type': 'application/json'
      }
    }
  );

  return response.data;
}

// Uso
const link = await crearLinkDePago(
  450.00,
  'Crédito bot de consultoría',
  { cliente_id: 'CLI-001', orden: 'ORD-2026-100' }
);

console.log('Link de pago:', link.url);
// Guarda link.id junto a la orden: el webhook te dirá ese id cuando la paguen.
```

### Ejemplo: bot de Python

```python
import requests
import os

def crear_link_de_pago(monto, concepto, metadatos):
    response = requests.post(
        'https://pay.pagaconquickpay.com/switch/v1/links',
        json={
            'monto': monto,
            'concepto': concepto,
            'expira_horas': 24,
            'metadata': metadatos,
            'idempotency_key': metadatos['orden'],
        },
        headers={
            'x-switch-key': os.environ['QUICKPAY_KEY'],
            'content-type': 'application/json'
        }
    )
    
    return response.json()

# Uso
link = crear_link_de_pago(
    450.00,
    'Crédito bot de consultoría',
    {'cliente_id': 'CLI-001', 'orden': 'ORD-2026-100'}
)

print(f"Link: {link['url']}")
```

### Ejemplo: bot de Make/n8n (sin código)

**Make.com:**

1. **HTTP Request** a `POST https://pay.pagaconquickpay.com/switch/v1/links`
   - Headers: `x-switch-key: {{QUICKPAY_KEY}}`
   - Body (JSON):
     ```json
     {
       "monto": {{monto}},
       "concepto": "{{concepto}}",
       "expira_horas": 24,
       "metadata": {
         "cliente_id": "{{cliente_id}}"
       }
     }
     ```

2. **Extrae** `data.url` de la respuesta.

3. **Continúa** con el resto de tu flow (enviar a WhatsApp, etc.).

## Paso 3: Envía el link por WhatsApp con botón

Una vez tienes la URL, envía un mensaje **interactivo** con botón al cliente.

### 3.1 Si usas WhatsApp Cloud API

```js
const axios = require('axios');

async function enviarPagoWhatsApp(numeroCliente, urlPago, monto) {
  await axios.post(
    `https://graph.facebook.com/v18.0/${process.env.WA_PHONE_ID}/messages`,
    {
      messaging_product: 'whatsapp',
      to: numeroCliente,
      type: 'interactive',
      interactive: {
        type: 'cta_url',
        body: {
          text: `Hola, tienes un pago de Bs ${monto.toFixed(2)} pendiente. Puedes pagarlo desde cualquier banco.`
        },
        footer: {
          text: 'Powered by QuickPay'
        },
        action: {
          name: 'cta_url',
          parameters: { display_text: 'Pagar ahora', url: urlPago }
        }
      }
    },
    {
      headers: {
        'Authorization': `Bearer ${process.env.WA_TOKEN}`
      }
    }
  );
}
```

### 3.2 Si usas Make/n8n/Zapier

- **Module**: WhatsApp / Send Interactive Message
- **Text**: "Tienes un pago de Bs XXX pendiente"
- **Button type**: URL
- **Button text**: "Pagar ahora"
- **Button URL**: `{{link.url}}`

## Paso 4: Recibe la confirmación de pago (webhook)

Registra la URL de tu bot en **Integraciones › Webhooks** (o con `POST /switch/v1/webhooks`). Cuando tu cliente paga, te llega `link.pagado` con el `link_id`: búscalo en tu base, verifica la firma v2 y confírmale al cliente por WhatsApp. → [Webhooks](/developers/webhooks-referencia)

## Paso 5: Entrega el servicio/producto

El aviso trae el `link_id`, no tus `metadata`: busca la orden que guardaste con ese id.

```js
// En tu handler del webhook (después de verificar la firma)
if (event.type === 'link.pagado') {
  const orden = await BD.buscarOrden({ link_id: event.data.link_id });
  if (!orden || orden.estado === 'pagado') return; // ya entregada: el aviso puede llegar dos veces

  await BD.actualizar({ link_id: event.data.link_id }, { estado: 'pagado', pagado_en: new Date() });
  await entregarServicio(orden.cliente_id, orden.id);
  await enviarConfirmacion(orden.cliente_id);
}
```

## Flujo completo (ejemplo real)

**Bot de créditos educativos:**

```js
const express = require('express');
const axios = require('axios');

const app = express();
app.use(express.json());

// Cliente envía: "/pagar 450 Matricula"
app.post('/api/iniciar-pago', async (req, res) => {
  const { cliente_id, monto, concepto } = req.body;

  // 1. Crear link de pago
  const link = await axios.post(
    'https://pay.pagaconquickpay.com/switch/v1/links',
    {
      monto,
      concepto,
      metadata: { cliente_id }
    },
    { headers: { 'x-switch-key': process.env.QUICKPAY_KEY } }
  );

  // 2. Guardar orden pendiente
  await BD.insertOne({
    cliente_id,
    link_id: link.data.id,
    monto,
    concepto,
    estado: 'pendiente'
  });

  // 3. Enviar botón a WhatsApp
  await axios.post(`https://graph.facebook.com/v18.0/${process.env.WA_PHONE_ID}/messages`, {
    messaging_product: 'whatsapp',
    to: cliente_id,
    type: 'interactive',
    interactive: {
      type: 'cta_url',
      body: { text: `Hola, tienes un pago de Bs ${monto} por ${concepto}.` },
      action: {
        name: 'cta_url',
        parameters: { display_text: 'Pagar ahora', url: link.data.url }
      }
    }
  }, {
    headers: { 'Authorization': `Bearer ${process.env.WA_TOKEN}` }
  });

  res.json({ link: link.data.url });
});

// 4. Webhook de confirmación (verifica la firma v2 antes: ver Webhooks)
app.post('/webhooks/quickpay', async (req, res) => {
  const event = req.body;

  if (event.type === 'link.pagado') {
    // El aviso trae link_id: con él encuentras la orden que guardaste en el paso 2
    const orden = await BD.findOne({ link_id: event.data.link_id, estado: 'pendiente' });
    if (!orden) return res.status(200).send('OK'); // repetido o desconocido
    const cliente_id = orden.cliente_id;

    await BD.updateOne({ link_id: event.data.link_id }, { estado: 'pagado', pagado_en: new Date() });

    // Envía confirmación a WhatsApp
    axios.post(`https://graph.facebook.com/v18.0/${process.env.WA_PHONE_ID}/messages`, {
      messaging_product: 'whatsapp',
      to: cliente_id,
      type: 'text',
      text: { body: '✓ Pago confirmado. Tu matrícula está activa.' }
    }, {
      headers: { 'Authorization': `Bearer ${process.env.WA_TOKEN}` }
    });
  }

  res.status(200).send('OK');
});

app.listen(3000);
```

## Checklist de implementación

- ✅ Tengo `x-switch-key` y `QUICKPAY_WEBHOOK_SECRET` en `.env`.
- ✅ Mi bot crea links con `POST /switch/v1/links`.
- ✅ Envío el link en un botón de WhatsApp (o mi plataforma).
- ✅ Registré el webhook en `/switch/v1/webhooks`.
- ✅ Mi endpoint verifica firmas HMAC-SHA256.
- ✅ Respondo `200` en menos de 8 segundos desde el webhook.
- ✅ Deduplico eventos por `(type, data.link_id)`.
- ✅ Entrego el servicio cuando recibo `link.pagado`.
- ✅ Probé con la llave de prueba (`sk_test_…`) antes de producción.

## Troubleshooting

| Problema | Solución |
|---|---|
| "unauthorized" (401) | Verifica que `x-switch-key` está en formato `comercio:sk_test_xxx` |
| Link devuelve estado "pendiente" | Normal, espera el webhook. Cliente aún no pagó. |
| No recibo webhook | Verifica que tu URL es HTTPS, responde `200` y tu firewall no bloquea. |
| "Invalid signature" | Asegúrate de capturar el **raw body** antes de parsear JSON. |
| Cliente se sale del checkout | Normal, espera a que intente de nuevo o el link expire (24h default). |

## Seguridad

- **Guarda `sk_live_…` en variables de entorno**, nunca en código.
- **Verifica siempre el webhook** — no confíes en un `link.pagado` sin firma.
- **Sé idempotente** — un webhook puede llegar dos veces.
- **No des acceso** a `QUICKPAY_WEBHOOK_SECRET` a código cliente.
- **Usa HTTPS** en tu endpoint de webhook.

## Próximos pasos

- Prueba el ciclo completo con tu llave de prueba → [Modo prueba](/developers/datos-de-prueba)
- Cuando funcione, cambia a la llave de producción → [Pasar a producción](/developers/pasar-a-produccion)

## Soporte

Escríbenos por WhatsApp desde el enlace **Soporte** al pie de esta página.

