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; una sk_live_… mueve dinero real. Tú nunca envías un campo mode.
  • 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 campo estado, 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_…modo test (sandbox: QA / simulado, sin dinero real).
  • sk_live_…modo live (producción: rieles bancarios reales).
  • ✅ El cliente no puede forzar el modo: el campo mode lo 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 mismo x-switch-key sirve para la API REST y para el servidor MCP.

Una llave inválida o mal formada (<comercio>:<secreto> incompleto) responde 401 { "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:

bancoBancoNotas para sandbox
0138Banco PlazaRiel adquirente/tesorería por defecto. En test → Plaza QA.
0191BNCEn test → simulado (siempre éxito, no sale a la red).
0105Banco MercantilBanco del pagador/beneficiario en ejemplos.
0134BanescoBanco del beneficiario en ejemplos.
0102Banco de VenezuelaGenérico de prueba.

Consulta el catálogo vigente de bancos habilitados con sus capacidades:

bash
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 banco del instrumento (ese es el banco de la persona). Para sugerir un riel, envía banco_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 personaV/E (natural), J/G (jurídico), P (pasaporte). Ej.: V13759368, J00378944781.
  • valor (teléfono): celular local de 11 dígitos con 0 inicial. 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):

Roltipovalorbancoidentificacionnombre
Comercio (tú)cuenta013800000112345678900138J00378944781Mi Comercio CA
Pagadortelefono041255512340105V13759368Ana Pérez
Beneficiariotelefono041455566770134V14589678María Gómez
Beneficiariocuenta013400000198765432100134V14589678Marí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 (moneda por defecto "VES", ISO-4217). valor debe 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_rechazo en 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.

bash
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):

jsonc
{
  "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 === true y la referencia_banco empieza por TEST-.

5.2 ACEPTADAPENDIENTELIQUIDADA — flujo asíncrono

Comportamiento actual. Los cobros por BNC simulado devuelven ACEPTADA (aceptado por el banco, aún no liquidado):

bash
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:

bash
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/PENDIENTE y el poller la confirma luego como LIQUIDADA o RECHAZADA. 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:

  1. Solicitar token (/cobrar/token): el banco del pagador genera el OTP. En sandbox BNC esto devuelve ACEPTADA simulado (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" }' ``
  2. Cobrar (/cobrar) con el otp capturado (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 DESCONOCIDA en un simulador determinista.

5.5 RECHAZADA y ERROR

  • RECHAZADA = rechazo de negocio; el detalle está en motivo_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 · DESCONOCIDO

Hoy, 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 resultantemotivo_rechazo
cualquiera no listadoACEPTADA/LIQUIDADAnull
…​.51RECHAZADASALDO_INSUFICIENTE
…​.65RECHAZADAOTP_INVALIDO
…​.02RECHAZADACUENTA_NO_EXISTE
…​.06RECHAZADACUENTA_BLOQUEADA
…​.45RECHAZADACUENTA_NO_DEBITO
…​.48RECHAZADACUENTA_NO_CREDITO
…​.13RECHAZADAMONTO_INVALIDO
…​.32RECHAZADAEXCEDE_LIMITE
…​.30RECHAZADABENEFICIARIO_NO_COINCIDE
…​.10RECHAZADANO_AFILIADO_SERVICIO
…​.91RECHAZADABANCO_NO_DISPONIBLE
…​.11RECHAZADADUPLICADA
…​.01RECHAZADAFUERA_DE_HORARIO
…​.99RECHAZADACANCELADA_POR_PAGADOR
…​.31PENDIENTEPENDIENTE_BCV (en raw)
…​.90RECHAZADARECHAZO_TECNICO
…​.00 con OTP especial (ver)RECHAZADAFIRMA_AUTH
…​.77RECHAZADABLOQUEO_RIESGO
…​.79DESCONOCIDAnull (no reintegrar)

Ejemplo (propuesto): "monto": { "valor": 320.51 }RECHAZADA / SALDO_INSUFICIENTE.

Por OTP (solo aplica al paso /cobrar, donde se envía otp):

otpResultado del cobro
00000000RECHAZADA / OTP_INVALIDO
cualquiera (8 díg.)OTP válido (sigue el monto)

Con esta convención, OTP_INVALIDO se puede disparar de dos formas equivalentes: con el monto …​.65 o con el OTP 00000000.

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/token con el mismo idempotency_key (mismo comercio) no duplica la operación: devuelve el resultado original.
  • Cambia el idempotency_key para ejecutar una operación nueva.
  • En el camino BNC simulado, el idempotency_key también determina la referencia_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:

viaRielInstrumentoLiquidación
credito_inmediato (default)Crédito Inmediato (CCE/BCV)teléfono o cuentaAsíncrona → ACEPTADA y luego LIQUIDADA por consulta
pago_movilPago Móvil P2Psolo teléfonoInstantánea → LIQUIDADA

Regla: a cuenta siempre es crédito inmediato; a teléfono es crédito inmediato salvo que indiques via: "pago_movil". Para una LIQUIDADA inmediata y determinista en sandbox, usa banco_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):

bash
# 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/movimientos se sirven desde el QA del banco correspondiente; sus cifras son de prueba y no reflejan dinero real.


11. Recordatorio de seguridad

sk_test no 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 llaves sk_live_… para tráfico real y nunca las publiques en código cliente ni repositorios.