api

Webhooks

QuantaPay envía solicitudes HTTP POST a la URL de webhook configurada cuando ocurren eventos de pago. Esto permite que tu servidor reaccione a los pagos en tiempo real.

Actualizado: 8/4/2026

QuantaPay envía solicitudes HTTP POST a la URL de webhook configurada cuando ocurren eventos de pago. Esto permite que tu servidor reaccione a los pagos en tiempo real.

Configuración

Configura tu webhook en Ajustes → Pagos → Webhook:

  • Webhook URL: Tu endpoint HTTPS (p. ej., https://tusitio.com/webhook/quantapay)
  • Webhook Secret Key: Clave generada automáticamente para verificar el payload

Carga útil del webhook

Cuando se completa un pago, QuantaPay envía una solicitud POST con Content-Type: application/json:

{
  "key": "your-webhook-secret-key",
  "transaction": {
    "id": "197",
    "biz_id": "QP-20260408-560BF",
    "title": "",
    "description": "",
    "from": "0xCustomerWalletAddress",
    "to": "0xYourWalletAddress",
    "hash": "0xBlockchainTransactionHash",
    "amount": "0.025",
    "amount_fiat": "49.99000000",
    "cryptocurrency": "eth",
    "currency": "usd",
    "external_reference": "your-order-id-123",
    "creation_time": "2026-03-08 10:00:00",
    "status": "C",
    "webhook": "1",
    "vat": "0",
    "billing": "",
    "checkout_id": null,
    "type": "2"
  }
}

Campos de la transacción

CampoTipoDescripción
idstringID interno de transacción en QuantaPay.
biz_idstringReferencia de pedido de QuantaPay (p. ej., QP-20260408-560BF).
titlestringTítulo de la transacción.
fromstringDirección de cartera del cliente (remitente).
tostringTu dirección de cartera (receptor).
hashstringHash de la transacción en blockchain.
amountstringMonto en criptomoneda.
amount_fiatstringMonto en moneda fiat (8 decimales, p. ej., "49.99000000").
cryptocurrencystringCódigo de criptomoneda (p. ej., btc, eth, usdt).
currencystringCódigo de moneda fiat (p. ej., usd, eur, hkd).
external_referencestringTu ID de pedido — proporcionado al crear la Checkout Session. Úsalo para localizar tu pedido.
creation_timestringMarca de tiempo de creación de la transacción (UTC).
statusstringEstado de la transacción: C (completada).
checkout_idstring|nullID de la Checkout Session asociada, o null.
typestringTipo de transacción: 1 = pago directo, 2 = Checkout Session.

Asociar pedidos con external_reference

Esta es la forma recomendada de vincular un pago de QuantaPay con tu propio pedido.

Al crear una Checkout Session, pasa el ID de tu pedido en el campo external_reference:

{
  "order_id": "your-order-id-123",
  "external_reference": "your-order-id-123",
  "price": 49.99,
  "currency": "usd"
}

QuantaPay almacena este valor y lo devuelve sin cambios en el payload del webhook bajo transaction.external_reference. Úsalo para encontrar y completar el pedido correcto.

Verificación de firma

El campo key del payload contiene tu Webhook Secret Key. Si no está configurado, el sistema usa la clave de cifrado de tu cuenta. Configura siempre una Webhook Secret Key dedicada.

Ejemplo PHP

$payload = json_decode(file_get_contents('php://input'), true);

$webhook_secret = 'your-webhook-secret-key'; // From Settings

// 1. Verify webhook authenticity
if ($payload['key'] !== $webhook_secret) {
    http_response_code(401);
    die('Invalid webhook signature');
}

$transaction = $payload['transaction'];

// 2. Check payment is complete
if ($transaction['status'] !== 'C') {
    http_response_code(200);
    die('Not completed');
}

// 3. Match your order using external_reference
$your_order_id = $transaction['external_reference'];
$order = find_order($your_order_id);
if (!$order) {
    http_response_code(200);
    die('Order not found');
}

// 4. Verify amount using float comparison (amount_fiat has 8 decimal places)
$paid_amount = floatval($transaction['amount_fiat']);
$expected_amount = floatval($order->total);
if (abs($paid_amount - $expected_amount) > 0.01 || $transaction['currency'] !== $order->currency) {
    http_response_code(200);
    die('Amount mismatch');
}

// 5. Idempotency check — use biz_id as dedup key
if (order_already_fulfilled($transaction['biz_id'])) {
    http_response_code(200);
    die('Already processed');
}

// 6. Mark order as paid
fulfill_order($your_order_id);

http_response_code(200);
echo 'OK';

Ejemplo Node.js

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

const WEBHOOK_SECRET = 'your-webhook-secret-key';

app.post('/webhook/quantapay', (req, res) => {
  const { key, transaction } = req.body;

  // 1. Verify webhook authenticity
  if (key !== WEBHOOK_SECRET) {
    return res.status(401).send('Invalid signature');
  }

  // 2. Only process completed payments
  if (transaction.status !== 'C') {
    return res.status(200).send('OK');
  }

  // 3. Match your order using external_reference
  const yourOrderId = transaction.external_reference;
  const bizId = transaction.biz_id; // use as dedup key

  console.log(`Payment completed: ${transaction.amount_fiat} ${transaction.currency}`);
  console.log(`Your order: ${yourOrderId}, QuantaPay ref: ${bizId}`);
  console.log(`TX Hash: ${transaction.hash}`);

  // Fulfill order logic here (use biz_id for idempotency)

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

app.listen(3000);

Prueba con cURL

curl -X POST https://yoursite.com/webhook/quantapay \
  -H "Content-Type: application/json" \
  -d '{
    "key": "your-webhook-secret-key",
    "transaction": {
      "id": "197",
      "biz_id": "QP-20260408-560BF",
      "status": "C",
      "amount": "0.025",
      "amount_fiat": "49.99000000",
      "cryptocurrency": "eth",
      "currency": "usd",
      "external_reference": "your-order-id-123",
      "hash": "0xabc123..."
    }
  }'

Tipos de eventos

EstadoEventoDescripción
CPago completadoEl pago ha sido confirmado en la blockchain con suficientes confirmaciones.

Nota: Los webhooks solo se envían para transacciones completadas (estado C). Las transacciones expiradas o pendientes no los activan.

Mejores prácticas

1. Responder rápidamente

Devuelve HTTP 200 tan pronto como recibas el webhook. Procesa tareas pesadas de forma asíncrona.

2. Procesamiento idempotente

Tu manejador debe ser idempotente — procesar el mismo webhook dos veces no debe causar duplicados. Usa biz_id como clave de deduplicación.

if (order_already_fulfilled($transaction['biz_id'])) {
    http_response_code(200);
    die('Already processed');
}

3. Verificar la clave

Verifica siempre que el campo key coincida con tu Webhook Secret Key antes de procesar.

4. Usar HTTPS

Usa siempre un endpoint HTTPS para tu URL de webhook.

5. Registrar todo

Registra todos los webhooks entrantes para depuración y auditoría.

error_log('QuantaPay Webhook: ' . json_encode($payload));

6. Gestionar fallos correctamente

QuantaPay no reintenta automáticamente los webhooks fallidos. Usa la API get-checkout-session o get-transactions como alternativa para verificar el estado del pago si tu servidor estuvo temporalmente inaccesible.