Pasar a producción
Prueba todo con pagos simulados y pasa a cobrar de verdad cambiando solo la configuración.
Para cuando tu integración ya funciona en prueba y vas a recibir pagos reales. La idea es que pasar a producción no toque tu código: solo variables de entorno y recursos creados otra vez en el otro entorno.
El modelo
| Prueba | Producción | |
|---|---|---|
| Clave secreta | Empieza por sk_test_ | Empieza por sk_prod_ |
| SDK | environment: "test" | environment: "production" |
| Pagos | Simulados, con escenarios conocidos | Reales: mueven dinero |
| Productos, planes, clientes | Los de prueba | Otros, creados en producción |
| Webhook | Su endpoint y su secreto | Otro endpoint, con otro secreto |
- Dos entornos aislados. Nada pasa de uno a otro: un ID de prueba no existe en producción. Por eso tu código busca planes y productos por su
lookupKey, que sí puede repetirse en cada entorno, en vez de guardar IDs. - La misma validación en los dos. Los datos que pide cada método de pago y cómo se validan son iguales; en prueba solo cambia el cobro real por un simulador. Lo que funciona en prueba funciona en producción.
- La clave dice su entorno. El SDK rechaza al crearse una clave que no coincide con
environment, así que una configuración mezclada falla al arrancar y no al cobrar.
1. Prueba con pagos simulados
Con una clave sk_test_, cada método del checkout trae escenarios de prueba: qué datos enviar para que el pago se confirme, falle por un motivo concreto o se quede esperando. El checkout alojado los muestra; en un checkout propio vienen en testScenarios.
Recorre al menos una compra exitosa, un pago rechazado y su reintento, un evento repetido y, si vendes suscripciones, una renovación y una cancelación. La lista completa está en prueba tu integración.
2. Configura el entorno por variables
import { createBillete } from "@boelabs/billete-sdk";
// Lee la clave de BILLETE_API_KEY.
export const billete = createBillete({
apiVersion: "2026-10-24",
environment: process.env.BILLETE_ENVIRONMENT === "production" ? "production" : "test",
});En el servidor de producción, BILLETE_API_KEY tiene la clave sk_prod_ (de Desarrolladores → Claves API, con el dashboard en producción) y BILLETE_ENVIRONMENT vale production. La clave nunca va en el navegador ni dentro de una app móvil: ahí se usa el cliente público.
3. Crea tus recursos en producción
Productos, planes, cuotas, cupones y enlaces de pago se crean otra vez, con el dashboard en producción o con un script que corres una vez. A planes y productos dales el mismo lookupKey que en prueba y búscalos por él; las cuotas ya se identifican por su key:
const { data: [plus] } = await billete.plans.list({ lookupKey: "plus" });
const { data: [camiseta] } = await billete.products.list({ lookupKey: "camiseta_negra" });Los clientes no se copian: se crean solos con sus primeras compras o suscripciones en producción.
4. Registra el webhook de producción
const endpoint = await billete.webhookEndpoints.create({
url: "https://tuapp.com/api/webhooks/billete",
events: ["checkout.completed", "subscription.updated", "subscription.renewed"],
});
// Guarda `endpoint.secret` en el servidor de producción: no es el de prueba.En producción la URL debe ser HTTPS y pública. Cómo recibir los eventos sin perder ni duplicar ninguno está en webhooks sin perder ni duplicar.
5. Revisa la lista
- Versión fija.
apiVersiones obligatoria en el SDK y Billete nunca cambia una versión publicada: tu integración se comporta igual hasta que tú la actualices. El endpoint del webhook tiene su propia versión; mantenla igual a la del SDK (versiones). - Idempotencia en lo que cobra o devuelve. El SDK genera una clave por llamada, pero si tu código repite una operación (un job que reintenta, un doble clic), pasa una
idempotencyKeyderivada de lo tuyo, comocheckout-${order.id}(idempotencia). - Errores por código. Decide según
error.code, nunca según el mensaje, y guardaerror.requestIdpara soporte. Si una llamada se cortó (network_error), consulta el estado antes de repetirla:
import { BilleteError } from "@boelabs/billete-sdk";
try {
await billete.subscriptions.create(input, { idempotencyKey: `hobby-${user.id}` });
} catch (error) {
if (error instanceof BilleteError && error.code === "subscription_exists") return;
throw error;
}- Entrega por webhook, no por la página de éxito. El cliente puede abrir
successUrlsin haber pagado; entrega al recibircheckout.completed. - Eventos del entorno correcto. Tu ruta de webhooks comprueba
event.environmentantes de procesar.
6. Activa tu negocio
Para operar en producción, tu negocio debe completar su verificación en el dashboard y estar aprobado. Hasta entonces, una petición con una clave sk_prod_ responde production_not_enabled. Prueba no necesita aprobación: está disponible siempre.
7. Haz el primer pago real
Con todo desplegado, haz una compra real pequeña y comprueba el monto en bolívares, que llegue el webhook, que tu aplicación entregue la compra y que el pago aparezca en el dashboard. Desde aquí, cada operación mueve dinero real.
Prueba tu integración · Autenticación · Configuración del SDK · Errores y reintentos
Webhooks sin perder ni duplicar
Recibe los eventos de Billete, guárdalos una sola vez y procésalos aparte, aunque lleguen repetidos, tarde o en otro orden.
Autoservicio del cliente
Deja que tus clientes paguen sus renovaciones, cancelen o cambien sus puestos con el portal de Billete o con tus propias pantallas.