Sandboxes y Test Clocks
Un Sandbox es un tenant aislado de una cuenta LIVE. Tiene sus propias llaves TEST, objetos, actividad, balances simulados y endpoints de webhook. Una llave de Sandbox nunca puede leer IDs de LIVE ni de otro Sandbox, y ninguna simulación llama a un procesador, banco, blockchain o proveedor fiscal.
El rollout se habilita por cuenta. Una vez habilitado, toda operación pública corre dentro del tenant aislado: algunas usan el modelo normal y otras persisten una simulación local determinística. Ninguna llama proveedores reales.
Crear y autenticar un Sandbox
Un administrador crea hasta cinco ambientes en Configuración → Sandboxes. Puede empezar vacío o copiar marca, configuración segura de checkout, productos, precios, campos personalizados y cupones. Clientes, métodos de pago, suscripciones, movimientos, credenciales y balances nunca se copian.

La llave TEST se revela una sola vez. Guárdala fuera del código y úsala contra la misma URL base de LIVE:
Todas las respuestas y webhooks creados con esta llave pertenecen únicamente a ese Sandbox.

Al entrar al ambiente, un banner persistente mantiene visible el nombre del Sandbox y recuerda que los datos, llaves y dinero son de prueba. En mobile aparece debajo de la navegación fija para que el contexto nunca quede oculto.
Los Sandboxes no aparecen en el selector global de cuentas. Para entrar, vuelve a la cuenta LIVE y usa Configuración → Sandboxes → Entrar; así el cambio de ambiente siempre es explícito.


