Ir al contenido

Mejores Prácticas

Sigue estas recomendaciones para implementar webhooks de forma robusta y confiable.

Tu endpoint debe responder en menos de 10 segundos. Si tu procesamiento es pesado, guarda el evento y procésalo en background:

// BIEN: Responder rápido, procesar después
public function handle(Request $request)
{
// Guardar para procesar en background
WebhookEvent::create([
'event_id' => $request->input('id'),
'payload' => $request->all()
]);
return response('OK', 200); // Responder inmediatamente
}
// En un job de background
ProcessWebhookJob::dispatch($webhookEvent);

Puedes recibir el mismo evento más de una vez. Usa el campo id para detectar duplicados:

public function handle(Request $request)
{
$eventId = $request->input('id');
// ¿Ya procesamos este evento?
if (ProcessedEvent::where('event_id', $eventId)->exists()) {
return response('Already processed', 200);
}
// Procesar y registrar en una transacción
DB::transaction(function () use ($request, $eventId) {
ProcessedEvent::create(['event_id' => $eventId]);
$this->processEvent($request->all());
});
return response('OK', 200);
}

Al crear payment links, usa la descripción para incluir información útil:

Ventana de terminal
curl -X POST https://api.alohapay.co/api/external/v1/payment-links \
-H "X-API-Key: tu_api_key" \
-d '{
"amount": 100.00,
"currency": "USD",
"description": "Orden #1234 - Cliente: cus_789"
}'

La descripción te llega de vuelta en el webhook, facilitando la reconciliación.

Si te suscribes a múltiples eventos, asegúrate de manejarlos todos:

switch ($event['event']) {
case 'payment.completed':
// Marcar orden como pagada
break;
case 'payment.failed':
// Notificar al cliente
break;
case 'payment_link.expired':
// Liberar inventario reservado
break;
default:
// Evento desconocido - ignorar pero responder OK
Log::info('Evento no manejado: ' . $event['event']);
break;
}

Guarda logs de todos los webhooks para debugging:

Log::info('Webhook recibido', [
'event_id' => $event['id'],
'event_type' => $event['event'],
'object_id' => $event['data']['object']['id'] ?? null,
'amount' => $event['data']['object']['amount'] ?? null,
'status' => $event['data']['object']['status'] ?? null,
]);

Si tu servidor no responde con código 2xx, reintentamos automáticamente:

IntentoEsperaTiempo acumulado
1Inmediato0
21 minuto1 minuto
35 minutos6 minutos
415 minutos21 minutos
51 hora1 hora 21 min
63 horas4 horas 21 min

Después del intento 6, el webhook se marca como fallido permanentemente.

Código¿Reintenta?Razón
200-299NoÉxito
408Timeout
429Rate limit
500-599Error del servidor
400-499 (otros)NoError del cliente

case 'payment.completed':
$order = Order::where('payment_id', $payment['id'])->first();
$order->update([
'status' => 'paid',
'paid_at' => $payment['completed_at']
]);
// Reducir inventario
foreach ($order->items as $item) {
$item->product->decrement('stock', $item->quantity);
}
// Notificar al cliente usando customer_data
$customerEmail = $payment['customer_data']['email'] ?? null;
if ($customerEmail) {
Mail::to($customerEmail)->send(new OrderConfirmedMail($order));
}
// Notificar al vendedor
Notification::send($order->seller, new NewSaleNotification($order));
break;
case 'payment.completed':
$subscription = Subscription::where('payment_id', $payment['id'])->first();
$subscription->update([
'status' => 'active',
'started_at' => now(),
'expires_at' => now()->addMonth()
]);
// Habilitar acceso al usuario
$subscription->user->update(['plan' => $subscription->plan]);
break;
case 'payment.completed':
$sale = Sale::where('payment_id', $payment['id'])->first();
// Calcular comisión usando el monto del webhook
$commission = $payment['amount'] * 0.10; // 10%
$sellerAmount = $payment['amount'] - $commission;
// Registrar para payout
SellerPayout::create([
'seller_id' => $sale->seller_id,
'amount' => $sellerAmount,
'currency' => $payment['currency'],
'status' => 'pending'
]);
break;

  1. Verifica que tu endpoint sea público

    Ventana de terminal
    curl -X POST https://tu-servidor.com/webhooks/alohapay \
    -H "Content-Type: application/json" \
    -d '{"test": true}'
  2. Verifica que el webhook esté activo

    Ventana de terminal
    curl https://api.alohapay.co/api/external/v1/webhooks \
    -H "X-API-Key: tu_api_key"
  3. Revisa los logs de tu servidor

  4. Verifica que no hay firewall bloqueando

  1. Usa el body raw, no parseado
  2. Verifica el orden: {timestamp}.{body}
  3. Usa el secret correcto (el que recibiste al crear)
  4. Usa comparación segura (hash_equals, no ===)
  • Los webhooks tienen un delay de 1-5 segundos normalmente
  • Si hay reintentos, pueden llegar horas después
  • Usa el campo created para saber cuándo ocurrió el evento real

RecursoLímite
Webhooks por API Key10
Timeout de respuesta10 segundos
Reintentos máximos6
Tamaño máximo de payload64 KB
Antigüedad máxima de timestamp5 minutos

¿Necesitas ayuda con tu integración?