Vas a tener este flujo funcionando.
- Verificar X-PietroCal-Signature sobre los bytes exactos.
- Deduplicar reintentos automáticos y manuales.
- Consultar el recurso completo mediante la API autorizada.
Seguí el contrato en este orden.
Registrá el endpoint
Desde Integraciones y API elegí URL HTTPS, tipos de evento y conservá el Signing Secret fuera del código fuente.
Leé el cuerpo crudo
Calculá HMAC SHA-256 sobre timestamp + punto + raw body. No vuelvas a serializar el JSON antes de verificar.
Deduplicá la entrega
Guardá X-PietroCal-Delivery con una restricción única. Un reenvío conserva el mismo identificador.
Confirmá y procesá
Respondé 2xx después de persistir el trabajo. Procesá en cola y consultá la API cuando necesites el estado completo.
Superficie utilizada.
Configuración → Integraciones y API → Webhooks
Registrar URL, eventos y secreto
Tu endpoint HTTPS
Recibir la entrega firmada
/api/v1/{recurso}.php
Recuperar el estado autorizado vigente
<?php
$secret = getenv('PIETROCAL_WEBHOOK_SECRET');
$timestamp = $_SERVER['HTTP_X_PIETROCAL_TIMESTAMP'] ?? '';
$signature = $_SERVER['HTTP_X_PIETROCAL_SIGNATURE'] ?? '';
$delivery = $_SERVER['HTTP_X_PIETROCAL_DELIVERY'] ?? '';
$rawBody = file_get_contents('php://input');
$expected = 'v1=' . hash_hmac(
'sha256',
$timestamp . '.' . $rawBody,
$secret
);
if ($timestamp === '' || $delivery === '' || !hash_equals($expected, $signature)) {
http_response_code(401);
exit;
}
// Insertar $delivery con índice UNIQUE antes de encolar el procesamiento.
// Si ya existe, responder 204 sin repetir el efecto.
http_response_code(204);
Lista de verificación.
- Rechazá versiones de schema que tu consumidor no soporte.
- Validá una tolerancia temporal antes de aceptar el timestamp.
- No asumas orden global entre endpoints ni entre reintentos.
- No registres Signing Secret, Authorization ni cuerpos sensibles.
Tratamiento mínimo.
Firma inválidaSe verificó JSON reserializado, secreto incorrecto o cuerpo alterado.
Entrega duplicadaEs normal con at least once; resolvela mediante el Delivery ID persistido.
TimeoutRespondé después de encolar, no después de completar trabajo pesado.
429 o 503PietroCal respeta Retry-After con un máximo operativo de seis horas.