Diferenciar LIVE, TEST legacy y Sandboxes nombrados
Una llave LIVE nunca cambia de tenant. Una llave TEST legacy solo se enruta al Sandbox default después de que Recurrente lo aprovisiona, verifica sus llaves y webhooks, y habilita la migración para esa cuenta. Deshabilitar el routing restaura el comportamiento legacy sin borrar el Sandbox. Para integraciones nuevas, usa la llave creada directamente dentro del Sandbox nombrado.
Qué puedes probar
La API pública está disponible con llaves Sandbox, pero no permite enviar fondos. Los recursos de catálogo y configuración viven naturalmente dentro del tenant. Los cobros, refunds, conversiones, cuentas conectadas, terminales y configuración fiscal persisten estados y balances locales determinísticos. Los hijos de una plataforma forman un grafo conectado dentro del mismo Sandbox y nunca se mezclan con cuentas LIVE.
El balance de un Sandbox es simulado, no transferible y no retirable. El dashboard no ofrece Enviar. La API rechaza transferencias a cuentas o teléfonos, splits de checkout/suscripción, swaps a dólares digitales y retiros. Las conversiones internas siguen disponibles porque no sacan fondos del ledger.
Estas simulaciones conservan el contrato observable sin contactar procesadores, bancos, Bridge, blockchain, hardware POS, INFILE u otros proveedores reales. Consulta la matriz de paridad para distinguir operaciones nativas de simulaciones locales.
Elegir cómo corre el tiempo
Una suscripción de Sandbox puede usar una de dos líneas de tiempo:
Un Test Clock pertenece a un Sandbox y se asocia a un customer. Todas las suscripciones que se creen después para ese customer heredan el clock. El tiempo efectivo aplica solo a ese customer durante el request o job: otros clocks, otros customers y LIVE continúan con su propia hora.
Asocia el customer al clock antes de crear la suscripción. Un customer con una suscripción ya creada no puede cambiar de clock; crea otro customer para empezar una línea de tiempo distinta.
Tutorial: ciclo completo de una suscripción
1. Registrar el webhook de prueba
Registra el endpoint con la llave del Sandbox, no con una llave LIVE:
Guarda el signingSecret: solo aparece en la respuesta de creación. Este endpoint
recibirá únicamente eventos TEST del Sandbox autenticado.
2. Crear el clock y el customer
Guarda el id retornado como clock_... y úsalo al crear el customer:
Guarda el id del customer (cus_...). La metadata del customer es independiente
de la metadata que luego persistirá en la suscripción.
3. Crear un producto recurrente
Guarda el prices[0].id de la respuesta (price_...).
4. Crear y completar el checkout inicial
Abre el checkout_url retornado y usa:
Después del pago exitoso valida:
- checkout
paid; - suscripción
activecontest_clock_id,current_period_startycurrent_period_end; - una invoice y un payment intent exitosos;
- metadata
integration_idyscenarioen la suscripción y sus webhooks; - eventos
payment_intent.succeededysubscription.createconlive_mode: falsey elsandbox_idesperado.
La metadata que sobrevive renovaciones, reintentos y cancelación es la metadata del checkout. La metadata enviada al crear el customer permanece en el customer, pero no se copia automáticamente a la suscripción.
5. Adelantar hasta la primera renovación
Obtén la suscripción y usa su current_period_end como destino del clock:
El avance responde 202 y es asíncrono. Consulta el clock hasta que cambie de
advancing a ready:
Cuando queda ready, debe existir una nueva invoice pagada, un nuevo
payment_intent.succeeded, un período actualizado y un crédito en el balance
simulado. Si queda failed, revisa last_error antes de volver a ejecutar el caso.
6. Probar rechazo y recuperación
El resultado configurado al avanzar aplica a un solo cobro y después vuelve a
success:
Al terminar valida payment_intent.failed, subscription.past_due,
payment_retries: 1 y un next_payment_attempt_at. Para probar recovery, adelanta
el mismo clock a ese next_payment_attempt_at sin enviar next_charge_outcome:
La invoice pendiente debe quedar pagada, la suscripción debe volver a active y se
emite otro payment_intent.succeeded.
7. Probar refund y cancelación
Usa el ID pa_... de un payment_intent.succeeded para reembolsar el monto completo:
Valida un refund succeeded, el evento refund.create y la reversión del balance
simulado. Después cancela la suscripción:
Valida subscription.cancel, estado cancelled y ausencia de nuevas invoices al
adelantar el clock más allá del siguiente período.
Secuencia esperada
Cada mensaje tiene eventType, un eventId idempotente y data.event_type.
Verifica la firma con el secret del endpoint, deduplica por eventId y confirma que
data.sandbox_id corresponde al ambiente bajo prueba.
Probar un webhook sin crear su flujo de dominio
El tutorial anterior es la prueba recomendada para suscripciones porque valida objetos, estados y eventos naturales. Si solo necesitas probar la firma, routing, reintentos o idempotencia de un evento difícil de provocar, emite un fixture:
El helper acepta cualquier event_type del catálogo público, persiste una
Activity y entrega el mensaje por el mismo endpoint Svix. La respuesta 201
contiene el payload base normalizado. Recurrente genera y reemplaza data.id y
data.created_at; la entrega Svix agrega data.event_type y data.sandbox_id.
Un fixture valida el contrato de entrega, pero no crea una disputa, retiro u otro grafo de dominio. Usa el endpoint real y verifica sus objetos cuando necesitas una prueba de comportamiento end-to-end.
Los payloads naturales incluyen campos como live_mode, metadata y test_clock_id
cuando el serializer de ese dominio los publica. El helper no inventa esos campos:
entrega los enviados más event_type, sandbox_id, id y created_at.
Reglas de los Test Clocks
- Cada Sandbox puede tener hasta diez clocks y cada customer pertenece como máximo a uno.
- Un clock solo avanza hacia adelante.
- El máximo por avance es dos veces el intervalo de facturación más corto de sus suscripciones; sin suscripciones, es dos años.
- Un avance procesa cronológicamente renovaciones, reintentos y reanudaciones que ocurran antes del destino.
- Los estados son
ready,advancing,failedydeleted. - No puedes eliminar un clock mientras avanza o mientras tenga suscripciones.
- Los endpoints LIVE y los de otro Sandbox nunca reciben sus eventos.
Checklist para automatizar pruebas
- Usa un Sandbox y una llave TEST dedicados por suite o equipo.
- Crea datos únicos por caso; no reutilices IDs de LIVE.
- Registra el webhook antes de iniciar el checkout y conserva su signing secret.
- Espera
readyantes de hacer otro avance del mismo clock. - Usa las fechas devueltas por la API (
current_period_endynext_payment_attempt_at) en vez de asumir días fijos. - Afirma objetos y webhooks: estado, monto, moneda, metadata,
sandbox_idytest_clock_id. - Trata los webhooks como reintentables e idempotentes.
- Usa fixtures solo para probar consumers; usa flujos reales para probar comportamiento.
- Termina cada escenario cancelando la suscripción y archivando el Sandbox cuando ya no necesites sus datos.
Archivo y retención
Archivar un Sandbox revoca sus llaves, bloquea nuevos requests y marca sus clocks como eliminados. No purga clientes, suscripciones, invoices, actividades ni webhooks históricos: se conservan para auditoría y diagnóstico. Crea un Sandbox nuevo para una suite limpia y nunca uses datos reales de clientes como fixtures.
Diferencias frente a Stripe Test Clocks
Recurrente sigue la asociación del clock al customer, avances asíncronos y solo hacia adelante, y el máximo de dos intervalos. Recurrente se diferencia en que:
- el estado se observa consultando el clock; no se publican webhooks separados de estado;
- no se puede eliminar un clock que tenga suscripciones;
- eliminar o archivar conserva el grafo histórico en vez de borrarlo;
- los clocks no se auto-eliminan después de un período fijo;
- los objetos y nombres de evento siguen el contrato público de Recurrente.
Consulta la documentación de Stripe sobre simulación de suscripciones y uso avanzado de Test Clocks para comparar los contratos.
Consulta la referencia de cada endpoint y la matriz de paridad de Sandbox para saber qué operaciones son nativas y cuáles persisten una simulación local.

