Botón de Pago - Hook
Los botones de pago personalizados ofrecen la posibilidad de enviar notificaciones cuando se realiza un pago exitoso, esto se logra mediante la configuración de un hook.
Activar Hook para un Botón de Pago
Activar un hook toma solo 2 pasos:
Definir la credencial predeterminada para hooks, que se utilizará para firmar cada solicitud y te permitirá validar la autenticidad de la información.
Configurar el URL al cual enviaremos las solicitudes.
Para utilizar el Hook, primero debes crear un botón de pago dinámico: Ver Tutorial
1. Definir una Credencial Predeterminada para Hooks
Para definirla ingresa en Configuración > Credenciales API

En el ejemplo de arriba podemos ver la opción donde escogeremos de una lista desplegable, la credencial que usaremos por defecto para los hooks.
2. Configurar el URL de tu Sistema
El segundo paso es configurar la ruta a la cual se harán las solicitudes cada vez que se reciban pagos exitosos en un botón de pago personalizado. Algunas consideraciones a tener presente:
Debe ser una ruta pública (accesible desde Internet).
Debe tener un certificado de seguridad válido (ruta debe utilizar HTTPS).
Para configurar el URL, simplemente ingresa a el/los botones de pago en los que quieres activar el Hook, haz click en editar y posteriormente en “Opciones Avanzadas”.
Una vez en las Opciones Avanzadas encontrarás un campo llamado “URL del Hook” donde podrás colocar la ruta.

