{
  "info": {
    "_postman_id": "qp-payapi-0001-4a7e-9c21-quickpay001",
    "name": "QuickPay · API",
    "description": "Colección oficial de la **QuickPay Pay API** — una sola integración para **cobrar** y **pagar** sobre los bancos de Venezuela.\n\n## Configuración rápida\n1. Selecciona el entorno o edita las variables de la colección.\n2. `base_url` → host del API (default `https://pay.pagaconquickpay.com`).\n3. `api_key` → tu llave con formato **`<comercio>:<api_key>`**, p. ej. `acme:sk_test_5f3a...`.\n\n## Autenticación\nTodas las llamadas envían la cabecera **`x-switch-key`** con el valor de `{{api_key}}` (`<comercio>:<api_key>`). Está configurada a nivel de colección y se hereda en cada request.\n\n## Modo test vs. live — lo decide la llave, no tú\nEl **modo lo fija la API key**: `sk_test_…` enruta al ambiente de ensayo (QA / simulado, no mueve dinero real) y `sk_live_…` a producción. **El cliente nunca envía `tenant_id` ni `mode`** en el body: el servidor los deriva de `x-switch-key`. Por eso ningún ejemplo de esta colección los incluye.\n\n## Idempotencia\nCada operación de dinero (`cobrar`, `cobrar/token`, `pagar`) lleva un **`idempotency_key` (UUID)** único. Reintentar con la misma llave nunca duplica el movimiento: devuelve el resultado original. Genera uno nuevo por operación real (puedes usar `{{$guid}}` de Postman).\n\n## Estados asíncronos\nLa liquidación interbancaria (BCV) es asíncrona. Una operación puede quedar `ACEPTADA`/`PENDIENTE` y confirmarse luego como `LIQUIDADA` o `RECHAZADA`. Lee el **estado en el body**, no en el código HTTP. Usa `/consultar` (o un webhook) para el estado final. Ante `DESCONOCIDA`, **consulta antes de reintegrar** — nunca reenvíes la operación original.\n\n## Carpetas\n- **Cobros** — debitar al pagador (C2P / débito inmediato, con OTP de un paso previo).\n- **Pagos** — enviar dinero a un beneficiario; el riel lo elige `via` (`credito_inmediato` | `pago_movil`).\n- **Consultas** — estado de una operación y catálogos (saldo, movimientos, bancos).",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "apikey",
    "apikey": [
      {
        "key": "key",
        "value": "x-switch-key",
        "type": "string"
      },
      {
        "key": "value",
        "value": "{{api_key}}",
        "type": "string"
      },
      {
        "key": "in",
        "value": "header",
        "type": "string"
      }
    ]
  },
  "event": [
    {
      "listen": "test",
      "script": {
        "type": "text/javascript",
        "exec": [
          "// Test básico heredado por todas las requests de la colección.",
          "pm.test('status 200', function () {",
          "    pm.response.to.have.status(200);",
          "});",
          "",
          "// La Pay API responde JSON en todos los endpoints.",
          "pm.test('respuesta es JSON', function () {",
          "    pm.response.to.be.json;",
          "});"
        ]
      }
    }
  ],
  "variable": [
    {
      "key": "base_url",
      "value": "https://pay.pagaconquickpay.com",
      "type": "string",
      "description": "Host del API. No lo hardcodees en las requests; cámbialo aquí (o por entorno) para apuntar a otro ambiente."
    },
    {
      "key": "api_key",
      "value": "acme:sk_test_5f3a9c1e7b2d4a8f6c0e1d2b3a4f5e6d",
      "type": "string",
      "description": "Llave de servicio con formato `<comercio>:<api_key>`. Usa `sk_test_…` para el ambiente de ensayo (QA/simulado) o `sk_live_…` para producción — el modo lo fija esta llave, no el body."
    },
    {
      "key": "lote_id",
      "value": ""
    },
    {
      "key": "link_id",
      "value": ""
    }
  ],
  "item": [
    {
      "name": "Enlaces de pago",
      "description": "Crear, consultar, cancelar y (en prueba) simular un enlace de pago. Guía: /developers/enlaces-de-pago y /developers/datos-de-prueba.",
      "item": [
        {
          "name": "links — crear un enlace",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-switch-key",
                "value": "{{api_key}}",
                "type": "text",
                "description": "Auth: <comercio>:<api_key> (sk_test_… o sk_live_…)."
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/switch/v1/links",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "switch",
                "v1",
                "links"
              ]
            },
            "description": "Crea el enlace. `success_url` y `failure_url` son opcionales (https). El modo (prueba/producción) lo decide la llave.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"monto\": 450.0,\n  \"concepto\": \"Pedido #1024\",\n  \"success_url\": \"https://tu-tienda.com/gracias?pedido=1024\",\n  \"failure_url\": \"https://tu-tienda.com/pago-fallido?pedido=1024\",\n  \"idempotency_key\": \"pedido-1024\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 201 (o 200 si es replay idempotente)', function () { pm.expect([200, 201]).to.include(pm.response.code); });",
                  "pm.collectionVariables.set('link_id', pm.response.json().id);"
                ]
              }
            }
          ]
        },
        {
          "name": "links — consultar un enlace",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-switch-key",
                "value": "{{api_key}}",
                "type": "text",
                "description": "Auth: <comercio>:<api_key> (sk_test_… o sk_live_…)."
              }
            ],
            "url": {
              "raw": "{{base_url}}/switch/v1/links/{{link_id}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "switch",
                "v1",
                "links",
                "{{link_id}}"
              ]
            },
            "description": "Devuelve su `estado`."
          }
        },
        {
          "name": "links — listar enlaces (con filtros)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-switch-key",
                "value": "{{api_key}}",
                "type": "text",
                "description": "Auth: <comercio>:<api_key> (sk_test_… o sk_live_…)."
              }
            ],
            "url": {
              "raw": "{{base_url}}/switch/v1/links?estado=pagado,procesando&desde=2026-10-08T04:00:00Z&hasta=2026-10-09T04:00:00Z&q=mensualidad&limit=20&offset=0",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "switch",
                "v1",
                "links"
              ],
              "query": [
                {
                  "key": "estado",
                  "value": "pagado,procesando",
                  "description": "Uno o varios separados por coma."
                },
                {
                  "key": "desde",
                  "value": "2026-10-08T04:00:00Z",
                  "description": "ISO 8601 o milisegundos; entra. Fecha del pago o, si no se pagó, de creación."
                },
                {
                  "key": "hasta",
                  "value": "2026-10-09T04:00:00Z",
                  "description": "ISO 8601 o milisegundos; no entra."
                },
                {
                  "key": "q",
                  "value": "mensualidad",
                  "description": "Concepto, nombre de quien pagó, referencia, id o código de verificación."
                },
                {
                  "key": "min",
                  "value": "",
                  "description": "Monto mínimo en Bs (sin propina).",
                  "disabled": true
                },
                {
                  "key": "max",
                  "value": "",
                  "description": "Monto máximo en Bs (sin propina).",
                  "disabled": true
                },
                {
                  "key": "con_propina",
                  "value": "",
                  "description": "true o false.",
                  "disabled": true
                },
                {
                  "key": "mode",
                  "value": "",
                  "description": "test o live.",
                  "disabled": true
                },
                {
                  "key": "origen",
                  "value": "",
                  "description": "api, panel, mi_pagina, boton o whatsapp.",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "20",
                  "description": "Por omisión 50, máximo 200."
                },
                {
                  "key": "offset",
                  "value": "0",
                  "description": "Para paginar."
                }
              ]
            },
            "description": "Lista tus enlaces, del más nuevo al más viejo. Todos los filtros son opcionales y se combinan. Devuelve una lista. Un filtro con un valor que no se entiende responde 400 con `parametro`."
          }
        },
        {
          "name": "links — cancelar un enlace pendiente",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-switch-key",
                "value": "{{api_key}}",
                "type": "text",
                "description": "Auth: <comercio>:<api_key> (sk_test_… o sk_live_…)."
              }
            ],
            "url": {
              "raw": "{{base_url}}/switch/v1/links/{{link_id}}/cancelar",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "switch",
                "v1",
                "links",
                "{{link_id}}",
                "cancelar"
              ]
            },
            "description": "Sólo cancela si sigue `pendiente`; si no, 409 `no_cancelable`."
          }
        },
        {
          "name": "links — simular resultado (sólo llave de prueba)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-switch-key",
                "value": "{{api_key}}",
                "type": "text",
                "description": "Auth: <comercio>:<api_key> (sk_test_… o sk_live_…)."
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/switch/v1/links/{{link_id}}/simular",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "switch",
                "v1",
                "links",
                "{{link_id}}",
                "simular"
              ]
            },
            "description": "Sólo con llave `sk_test_`: en un enlace de producción responde 403. `resultado`: `pagado`, `rechazado` o `expirado`.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"resultado\": \"pagado\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "verificar — comprobar un comprobante",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/switch/v1/verificar/QP-7K3M9-XQ4TA",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "switch",
                "v1",
                "verificar",
                "QP-7K3M9-XQ4TA"
              ]
            },
            "description": "Público (sin llave). Comprueba que un comprobante es auténtico con su código de verificación. 404 si no existe; 20 consultas por minuto por IP."
          }
        }
      ]
    },
    {
      "name": "Cobros",
      "description": "**Debitar al pagador** (C2P / débito inmediato). Suele requerir un **OTP** que emite el banco del pagador: primero `cobrar/token` (paso previo) y luego `cobrar` con el `otp` capturado. El sujeto evaluado por el motor de riesgo es el **pagador**.",
      "item": [
        {
          "name": "cobrar/token — solicitar OTP al banco del pagador",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "",
                  "var r = pm.response.json();",
                  "pm.test('token aceptado (estado ACEPTADA)', function () {",
                  "    pm.expect(r.estado).to.eql('ACEPTADA');",
                  "});"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-switch-key",
                "value": "{{api_key}}",
                "type": "text",
                "description": "Auth: <comercio>:<api_key> (sk_test_… o sk_live_…)."
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"idempotency_key\": \"c0d187a5-5ff0-4723-871f-e126d938c7a7\",\n  \"monto\": { \"valor\": 320.00, \"moneda\": \"VES\" },\n  \"cobrador\": {\n    \"tipo\": \"cuenta\",\n    \"valor\": \"01020000011234567890\",\n    \"banco\": \"0102\",\n    \"identificacion\": \"J123456789\",\n    \"nombre\": \"ACME C.A.\"\n  },\n  \"pagador\": {\n    \"tipo\": \"telefono\",\n    \"valor\": \"04125551234\",\n    \"banco\": \"0105\",\n    \"identificacion\": \"V12345678\",\n    \"nombre\": \"Ana Perez\"\n  },\n  \"concepto\": \"Matricula 2026-1\",\n  \"canal\": \"boton_pago\",\n  \"origen_ip\": \"200.44.32.11\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}/switch/v1/cobrar/token",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "switch",
                "v1",
                "cobrar",
                "token"
              ]
            },
            "description": "Paso **previo** a un cobro con token. El banco del pagador emite un OTP (válido ~120s) que el pagador te dicta. Mismo cuerpo que `/cobrar` pero **sin `otp`**.\n\nNo envíes `tenant_id` ni `mode`: el servidor los deriva de `x-switch-key`.\n\nRespuesta: `Resultado` con `estado: ACEPTADA` (token solicitado). Luego captura el OTP del pagador y llama a **cobrar** con el mismo `idempotency_key` y el `otp`."
          },
          "response": []
        },
        {
          "name": "cobrar — debitar al pagador (con OTP)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "",
                  "var r = pm.response.json();",
                  "pm.test('estado normalizado presente', function () {",
                  "    pm.expect(r).to.have.property('estado');",
                  "    pm.expect(['ACEPTADA','PENDIENTE','LIQUIDADA','RECHAZADA','ERROR','DESCONOCIDA']).to.include(r.estado);",
                  "});",
                  "pm.test('trae id y estado', function () {",
                  "    pm.expect(r).to.have.property('id');",
                  "    pm.expect(r).to.have.property('estado');",
                  "});",
                  "",
                  "// Guarda el id para encadenar con /consultar.",
                  "if (r && r.id) { pm.collectionVariables.set('ultimo_id', r.id); }"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-switch-key",
                "value": "{{api_key}}",
                "type": "text",
                "description": "Auth: <comercio>:<api_key> (sk_test_… o sk_live_…)."
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"idempotency_key\": \"c0d187a5-5ff0-4723-871f-e126d938c7a7\",\n  \"monto\": { \"valor\": 320.00, \"moneda\": \"VES\" },\n  \"cobrador\": {\n    \"tipo\": \"cuenta\",\n    \"valor\": \"01020000011234567890\",\n    \"banco\": \"0102\",\n    \"identificacion\": \"J123456789\",\n    \"nombre\": \"ACME C.A.\"\n  },\n  \"pagador\": {\n    \"tipo\": \"telefono\",\n    \"valor\": \"04125551234\",\n    \"banco\": \"0105\",\n    \"identificacion\": \"V12345678\",\n    \"nombre\": \"Ana Perez\"\n  },\n  \"concepto\": \"Matricula 2026-1\",\n  \"otp\": \"83920147\",\n  \"canal\": \"boton_pago\",\n  \"origen_ip\": \"200.44.32.11\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}/switch/v1/cobrar",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "switch",
                "v1",
                "cobrar"
              ]
            },
            "description": "Ejecuta un **cobro por débito inmediato** (C2P). Incluye el `otp` (8 dígitos) capturado del pagador en el paso `cobrar/token`. Usa el **mismo `idempotency_key`** que el token para encadenar de forma idempotente.\n\nLee el resultado en el campo **`estado`** del body, no en el código HTTP. Posibles estados: `ACEPTADA` / `PENDIENTE` / `LIQUIDADA` / `RECHAZADA` (con `motivo_rechazo` normalizado, p. ej. `OTP_INVALIDO`, `SALDO_INSUFICIENTE`, `BLOQUEO_RIESGO`) / `DESCONOCIDA`.\n\nNo envíes `tenant_id` ni `mode`: los fija `x-switch-key`. El test guarda `id` en `ultimo_id` para encadenar con `/consultar`."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Pagos",
      "description": "**Enviar dinero** a un beneficiario (payout desde tesorería). El riel lo elige **`via`**:\n\n- **`credito_inmediato`** (CCE) — riel **predominante**; admite **teléfono** o **cuenta**. Liquidación BCV asíncrona → `ACEPTADA` y luego `LIQUIDADA` (confírmalo con `/consultar`).\n- **`pago_movil`** (P2P por teléfono) — alterno instantáneo → `LIQUIDADA` (p. ej. reintegros).\n\nRegla: **a cuenta siempre es crédito inmediato**; a teléfono es CCE salvo que pidas `via: pago_movil`. El sujeto evaluado por riesgo es el **beneficiario**.\n\n**Habilitación:** `pagar` debita una cuenta de QuickPay, no un saldo tuyo. Con una llave de comercio sin habilitación responde `403` `{\"error\":\"pagar_no_habilitado\"}`.",
      "item": [
        {
          "name": "pagar — via credito_inmediato (a teléfono)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "",
                  "var r = pm.response.json();",
                  "pm.test('estado normalizado presente', function () {",
                  "    pm.expect(['ACEPTADA','PENDIENTE','LIQUIDADA','RECHAZADA','ERROR','DESCONOCIDA']).to.include(r.estado);",
                  "});",
                  "if (r && r.id) { pm.collectionVariables.set('ultimo_id', r.id); }"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-switch-key",
                "value": "{{api_key}}",
                "type": "text",
                "description": "Auth: <comercio>:<api_key> (sk_test_… o sk_live_…)."
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"idempotency_key\": \"8d96a4b2-f85a-4e05-af48-5b2eed381095\",\n  \"monto\": { \"valor\": 250.00, \"moneda\": \"VES\" },\n  \"ordenante\": {\n    \"tipo\": \"cuenta\",\n    \"valor\": \"01020000011234567890\",\n    \"banco\": \"0102\",\n    \"identificacion\": \"J123456789\",\n    \"nombre\": \"ACME C.A.\"\n  },\n  \"beneficiario\": {\n    \"tipo\": \"telefono\",\n    \"valor\": \"04145556677\",\n    \"banco\": \"0134\",\n    \"identificacion\": \"V87654321\",\n    \"nombre\": \"Maria Gonzalez\"\n  },\n  \"concepto\": \"Reintegro pedido 4821\",\n  \"proposito\": \"transferencia\",\n  \"via\": \"credito_inmediato\",\n  \"canal\": \"billetera_digital\",\n  \"origen_ip\": \"200.44.32.11\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}/switch/v1/pagar",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "switch",
                "v1",
                "pagar"
              ]
            },
            "description": "Pago por **Crédito Inmediato (CCE)** a un **teléfono** (caso típico). Es el riel **predominante**. Liquida en BCV de forma asíncrona: normalmente responde `ACEPTADA` y luego pasa a `LIQUIDADA` — confírmalo con `/consultar` o con el webhook `transaccion.liquidada`.\n\n`via: credito_inmediato`, `beneficiario.tipo: telefono`. El `ordenante` es tu cuenta de tesorería.\n\nNo envíes `tenant_id` ni `mode`: los fija `x-switch-key`."
          },
          "response": []
        },
        {
          "name": "pagar — via credito_inmediato (a cuenta)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "",
                  "var r = pm.response.json();",
                  "pm.test('estado normalizado presente', function () {",
                  "    pm.expect(['ACEPTADA','PENDIENTE','LIQUIDADA','RECHAZADA','ERROR','DESCONOCIDA']).to.include(r.estado);",
                  "});",
                  "if (r && r.id) { pm.collectionVariables.set('ultimo_id', r.id); }"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-switch-key",
                "value": "{{api_key}}",
                "type": "text",
                "description": "Auth: <comercio>:<api_key> (sk_test_… o sk_live_…)."
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"idempotency_key\": \"ee6f6993-8c74-4084-87c0-576831752626\",\n  \"monto\": { \"valor\": 1850.00, \"moneda\": \"VES\" },\n  \"ordenante\": {\n    \"tipo\": \"cuenta\",\n    \"valor\": \"01020000011234567890\",\n    \"banco\": \"0102\",\n    \"identificacion\": \"J123456789\",\n    \"nombre\": \"ACME C.A.\"\n  },\n  \"beneficiario\": {\n    \"tipo\": \"cuenta\",\n    \"valor\": \"01080000099887766554\",\n    \"banco\": \"0108\",\n    \"identificacion\": \"V18234907\",\n    \"nombre\": \"Carlos Rivas\"\n  },\n  \"concepto\": \"Pago proveedor febrero\",\n  \"proposito\": \"proveedor\",\n  \"via\": \"credito_inmediato\",\n  \"canal\": \"merchant\",\n  \"origen_ip\": \"200.44.32.11\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}/switch/v1/pagar",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "switch",
                "v1",
                "pagar"
              ]
            },
            "description": "Pago por **Crédito Inmediato (CCE)** a una **cuenta** (20 dígitos). A cuenta **siempre** es crédito inmediato, independientemente de `via`. Liquidación BCV asíncrona → `ACEPTADA` y luego `LIQUIDADA` por consulta.\n\n`beneficiario.tipo: cuenta`, `banco: 0108` (Provincial), `proposito: proveedor`.\n\nNo envíes `tenant_id` ni `mode`: los fija `x-switch-key`."
          },
          "response": []
        },
        {
          "name": "pagar — via pago_movil (P2P a teléfono)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "",
                  "var r = pm.response.json();",
                  "pm.test('estado normalizado presente', function () {",
                  "    pm.expect(['ACEPTADA','PENDIENTE','LIQUIDADA','RECHAZADA','ERROR','DESCONOCIDA']).to.include(r.estado);",
                  "});",
                  "if (r && r.id) { pm.collectionVariables.set('ultimo_id', r.id); }"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-switch-key",
                "value": "{{api_key}}",
                "type": "text",
                "description": "Auth: <comercio>:<api_key> (sk_test_… o sk_live_…)."
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"idempotency_key\": \"c4f75381-8072-4bac-8ac3-86ac8ec4e9f6\",\n  \"monto\": { \"valor\": 90.50, \"moneda\": \"VES\" },\n  \"ordenante\": {\n    \"tipo\": \"cuenta\",\n    \"valor\": \"01020000011234567890\",\n    \"banco\": \"0102\",\n    \"identificacion\": \"J123456789\",\n    \"nombre\": \"ACME C.A.\"\n  },\n  \"beneficiario\": {\n    \"tipo\": \"telefono\",\n    \"valor\": \"04267778899\",\n    \"banco\": \"0191\",\n    \"identificacion\": \"V20891345\",\n    \"nombre\": \"Luis Mendoza\"\n  },\n  \"concepto\": \"Reintegro parcial\",\n  \"proposito\": \"transferencia\",\n  \"via\": \"pago_movil\",\n  \"canal\": \"billetera_digital\",\n  \"origen_ip\": \"200.44.32.11\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}/switch/v1/pagar",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "switch",
                "v1",
                "pagar"
              ]
            },
            "description": "Pago por **Pago Móvil P2P** a un **teléfono** (riel alterno, instantáneo). Útil para reintegros rápidos. Suele responder directamente `LIQUIDADA`.\n\n`via: pago_movil` solo aplica a teléfono; a cuenta el switch usa CCE igualmente.\n\nNo envíes `tenant_id` ni `mode`: los fija `x-switch-key`."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Consultas",
      "description": "**Estado de una operación** y **catálogos**.\n\n- `consultar` (POST) — estado actualizado de una operación previa por su `id`.\n- `saldo` (GET) — saldo de una cuenta; read-only, no pasa por reglas de pago.\n- `movimientos` (GET) — movimientos para conciliación; `desde` es obligatorio.\n- `bancos` (GET) — bancos habilitados y sus capacidades.\n\n`saldo`, `movimientos` y `bancos` son **GET con query params**; `consultar` es **POST con JSON**.",
      "item": [
        {
          "name": "consultar — estado de una operación",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "",
                  "var r = pm.response.json();",
                  "pm.test('estado actualizado presente', function () {",
                  "    pm.expect(['ACEPTADA','PENDIENTE','LIQUIDADA','RECHAZADA','ERROR','DESCONOCIDA']).to.include(r.estado);",
                  "});"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-switch-key",
                "value": "{{api_key}}",
                "type": "text",
                "description": "Auth: <comercio>:<api_key> (sk_test_… o sk_live_…)."
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"id\": \"qp_txn_018f3c2a9b7e4d6f8a01b2c3d4e5f607\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}/switch/v1/consultar",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "switch",
                "v1",
                "consultar"
              ]
            },
            "description": "Devuelve el **estado actualizado** (`PENDIENTE` / `LIQUIDADA` / `RECHAZADA`) de una operación previa. Úsalo para confirmar pagos/cobros CCE asíncronos, y **siempre** ante un `DESCONOCIDA` antes de reintegrar.\n\nSolo necesita `id` (el `tenant_id` lo deriva el servidor de `x-switch-key`). Sustituye el `id` por uno real, o usa `{{ultimo_id}}` si encadenas tras un cobro/pago en esta colección.\n\nResponde `404` si el `id` no pertenece a tu comercio."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Cobro por lote",
      "description": "**Cobrarle a una lista** desde tu propio bot de WhatsApp: mandas hasta 500 items y recibes un link de pago por persona. Nada de esto mueve dinero; el cobro ocurre en el checkout de cada link. Guía: /developers/cobro-por-lote.",
      "item": [
        {
          "name": "lotes — crear un lote (N links de una vez)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-switch-key",
                "value": "{{api_key}}",
                "type": "text",
                "description": "Auth: <comercio>:<api_key> (sk_test_… o sk_live_…)."
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/switch/v1/lotes",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "switch",
                "v1",
                "lotes"
              ]
            },
            "description": "Crea el lote y sus links en una sola transacción (todo-o-nada). `idempotency_key` del lote: repetir devuelve el mismo lote. Cada item recibe `url` (para el botón) y `link_id`.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"nombre\": \"Mensualidad septiembre\",\n  \"idempotency_key\": \"mensualidad-2026-09\",\n  \"expira_horas\": 72,\n  \"items\": [\n    {\n      \"monto\": 450.0,\n      \"concepto\": \"Mensualidad septiembre\",\n      \"referencia_externa\": \"CLI-001\",\n      \"cliente\": {\n        \"nombre\": \"Cliente Uno\",\n        \"telefono\": \"04141234567\"\n      }\n    },\n    {\n      \"monto\": 450.0,\n      \"concepto\": \"Mensualidad septiembre\",\n      \"referencia_externa\": \"CLI-002\",\n      \"cliente\": {\n        \"nombre\": \"Cliente Dos\",\n        \"telefono\": \"04241234567\"\n      }\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 201 (o 200 si es replay idempotente)', function () {",
                  "    pm.expect([200, 201]).to.include(pm.response.code);",
                  "});",
                  "",
                  "var r = pm.response.json();",
                  "pm.collectionVariables.set('lote_id', r.id);",
                  "pm.collectionVariables.set('link_id', r.items[0].link_id);",
                  "pm.test('un link por item', function () { pm.expect(r.items.length).to.eql(r.total); });"
                ]
              }
            }
          ]
        },
        {
          "name": "lotes — estado del lote (items + resumen)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-switch-key",
                "value": "{{api_key}}",
                "type": "text",
                "description": "Auth: <comercio>:<api_key> (sk_test_… o sk_live_…)."
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/switch/v1/lotes/{{lote_id}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "switch",
                "v1",
                "lotes",
                "{{lote_id}}"
              ]
            },
            "description": "Estado de cada item (`pendiente`/`cobrando`/`procesando`/`revision`/`pagado`/`expirado`/`cancelado`) y resumen (`pagados`, `abiertos`, `monto_pagado`, `completo`)."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', function () { pm.response.to.have.status(200); });",
                  "var r = pm.response.json();",
                  "pm.test('trae resumen', function () { pm.expect(r.resumen).to.have.property('pagados'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "lotes — cancelar lo que sigue pendiente",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-switch-key",
                "value": "{{api_key}}",
                "type": "text",
                "description": "Auth: <comercio>:<api_key> (sk_test_… o sk_live_…)."
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/switch/v1/lotes/{{lote_id}}/cancelar",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "switch",
                "v1",
                "lotes",
                "{{lote_id}}",
                "cancelar"
              ]
            },
            "description": "Cancela SOLO los items `pendiente`. Los que están en `cobrando`/`procesando`/`revision`/`pagado` no se tocan (puede haber un OTP o un débito en curso)."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', function () { pm.response.to.have.status(200); });"
                ]
              }
            }
          ]
        }
      ]
    }
  ]
}
