Datos de prueba (sandbox sk_test)
Referencia de datos de prueba para integrar contra el ambiente sandbox de la QuickLink Pay API. Aquí encuentras qué cédulas, teléfonos, bancos y montos usar, qué resultado producen, y cómo reproducir cada estado y cada
motivo_rechazo.Reemplaza
{{base_url}}por la URL base de tu ambiente (p. ej. la de producción publicada en la documentación, o la que te haya indicado tu contacto de QuickLink). Todos los ejemplos usan esa variable: nunca la incrustes en tu código de integración.
0. TL;DR — lo esencial
- El modo (test/live) lo fija la API key, no el cliente. Una llave
sk_test_…enruta a sandbox; unask_live_…mueve dinero real. Tú nunca envías un campomode. - En sandbox no se mueve dinero real: los rieles van a QA / simulado (Banco Plaza QA, Bancaribe QA, Banco Activo QA; BNC simulado, sin red).
- La respuesta tiene la misma forma (
Resultado) que en producción: el resultado vive en el campoestado, no en el código HTTP. - Lee el estado final con
POST /switch/v1/consultar(la liquidación es asíncrona) o configura un webhook.
Importante sobre el alcance de este documento. Una parte de lo que sigue describe el comportamiento real, ya implementado del sandbox. Otra parte —en concreto, la tabla de “valores mágicos” que fuerzan cada
motivo_rechazo— es una convención propuesta, aún no implementada en el código. Cada sección lo indica de forma explícita con una de estas etiquetas:
- ✅ Comportamiento actual — así responde el sandbox hoy.
- 🧭 Propuesta (no implementada aún) — convención sugerida; verifica con QuickLink antes de depender de ella en tus pruebas automatizadas.
1. Autenticación y modo
Todas las llamadas usan la cabecera x-switch-key con el formato <comercio>:<api_key>:
x-switch-key: mi_comercio:sk_test_xxxxxxxxxxxxxxxxxxxx- ✅ El modo lo decide el prefijo de la llave, resuelto en el servidor:
sk_test_…→ modotest(sandbox: QA / simulado, sin dinero real).sk_live_…→ modolive(producción: rieles bancarios reales).- ✅ El cliente no puede forzar el modo: el campo
modelo fija el servidor a partir de la llave y por eso ni siquiera aparece en el request documentado. Si lo envías, se ignora. - ✅ Para probar, usa siempre tu llave
sk_test_…. Genera una desde el panel (sección de API keys del comercio). Ese mismox-switch-keysirve para la API REST y para el servidor MCP.
Una llave inválida o mal formada (
<comercio>:<secreto>incompleto) responde401 { "error": "unauthorized" }.
2. Catálogo de bancos de prueba
El campo banco de cada Instrumento es el código BCV de 4 dígitos del banco de esa persona. En sandbox puedes usar cualquier banco válido; estos son los más usados en los ejemplos:
banco | Banco | Notas para sandbox |
|---|---|---|
0138 | Banco Plaza | Riel adquirente/tesorería por defecto. En test → Plaza QA. |
0191 | BNC | En test → simulado (siempre éxito, no sale a la red). |
0105 | Banco Mercantil | Banco del pagador/beneficiario en ejemplos. |
0134 | Banesco | Banco del beneficiario en ejemplos. |
0102 | Banco de Venezuela | Genérico de prueba. |
Consulta el catálogo vigente de bancos habilitados con sus capacidades:
curl -s "{{base_url}}/switch/v1/bancos" \
-H "x-switch-key: mi_comercio:sk_test_xxx"✅ Qué banco procesa tu operación lo decide el enrutamiento del switch, no el
bancodel instrumento (ese es el banco de la persona). Para sugerir un riel, envíabanco_preferido(p. ej."bnc"para caer en el camino simulado determinista). Valores:banco_plaza,bnc,bancaribe,banco_activo.
3. Identidades de prueba (cédulas, teléfonos, cuentas)
✅ Comportamiento actual: el sandbox no valida estas identidades contra un registro real ni cambia el resultado según la cédula. Cumple las reglas de formato del contrato (validadas con zod en todos los bordes):
identificacion: cédula/RIF con prefijo de persona —V/E(natural),J/G(jurídico),P(pasaporte). Ej.:V13759368,J00378944781.valor(teléfono): celular local de 11 dígitos con0inicial. Ej.:04125551234.valor(cuenta): número de cuenta de 20 dígitos. Ej.:01380000011234567890.nombre: 1–40 caracteres.banco: 4 dígitos (ver §2).
Identidades sugeridas para tus pruebas (cualquiera válida sirve; estas son convenientes):
| Rol | tipo | valor | banco | identificacion | nombre |
|---|---|---|---|---|---|
| Comercio (tú) | cuenta | 01380000011234567890 | 0138 | J00378944781 | Mi Comercio CA |
| Pagador | telefono | 04125551234 | 0105 | V13759368 | Ana Pérez |
| Beneficiario | telefono | 04145556677 | 0134 | V14589678 | María Gómez |
| Beneficiario | cuenta | 01340000019876543210 | 0134 | V14589678 | María Gómez |
🧭 Propuesta (no implementada aún). Si en el futuro quieres forzar resultados por identidad (p. ej. “esta cédula siempre está bloqueada”), la vía recomendada es registrarla en las listas del motor de riesgo del panel en modo test (deny/allow), en lugar de codificar cédulas mágicas. Ver §7.3.
4. Montos
- ✅ Montos en VES (
monedapor defecto"VES", ISO-4217).valordebe ser un número positivo. - ✅ En sandbox el límite diario por comercio y el motor de riesgo NO aplican (corren solo sobre dinero real). Por eso, hoy, el monto no cambia el resultado: una operación de sandbox que llega al riel BNC simulado siempre tiene éxito sin importar el monto.
- 🧭 Propuesta (no implementada aún): ver §6, donde se propone usar el monto como “valor mágico” para disparar de forma determinista cada
motivo_rechazoen un simulador de sandbox.
5. Flujos y cómo simular cada estado
Los estados normalizados (EstadoTransaccion) son: ACEPTADA, PENDIENTE, LIQUIDADA, RECHAZADA, ERROR, DESCONOCIDA.
5.1 LIQUIDADA — éxito final (camino simulado determinista)
✅ Comportamiento actual. El camino más predecible en sandbox es BNC simulado: no sale a la red y devuelve éxito siempre. Un pago (/pagar) por BNC simulado es instantáneo → LIQUIDADA directo.
curl -s -X POST "{{base_url}}/switch/v1/pagar" \
-H "x-switch-key: mi_comercio:sk_test_xxx" \
-H "content-type: application/json" \
-d '{
"idempotency_key": "11111111-1111-4111-8111-111111111111",
"monto": { "valor": 250.00, "moneda": "VES" },
"banco_preferido": "bnc",
"via": "pago_movil",
"ordenante": { "tipo": "cuenta", "valor": "01380000011234567890", "banco": "0138", "identificacion": "J00378944781", "nombre": "Mi Comercio CA" },
"beneficiario": { "tipo": "telefono", "valor": "04145556677", "banco": "0134", "identificacion": "V14589678", "nombre": "Maria Gomez" },
"concepto": "Reintegro de prueba",
"proposito": "transferencia"
}'Respuesta (forma Resultado):
{
"id": "...",
"estado": "LIQUIDADA",
"banco_usado": "bnc",
"referencia_banco": "TEST-11111111", // prefijo TEST- + 8 primeros del idempotency_key
"endtoend": null,
"motivo_rechazo": null,
"intentos": 1,
"raw": { "simulated": true } // marca inequívoca de sandbox
}Reconoces una respuesta simulada porque
raw.simulated === truey lareferencia_bancoempieza porTEST-.
5.2 ACEPTADA → PENDIENTE → LIQUIDADA — flujo asíncrono
✅ Comportamiento actual. Los cobros por BNC simulado devuelven ACEPTADA (aceptado por el banco, aún no liquidado):
curl -s -X POST "{{base_url}}/switch/v1/cobrar" \
-H "x-switch-key: mi_comercio:sk_test_xxx" \
-H "content-type: application/json" \
-d '{
"idempotency_key": "22222222-2222-4222-8222-222222222222",
"monto": { "valor": 320.00, "moneda": "VES" },
"banco_preferido": "bnc",
"cobrador": { "tipo": "cuenta", "valor": "01380000011234567890", "banco": "0138", "identificacion": "J00378944781", "nombre": "Mi Comercio CA" },
"pagador": { "tipo": "telefono", "valor": "04125551234", "banco": "0105", "identificacion": "V13759368", "nombre": "Ana Perez" },
"concepto": "Matricula 2026-1",
"otp": "12345678"
}'→ { "estado": "ACEPTADA", "banco_usado": "bnc", "referencia_banco": "TEST-22222222", "raw": { "simulated": true }, ... }
Para conocer el estado final, consulta con el id devuelto:
curl -s -X POST "{{base_url}}/switch/v1/consultar" \
-H "x-switch-key: mi_comercio:sk_test_xxx" \
-H "content-type: application/json" \
-d '{ "id": "<id-de-la-respuesta-anterior>" }'En rieles que liquidan por BCV (Crédito Inmediato vía Plaza/Bancaribe QA), una operación puede quedar
ACEPTADA/PENDIENTEy el poller la confirma luego comoLIQUIDADAoRECHAZADA. Repite/consultar(o usa webhook) hasta ver un estado final (LIQUIDADA/RECHAZADA).
5.3 Cobro con OTP en dos pasos (token + cobrar)
✅ Comportamiento actual. Un cobro por débito inmediato puede requerir un OTP que el banco del pagador emite en un paso previo:
- Solicitar token (
/cobrar/token): el banco del pagador genera el OTP. En sandbox BNC esto devuelveACEPTADAsimulado (no se envía SMS real). ``bash curl -s -X POST "{{base_url}}/switch/v1/cobrar/token" \ -H "x-switch-key: mi_comercio:sk_test_xxx" \ -H "content-type: application/json" \ -d '{ "idempotency_key": "33333333-3333-4333-8333-333333333333", "monto": { "valor": 320.00, "moneda": "VES" }, "banco_preferido": "bnc", "cobrador": { "tipo": "cuenta", "valor": "01380000011234567890", "banco": "0138", "identificacion": "J00378944781", "nombre": "Mi Comercio CA" }, "pagador": { "tipo": "telefono", "valor": "04125551234", "banco": "0105", "identificacion": "V13759368", "nombre": "Ana Perez" }, "concepto": "Matricula 2026-1" }'`` - Cobrar (
/cobrar) con elotpcapturado (ver §6 para el OTP de prueba).
5.4 DESCONOCIDA — respuesta ambigua
✅ Comportamiento actual. DESCONOCIDA aparece cuando una operación de dinero sufre un timeout/corte post-envío (el banco pudo haber movido el dinero). Es ambigua por diseño: el switch no reintegra ni reintenta a ciegas; lo resuelve /consultar o el poller. En el camino BNC simulado no ocurre de forma natural.
🧭 Propuesta (no implementada aún): ver §6 para un monto mágico que fuerce
DESCONOCIDAen un simulador determinista.
5.5 RECHAZADA y ERROR
RECHAZADA= rechazo de negocio; el detalle está enmotivo_rechazo(ver §6).ERROR= fallo técnico interno (reintentable). En sandbox no deberías verlo salvo problemas reales de infraestructura del propio QA.
6. motivo_rechazo — catálogo y cómo disparar cada uno
6.1 Estado actual
✅ Comportamiento actual. El conjunto de motivos está normalizado (mismo para todos los bancos); el código crudo del banco se preserva siempre en Resultado.raw. Valores posibles de motivo_rechazo:
SALDO_INSUFICIENTE · OTP_INVALIDO · CUENTA_NO_EXISTE · CUENTA_BLOQUEADA ·
CUENTA_NO_DEBITO · CUENTA_NO_CREDITO · MONTO_INVALIDO · EXCEDE_LIMITE ·
BENEFICIARIO_NO_COINCIDE · NO_AFILIADO_SERVICIO · BANCO_NO_DISPONIBLE · DUPLICADA ·
FUERA_DE_HORARIO · CANCELADA_POR_PAGADOR · PENDIENTE_BCV · RECHAZO_TECNICO ·
FIRMA_AUTH · NO_SOPORTADO · BLOQUEO_RIESGO · DESCONOCIDOHoy, el sandbox no tiene cédulas/teléfonos/montos “mágicos” que fuercen un rechazo concreto:
- El camino BNC simulado siempre devuelve éxito.
- Los caminos Plaza/Bancaribe/Activo QA producen rechazos reales del QA del banco según los datos que aceptes/configures allí; no son deterministas desde esta API y dependen del estado del QA.
Por eso, para pruebas reproducibles de cada
motivo_rechazo, se propone la convención de la sección siguiente.
6.2 🧭 Convención propuesta de valores mágicos (no implementada aún)
Propuesta para discutir con QuickLink. Define un simulador de sandbox determinista que enrute por el camino simulado y elija el resultado según el monto (céntimos) y según un OTP especial. Es la forma habitual en pasarelas tipo Stripe y no requiere cédulas mágicas. Mientras no esté implementada, estos valores se comportan como un cobro/pago de prueba normal (éxito).
Por monto (los céntimos seleccionan el resultado; la parte entera es libre):
monto.valor (céntimos .NN) | Estado resultante | motivo_rechazo |
|---|---|---|
| cualquiera no listado | ACEPTADA/LIQUIDADA | null |
….51 | RECHAZADA | SALDO_INSUFICIENTE |
….65 | RECHAZADA | OTP_INVALIDO |
….02 | RECHAZADA | CUENTA_NO_EXISTE |
….06 | RECHAZADA | CUENTA_BLOQUEADA |
….45 | RECHAZADA | CUENTA_NO_DEBITO |
….48 | RECHAZADA | CUENTA_NO_CREDITO |
….13 | RECHAZADA | MONTO_INVALIDO |
….32 | RECHAZADA | EXCEDE_LIMITE |
….30 | RECHAZADA | BENEFICIARIO_NO_COINCIDE |
….10 | RECHAZADA | NO_AFILIADO_SERVICIO |
….91 | RECHAZADA | BANCO_NO_DISPONIBLE |
….11 | RECHAZADA | DUPLICADA |
….01 | RECHAZADA | FUERA_DE_HORARIO |
….99 | RECHAZADA | CANCELADA_POR_PAGADOR |
….31 | PENDIENTE | PENDIENTE_BCV (en raw) |
….90 | RECHAZADA | RECHAZO_TECNICO |
….00 con OTP especial (ver) | RECHAZADA | FIRMA_AUTH |
….77 | RECHAZADA | BLOQUEO_RIESGO |
….79 | DESCONOCIDA | null (no reintegrar) |
Ejemplo (propuesto): "monto": { "valor": 320.51 } → RECHAZADA / SALDO_INSUFICIENTE.
Por OTP (solo aplica al paso /cobrar, donde se envía otp):
otp | Resultado del cobro |
|---|---|
00000000 | RECHAZADA / OTP_INVALIDO |
| cualquiera (8 díg.) | OTP válido (sigue el monto) |
Con esta convención,
OTP_INVALIDOse puede disparar de dos formas equivalentes: con el monto….65o con el OTP00000000.
Por qué es propuesta y no realidad: el código actual no inspecciona céntimos ni OTPs especiales en modo test; el motor de riesgo (que produciría
BLOQUEO_RIESGO) y el límite diario (EXCEDE_LIMITE) se saltan explícitamente en sandbox. Implementar esto requiere un “banco simulador” dedicado en el switch. Trátalo como diseño sugerido, no como contrato.
7. Otras formas (reales) de provocar resultados específicos en sandbox
Aunque no haya montos mágicos, sí puedes provocar ciertos resultados de verdad en sandbox usando la configuración del panel, porque algunas validaciones corren antes de tocar el banco:
7.1 NO_SOPORTADO
✅ Operaciones que un banco no soporta (p. ej. /reverso en rieles sin anulación) responden RECHAZADA / NO_SOPORTADO. Útil para probar tu manejo de “no se puede revertir, reintegra manual”.
7.2 BANCO_NO_DISPONIBLE
✅ Si deshabilitas todos los bancos capaces de una operación (desde el panel, en modo test), el enrutamiento no encuentra riel y la operación se rechaza limpio.
7.3 BLOQUEO_RIESGO (vía listas del panel, en test)
🧭 Propuesta/condicional. El motor de riesgo, por diseño, solo evalúa dinero real; en sandbox no bloquea. Si necesitas ejercitar el manejo de BLOQUEO_RIESGO en test, coordínalo con QuickLink (requeriría habilitar la evaluación de listas en modo test). El sujeto evaluado es quien recibe el efecto del dinero: el pagador en cobrar/token, el beneficiario en pagar.
8. Idempotencia (vale para sandbox y producción)
✅ Comportamiento actual. Envía siempre un idempotency_key UUID único por operación.
- Reintentar
cobrar/pagar/tokencon el mismoidempotency_key(mismo comercio) no duplica la operación: devuelve el resultado original. - Cambia el
idempotency_keypara ejecutar una operación nueva. - En el camino BNC simulado, el
idempotency_keytambién determina lareferencia_banco:TEST-+ sus 8 primeros caracteres.
Genera un UUID v4 por operación (uuidgen, crypto.randomUUID(), etc.).
9. pagar: elegir el riel con via
✅ Comportamiento actual. El campo via del request de /pagar elige el riel:
via | Riel | Instrumento | Liquidación |
|---|---|---|---|
credito_inmediato (default) | Crédito Inmediato (CCE/BCV) | teléfono o cuenta | Asíncrona → ACEPTADA y luego LIQUIDADA por consulta |
pago_movil | Pago Móvil P2P | solo teléfono | Instantánea → LIQUIDADA |
Regla: a cuenta siempre es crédito inmediato; a teléfono es crédito inmediato salvo que indiques
via: "pago_movil". Para unaLIQUIDADAinmediata y determinista en sandbox, usabanco_preferido: "bnc"+via: "pago_movil"(§5.1).
10. Consultas que no mueven dinero
✅ Disponibles también en sandbox (read-only, no las filtran las reglas de pago):
# Saldo de una cuenta cobradora
curl -s "{{base_url}}/switch/v1/saldo?cuenta=01380000011234567890&moneda=VES" \
-H "x-switch-key: mi_comercio:sk_test_xxx"
# Movimientos (conciliación) — 'desde' es obligatorio (YYYY-MM-DD)
curl -s "{{base_url}}/switch/v1/movimientos?cuenta=01380000011234567890&desde=2026-06-01" \
-H "x-switch-key: mi_comercio:sk_test_xxx"
# Catálogo de bancos
curl -s "{{base_url}}/switch/v1/bancos" \
-H "x-switch-key: mi_comercio:sk_test_xxx"En sandbox,
saldo/movimientosse sirven desde el QA del banco correspondiente; sus cifras son de prueba y no reflejan dinero real.
11. Recordatorio de seguridad
✅
sk_testno mueve dinero real. El sandbox enruta a ambientes de ensayo: Banco Plaza QA, Bancaribe QA, Banco Activo QA y BNC simulado (BNC no tiene sandbox alcanzable, así que el switch lo simula sin salir a la red). Ninguna operación de prueba debita ni acredita cuentas productivas.Cuando integres en producción, cambia únicamente la API key (
sk_test_…→sk_live_…): el contrato, los endpoints y la forma de las respuestas son idénticos. Reserva las llavessk_live_…para tráfico real y nunca las publiques en código cliente ni repositorios.