5 eventos cubren todo el ciclo de un payment intent. Cada uno llega firmado con HMAC-SHA256 al endpoint que configuraste en el dashboard, con retry exponencial hasta 6 intentos.
5
Event types
HMAC-256
Firma
6 retries
Backoff exponencial
≤ 60s
Latencia típica
Cada request trae X-CWallet-Signature = HMAC-SHA256(raw body, webhook_secret). Validá antes de hacer cualquier cosa.
// Node.js + Express (raw body required)
import crypto from 'node:crypto';
app.post('/webhooks/cwallet',
express.raw({ type: 'application/json' }),
(req, res) => {
const sig = req.headers['x-cwallet-signature'];
const expected = crypto
.createHmac('sha256', process.env.CWALLET_WEBHOOK_SECRET)
.update(req.body)
.digest('hex');
if (sig.length !== expected.length ||
!crypto.timingSafeEqual(
Buffer.from(sig, 'hex'),
Buffer.from(expected, 'hex'))) {
return res.status(401).end();
}
const event = JSON.parse(req.body.toString());
// … process event …
res.json({ received: true });
});En Python: hmac.new(secret, body, hashlib.sha256).hexdigest() con hmac.compare_digest. En PHP: hash_hmac('sha256', $body, $secret) con hash_equals.
Cada evento llega con headers X-CWallet-Event, X-CWallet-Environment, X-CWallet-Livemode, X-CWallet-Signature.
Cuándo: El cliente pagó (live: USDT settled on-chain; sandbox: simulado).
Tu acción: Marcá la orden como pagada. Acreditá producto/servicio al cliente.
{
"event": "payment.success",
"intent_id": "11111111-2222-3333-4444-555555555555",
"transfer_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"amount": 25.5,
"currency": "USDT",
"terminal_id": "99999999-aaaa-bbbb-cccc-dddddddddddd",
"terminal_name": "Caja principal",
"environment": "live",
"livemode": true,
"simulated": false,
"timestamp": "2026-05-20T14:23:01.234Z"
}Cuándo: Se crea un nuevo payment intent (útil para sincronizar dashboards).
Tu acción: Logueá en tu sistema; opcional para auditoría/analytics.
{
"event": "intent.created",
"intent_id": "11111111-2222-3333-4444-555555555555",
"amount": 25.5,
"currency": "USDT",
"terminal_id": "99999999-aaaa-bbbb-cccc-dddddddddddd",
"terminal_name": "Caja principal",
"environment": "live",
"livemode": true,
"expires_at": "2026-05-20T15:23:01.234Z",
"checkout_uri": "cwallet:pay?intent=11111111-2222-3333-4444-555555555555",
"timestamp": "2026-05-20T14:23:01.234Z"
}Cuándo: Un intent pendiente llegó a su expires_at sin pagarse.
Tu acción: Cancelá el carrito del cliente, liberá stock reservado.
{
"event": "payment.expired",
"intent_id": "11111111-2222-3333-4444-555555555555",
"amount": 25.5,
"currency": "USDT",
"terminal_id": "99999999-aaaa-bbbb-cccc-dddddddddddd",
"terminal_name": "Caja principal",
"environment": "live",
"livemode": true,
"timestamp": "2026-05-20T15:23:01.234Z"
}Cuándo: Un admin del merchant rotó la API key del terminal desde el dashboard.
Tu acción: Invalidá la API key cacheada — la nueva tenés que sacarla del dashboard manualmente.
{
"event": "key.rotated",
"terminal_id": "99999999-aaaa-bbbb-cccc-dddddddddddd",
"environment": "live",
"livemode": true,
"rotated_at": "2026-05-20T16:00:00.000Z",
"last4": "Ab12"
}Cuándo: Disparado a demanda desde el dashboard ("Probar webhook"). Útil para validar tu endpoint.
Tu acción: Responder 200. Sirve para confirmar que la URL es alcanzable y la firma se verifica bien.
{
"event": "test.ping",
"message": "Hello from CWallet. Si ves esto con una firma HMAC válida, tu endpoint está bien wireado.",
"request_id": "cccccccc-dddd-eeee-ffff-000000000000",
"environment": "sandbox",
"livemode": false,
"timestamp": "2026-05-20T16:05:00.000Z"
}Si tu endpoint no responde 2xx en 8 segundos, CWallet reintenta con backoff exponencial. Tras 6 intentos fallidos, el evento queda marcado como dead y aparece en /admin para revisión.
| Intento | Espera desde el último intento | Total transcurrido |
|---|---|---|
| #1 | inmediato | 0s |
| #2 | +1 min | 1 min |
| #3 | +5 min | 6 min |
| #4 | +30 min | 36 min |
| #5 | +2 h | ~3 h |
| #6 | +6 h | ~9 h |
| dead | +24 h | ~33 h |