Validación de Firma
1. Librerías oficiales
Se recomienda usar nuestras librerías oficiales:
Entorno | Paquete | Docs & Install |
---|---|---|
Python ≥ 3.8 | fygaro-webhook | `pypi.org/project/fygaro-webhook` |
Node ≥ 16 | @fygaro/webhook | `npmjs.com/package/@fygaro/webhook` |
En resumen: Instala el paquete, crea un validador con tu(s) secreto(s) compartido(s), llama a verify_signature y solo procesa el JSON si devuelve True (Python) o true (JS).
2. Algoritmo manual (para otros lenguajes)
Si no hay una librería disponible, implementa estos pasos:
Lee el cuerpo crudo de la solicitud (en bytes).
Analiza la cabezera Fygaro-Signature → extrae el timestamp t= y cada has v1=.
Analiza el Fygaro-Key-ID para saber cual secret utilizar.
(Recomendado) rechazar si abs(now - t) > 300 s (protección básica contra reproducción).
Re-crea el mensaje exactamente como lo hizo Fygaro:
message = t + "." + raw_body
Calcula HMAC-SHA-256(secret, message) → hex.
Constant-time compare el resultado contra cada `v1`; acepta si alguno coincide.
En caso exitoso, responde con HTTP 200 y continua procesando el JSON; de lo contrario retorna 4xx.
3. Ejemplos por lenguaje
PHP ≥ 7.4 (sin importar el framework)
<?php
// 1. Map Fygaro-Key-ID → shared secret (raw string)
$secrets = [
'1234abcd' => 'your-secret-here',
];
// 2. Read raw body & headers
$rawBody = file_get_contents('php://input') ?: '';
$sigHdr = $_SERVER['HTTP_FYGARO_SIGNATURE'] ?? '';
$keyId = $_SERVER['HTTP_FYGARO_KEY_ID'] ?? '';
if ($sigHdr === '' || $keyId === '') {
http_response_code(400);
exit('Missing Fygaro headers');
}
// 3. Parse Fygaro-Signature (t=...,v1=...,v1=...)
$timestamp = null;
$hashes = [];
foreach (explode(',', $sigHdr) as $part) {
[$k, $v] = array_map('trim', explode('=', $part, 2));
if ($k === 't') { $timestamp = $v; }
if ($k === 'v1') { $hashes[] = $v; }
}
if (!$timestamp || !$hashes || !isset($secrets[$keyId])) {
http_response_code(400);
exit('Malformed signature header');
}
// 4. Optional replay check (±5 min window)
if (abs(time() - (int)$timestamp) > 300) {
http_response_code(400);
exit('Stale timestamp');
}
// 5. Compute expected HMAC
$secret = $secrets[$keyId];
$message = $timestamp . '.' . $rawBody;
$expected = hash_hmac('sha256', $message, $secret);
// 6. Validate: any v1 must match
$valid = false;
foreach ($hashes as $h) {
if (hash_equals($expected, $h)) {
$valid = true;
break;
}
}
if (!$valid) {
http_response_code(400);
exit('Invalid signature');
}
// 7. Signature verified → process payload
$data = json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR);
/* …your business logic… */
// MUST reply with HTTP 200 so Fygaro marks the hook successful
http_response_code(200);
echo 'OK';
(Para C#, Ruby, Go, etc., adapta el manejo de cabeceras/cuerpo y cálculo HMAC según el lenguaje.)
4. Mejores prácticas
Guarda los secretos de forma segura (variables de entorno, vaults).
Rota los secretos de manera suave: mantén ambos (viejo y nuevo) hasta que todo el tráfico use el nuevo.
Siempre usa comparación en tiempo constante (hash_equals, timingSafeEqual, etc.).
Nunca registres secretos o HMACs completos—solo razones de fallo e IDs de solicitud.
Responde con HTTP 200 rápidamente en caso de éxito; Fygaro lo interpreta como “entregado”.
Webhook del Botón de Pago
1. Webhook payload (POST body)
All monetary values are strings with two decimals.
{
"transactionId": "08d7360a-fc4b-46ad-a513-0a3d3fd3771c",
"reference": "ORDER-98765",
"customReference": "INV-2025-0420",
"authCode": "A12345",
"currency": "USD",
"amount": "59.99",
"createdAt": "2025-06-20T14:32:07Z",
// ↓ The next three blocks are OPTIONAL; they are sent only when data exists.
"card": {
"last4": "4242",
"expMonth": 12,
"expYear": 2030,
"brand": "visa"
},
"client": {
"email": "jane.doe@example.com",
"phone": "15551234567"
},
"billing": {
"country": { "name": "United States", "code": "US" },
"state": { "name": "California" },
"city": { "name": "Los Angeles" },
"locality": { "name": "Hollywood" },
"address": "123 Main St Apt 4B",
"postal_code": "90028"
},
"gratuity_amount": "5.00", // Present only when tips are captured
"jwt": "eyJhbGciOiJIUzI1NiIsImtpZCI6IjEyMzRhYmNkIn0…" // LEGACY; will be removed
}
Referencia de campos
Field | Type | Description |
---|---|---|
transactionId | string (UUID) | ID de transacción de Fygaro inmutable. |
reference | string | Referencia de pago. |
customReference | string \ | null |
authCode | string \ | null |
currency | string | ISO 4217 code (e.g., USD). |
amount | string | Monto capturado ("59.99"). |
createdAt | ISO-8601 string | UTC timestamp de cuando el pago fue creado. |
gratuity_amount | string \ | absent |
card | object \ | absent |
client | object \ | absent |
billing | object \ | absent |
jwt | string | Deprecated. Present for backward compatibility only. |
Aviso: comienza a migrar fuera del campo jwt ahora; futuras versiones del API lo omitirán.
card object
Campo | Tipo | Descripción |
---|---|---|
last4 | string \ | null |
expMonth | integer \ | null |
expYear | integer \ | null |
brand | string | Uno de: visa, mastercard, amex, discover, diners, jcb, unionpay, maestro, o unknown. |
client object
Campo | Tipo | Descripción |
---|---|---|
name | string | Nombre del comprador. |
string \ | absent | |
phone | string \ | absent |
billing object
Campo | Tipo | Descripción |
---|---|---|
country.name | string \ | null |
country.code | string \ | null |
state.name | string \ | null |
city.name | string \ | null |
locality.name | string \ | null |
address | string \ | null |
postal_code | string \ | null |
Necesita ayuda? → soporte@fygaro.com
Actualizado el: 23/06/2025
¡Gracias!