Documentación / Configuración de pagos — y el único paso que pierde dinero en silencio

Configuración de pagos — y el único paso que pierde dinero en silencio

Las credenciales de pago son solo del lado del servidor: viven en .env en tu máquina y nunca en la base de datos, nunca en un formulario, nunca en este admin. Eso es deliberado. Lo que sigue es dónde va cada valor —y el único paso que es fácil de pasar por alto y caro de pasar por alto—.

El paso que cuesta dinero si te lo saltas

La mayoría de los métodos de pago indonesios son asíncronos. Un comprador elige una cuenta virtual, una cartera electrónica, o paga en un punto de venta minorista, y luego cierra la pestaña. Puede terminar de pagar una hora más tarde, desde su app bancaria, en un dispositivo diferente. Nada de eso regresa jamás a tu sitio web.

Así que la compra se completa cuando el proveedor llama a tu servidor —un webhook— y por nada más.

Si esa llamada nunca llega:

  • el dinero del comprador te llega,
  • su licencia nunca se emite,
  • el pedido queda en "pending",
  • y nada en ningún sitio dice por qué.

Este no es un caso límite raro. En los métodos indonesios es la ruta normal.

Dónde obtiene su URL cada proveedor

Proveedor URL del webhook Quién la configura
Xendit https://yourdomain/webhooks/xendit tú, a mano, una vez
PayPal (ninguna) no hace falta: se completa al regresar

PayPal se completa cuando el comprador regresa, así que no necesita ningún webhook en absoluto. Xendit es el que te necesita: mira más abajo.

Xendit es el que te necesita. Su callback de "invoice paid" es a nivel de cuenta, no por factura, así que se configura una vez en el propio panel de Xendit.

Xendit, clic a clic

  1. Inicia sesión en dashboard.xendit.co.
  2. Settings → Developers → Webhooks.
  3. Bajo Invoices paid, pega la URL que tu página de admin muestra para Xendit (https://yourdomain/webhooks/xendit).
  4. Guarda, y copia el webhook verification token que se muestra en la misma página.
  5. Pon ese token en el .env de tu servidor como XENDIT_CALLBACK_TOKEN, junto a XENDIT_SECRET_KEY.
  6. Reinicia el sitio para que se lean los nuevos valores.

Ambas mitades son necesarias. La URL sin el token significa que las entregas llegan y se rechazan; el token sin la URL significa que no llega nada en absoluto.

Demostrar que realmente funciona

No confíes en el "ya lo pegué". Abre Admin → Settings → Payment webhooks. Informa de lo que ha llegado genuinamente a tu servidor:

Qué dice Qué significa Qué hacer
Never received Nunca ha llegado nada de este proveedor La URL falta o es incorrecta en el panel del proveedor
Not matching Las entregas llegan pero no nombran ningún pedido tuyo La URL apunta hacia ti desde una cuenta diferente del proveedor a la que usa la tienda
Working Al menos una entrega coincidió con un pedido real Nada: está conectado

Los contadores solo se mueven para las llamadas que llevan las propias credenciales del proveedor, así que una sonda aleatoria desde internet nunca puede hacer que una pasarela sin configurar parezca saludable.

Pruébalo de principio a fin antes de aceptar dinero real. El panel de Xendit tiene un botón "test webhook" en la misma página; úsalo, y luego recarga la ficha de admin. Si sigue diciendo Never received, la URL es incorrecta: revisa si hay un error tipográfico, un https:// faltante o una barra final.

Las credenciales en sí

Hay dos maneras de configurarlas. Ambas mantienen el secreto fuera de la vista: ninguna muestra jamás un valor guardado.

Desde la página de admin (recomendado)

Admin → Settings → Payment gateway credentials. Introduce el PayPal Client ID + Secret (y el interruptor sandbox/live) y la Xendit Secret Key + Callback token. Se guardan cifrados en el servidor; los campos son de solo escritura, así que una vez guardados nunca se vuelven a mostrar: la página solo indica Configured / Not set. Deja un campo en blanco para dejarlo sin cambios; usa Remove stored credentials para borrar uno.

Configuración de una sola vez: genera la clave que los cifra, mantenida separada de la clave de la app para que un volcado de la base de datos y una fuga del .env sean cada uno inútiles por su cuenta:

php artisan store:secrets-key      # writes STORE_SECRETS_KEY to .env — then BACK IT UP off the server
php artisan config:clear

Perder STORE_SECRETS_KEY hace que las credenciales guardadas queden ilegibles (bastaría con volver a introducirlas).

O desde .env (alternativa)

Si lo prefieres, configúralas en .env en el servidor y luego reinicia. Los valores de la página de admin tienen prioridad cuando ambos están presentes.

# Xendit
XENDIT_SECRET_KEY=...
XENDIT_CALLBACK_TOKEN=...     # from Settings → Developers → Webhooks

# PayPal
PAYPAL_CLIENT_ID=...
PAYPAL_SECRET=...
PAYPAL_ENV=sandbox           # or: live

Una pasarela sin credenciales simplemente queda desactivada: no hay nada más que habilitar.

Si tu servidor está detrás de un proxy o firewall

La ruta del webhook es una URL pública, de servidor a servidor. No tiene inicio de sesión, por necesidad: el proveedor no puede iniciar sesión como tú. En su lugar está protegida por la propia firma o token del proveedor, una relectura autoritativa del estado del pago directamente desde el proveedor, y un límite de tasa.

Eso significa que POST /webhooks/* debe ser alcanzable desde la internet pública. Si lo bloqueas, o pones el sitio entero detrás de una lista blanca de IPs, los pagos asíncronos dejan de cumplirse, con exactamente el mismo síntoma silencioso que no haber configurado nunca la URL.